C++ 您能否运行多个ISR';没有穿线的情况下,是同时发生的吗?
我一直在剖析一些使用比较定时器中断一次控制多个步进电机的代码,但代码的编写方式我无法判断该代码是否真的触发了单独的中断以同时运行,或者它是一步一步地步进电机,并作为一个回路在每个电机之间循环,直到它们停止运行已全部到达所需位置。我的主要问题是,因为它们使用相同的输出比较寄存器触发下一个中断,所以不能有多个isr,因为它们不能,但相同内存位置中的不同值正确吗?如果是这样的话,我的假设是一次一个步进电机是正确的吗C++ 您能否运行多个ISR';没有穿线的情况下,是同时发生的吗?,c++,embedded,arduino-uno,C++,Embedded,Arduino Uno,我一直在剖析一些使用比较定时器中断一次控制多个步进电机的代码,但代码的编写方式我无法判断该代码是否真的触发了单独的中断以同时运行,或者它是一步一步地步进电机,并作为一个回路在每个电机之间循环,直到它们停止运行已全部到达所需位置。我的主要问题是,因为它们使用相同的输出比较寄存器触发下一个中断,所以不能有多个isr,因为它们不能,但相同内存位置中的不同值正确吗?如果是这样的话,我的假设是一次一个步进电机是正确的吗 #define X_DIR_PIN 55 #define X
#define X_DIR_PIN 55
#define X_STEP_PIN 54
#define X_ENABLE_PIN 38
#define Y_DIR_PIN 61
#define Y_STEP_PIN 60
#define Y_ENABLE_PIN 56
#define Z_DIR_PIN 48
#define Z_STEP_PIN 46
#define Z_ENABLE_PIN 62
#define A_DIR_PIN 28
#define A_STEP_PIN 26
#define A_ENABLE_PIN 24
#define B_DIR_PIN 34
#define B_STEP_PIN 36
#define B_ENABLE_PIN 30
#define C_DIR_PIN 32
#define C_STEP_PIN 47
#define C_ENABLE_PIN 45
#define X_STEP_HIGH PORTF |= 0b00000001;
#define X_STEP_LOW PORTF &= ~0b00000001;
#define Y_STEP_HIGH PORTF |= 0b01000000;
#define Y_STEP_LOW PORTF &= ~0b01000000;
#define Z_STEP_HIGH PORTL |= 0b00001000;
#define Z_STEP_LOW PORTL &= ~0b00001000;
#define A_STEP_HIGH PORTA |= 0b00010000;
#define A_STEP_LOW PORTA &= ~0b00010000;
#define B_STEP_HIGH PORTC |= 0b00000010;
#define B_STEP_LOW PORTC &= ~0b00000010;
#define C_STEP_HIGH PORTL |= 0b00000100;
#define C_STEP_LOW PORTL &= ~0b00000100;
#define TIMER1_INTERRUPTS_ON TIMSK1 |= (1 << OCIE1A);
#define TIMER1_INTERRUPTS_OFF TIMSK1 &= ~(1 << OCIE1A);
struct stepperInfo {
// externally defined parameters
float acceleration;
volatile unsigned int minStepInterval; // ie. max speed, smaller is faster
void (*dirFunc)(int);
void (*stepFunc)();
// derived parameters
unsigned int c0; // step interval for first step, determines acceleration
long stepPosition; // current position of stepper (total of all movements taken so far)
// per movement variables (only changed once per movement)
volatile int dir; // current direction of movement, used to keep track of position
volatile unsigned int totalSteps; // number of steps requested for current movement
volatile bool movementDone = false; // true if the current movement has been completed (used by main program to wait for completion)
volatile unsigned int rampUpStepCount; // number of steps taken to reach either max speed, or half-way to the goal (will be zero until this number is known)
// per iteration variables (potentially changed every interrupt)
volatile unsigned int n; // index in acceleration curve, used to calculate next interval
volatile float d; // current interval length
volatile unsigned long di; // above variable truncated
volatile unsigned int stepCount; // number of steps completed in current movement
};
void xStep() {
X_STEP_HIGH
X_STEP_LOW
}
void xDir(int dir) {
digitalWrite(X_DIR_PIN, dir);
}
void yStep() {
Y_STEP_HIGH
Y_STEP_LOW
}
void yDir(int dir) {
digitalWrite(Y_DIR_PIN, dir);
}
void zStep() {
Z_STEP_HIGH
Z_STEP_LOW
}
void zDir(int dir) {
digitalWrite(Z_DIR_PIN, dir);
}
void aStep() {
A_STEP_HIGH
A_STEP_LOW
}
void aDir(int dir) {
digitalWrite(A_DIR_PIN, dir);
}
void bStep() {
B_STEP_HIGH
B_STEP_LOW
}
void bDir(int dir) {
digitalWrite(B_DIR_PIN, dir);
}
void cStep() {
C_STEP_HIGH
C_STEP_LOW
}
void cDir(int dir) {
digitalWrite(C_DIR_PIN, dir);
}
void resetStepperInfo( stepperInfo& si ) {
si.n = 0;
si.d = 0;
si.di = 0;
si.stepCount = 0;
si.rampUpStepCount = 0;
si.totalSteps = 0;
si.stepPosition = 0;
si.movementDone = false;
}
#define NUM_STEPPERS 6
volatile stepperInfo steppers[NUM_STEPPERS];
void setup() {
pinMode(X_STEP_PIN, OUTPUT);
pinMode(X_DIR_PIN, OUTPUT);
pinMode(X_ENABLE_PIN, OUTPUT);
pinMode(Y_STEP_PIN, OUTPUT);
pinMode(Y_DIR_PIN, OUTPUT);
pinMode(Y_ENABLE_PIN, OUTPUT);
pinMode(Z_STEP_PIN, OUTPUT);
pinMode(Z_DIR_PIN, OUTPUT);
pinMode(Z_ENABLE_PIN, OUTPUT);
pinMode(A_STEP_PIN, OUTPUT);
pinMode(A_DIR_PIN, OUTPUT);
pinMode(A_ENABLE_PIN, OUTPUT);
pinMode(B_STEP_PIN, OUTPUT);
pinMode(B_DIR_PIN, OUTPUT);
pinMode(B_ENABLE_PIN, OUTPUT);
pinMode(C_STEP_PIN, OUTPUT);
pinMode(C_DIR_PIN, OUTPUT);
pinMode(C_ENABLE_PIN, OUTPUT);
digitalWrite(X_ENABLE_PIN, LOW);
digitalWrite(Y_ENABLE_PIN, LOW);
digitalWrite(Z_ENABLE_PIN, LOW);
digitalWrite(A_ENABLE_PIN, LOW);
digitalWrite(B_ENABLE_PIN, LOW);
digitalWrite(C_ENABLE_PIN, LOW);
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 1000; // compare value
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= ((1 << CS11) | (1 << CS10)); // 64 prescaler
interrupts();
steppers[0].dirFunc = bDir;
steppers[0].stepFunc = bStep;
steppers[0].acceleration = 1000;
steppers[0].minStepInterval = 50;
steppers[1].dirFunc = aDir;
steppers[1].stepFunc = aStep;
steppers[1].acceleration = 4000;
steppers[1].minStepInterval = 50;
steppers[2].dirFunc = cDir;
steppers[2].stepFunc = cStep;
steppers[2].acceleration = 1000;
steppers[2].minStepInterval = 50;
steppers[3].dirFunc = xDir;
steppers[3].stepFunc = xStep;
steppers[3].acceleration = 1000;
steppers[3].minStepInterval = 250;
steppers[4].dirFunc = yDir;
steppers[4].stepFunc = yStep;
steppers[4].acceleration = 1000;
steppers[4].minStepInterval = 50;
steppers[5].dirFunc = zDir;
steppers[5].stepFunc = zStep;
steppers[5].acceleration = 1000;
steppers[5].minStepInterval = 450;
}
void resetStepper(volatile stepperInfo& si) {
si.c0 = si.acceleration;
si.d = si.c0;
si.di = si.d;
si.stepCount = 0;
si.n = 0;
si.rampUpStepCount = 0;
si.movementDone = false;
}
volatile byte remainingSteppersFlag = 0;
void prepareMovement(int whichMotor, int steps) {
volatile stepperInfo& si = steppers[whichMotor];
si.dirFunc( steps < 0 ? HIGH : LOW );
si.dir = steps > 0 ? 1 : -1;
si.totalSteps = abs(steps);
resetStepper(si);
remainingSteppersFlag |= (1 << whichMotor);
}
volatile byte nextStepperFlag = 0;
volatile int ind = 0;
volatile unsigned int intervals[100];
void setNextInterruptInterval() {
bool movementComplete = true;
unsigned int mind = 999999;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ((1 << i) & remainingSteppersFlag) && steppers[i].di < mind ) {
mind = steppers[i].di;
}
}
nextStepperFlag = 0;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ! steppers[i].movementDone )
movementComplete = false;
if ( ((1 << i) & remainingSteppersFlag) && steppers[i].di == mind )
nextStepperFlag |= (1 << i);
}
if ( remainingSteppersFlag == 0 ) {
OCR1A = 65500;
}
OCR1A = mind;
}
ISR(TIMER1_COMPA_vect)
{
unsigned int tmpCtr = OCR1A;
OCR1A = 65500;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ! ((1 << i) & remainingSteppersFlag) )
continue;
if ( ! (nextStepperFlag & (1 << i)) ) {
steppers[i].di -= tmpCtr;
continue;
}
volatile stepperInfo& s = steppers[i];
if ( s.stepCount < s.totalSteps ) {
s.stepFunc();
s.stepCount++;
s.stepPosition += s.dir;
if ( s.stepCount >= s.totalSteps ) {
s.movementDone = true;
remainingSteppersFlag &= ~(1 << i);
}
}
if ( s.rampUpStepCount == 0 ) {
s.n++;
s.d = s.d - (2 * s.d) / (4 * s.n + 1);
if ( s.d <= s.minStepInterval ) {
s.d = s.minStepInterval;
s.rampUpStepCount = s.stepCount;
}
if ( s.stepCount >= s.totalSteps / 2 ) {
s.rampUpStepCount = s.stepCount;
}
}
else if ( s.stepCount >= s.totalSteps - s.rampUpStepCount ) {
s.d = (s.d * (4 * s.n + 1)) / (4 * s.n + 1 - 2);
s.n--;
}
s.di = s.d; // integer
}
setNextInterruptInterval();
TCNT1 = 0;
}
void runAndWait() {
setNextInterruptInterval();
while ( remainingSteppersFlag );
}
void loop() {
TIMER1_INTERRUPTS_ON
for (int i = 0; i < 4; i++) {
for (int k = 0; k < NUM_STEPPERS; k++) {
prepareMovement( k, 200 );
runAndWait();
}
}
for (int i = 0; i < 4; i++) {
for (int k = 0; k < NUM_STEPPERS; k++) {
prepareMovement( k, 200 );
}
runAndWait();
}
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, 400 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, -400 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, 200 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, -200 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, 600 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, -600 );
runAndWait();
while (true);
}```
#定义X方向引脚55
#定义X_步骤_引脚54
#定义X_启用_引脚38
#定义Y_方向引脚61
#定义Y_步骤_针脚60
#定义Y_启用_引脚56
#定义Z_方向引脚48
#定义Z_步进_针脚46
#定义Z_启用_引脚62
#定义一个_DIR_引脚28
#定义一个_步骤_针脚26
#定义一个\u启用\u引脚24
#定义B_DIR_引脚34
#定义B_步骤_针脚36
#定义B_启用_引脚30
#定义C_DIR_引脚32
#定义C_步骤_引脚47
#定义C_启用_引脚45
#定义X_步骤_高端口f |=0b0000001;
#定义X_步骤_低端口&=~0b00000001;
#定义Y_步骤_高端口F |=0b01000000;
#定义Y_步骤_低端口&=~0b01000000;
#定义Z_阶跃|u高端口|=0b00001000;
#定义Z_步进低端口&=~0b00001000;
#定义一个_阶跃|高端口|=0b00010000;
#定义一个低阶端口&=~0b00010000;
#定义B_阶跃_高端口C |=0b00000010;
#定义B_步骤_低端口C&=~0b00000010;
#定义C_步骤_高端口|=0b00000100;
#定义C_步骤_低端口&=~0b00000100;
#定义TIMSK1上的计时器1|u中断_=(1
我的主要问题是[…]不能有多个isr[…]
您的代码只清楚地显示一个ISR。如果调用了ISR,它的中断将被禁用,直到它返回
虽然ISR可以启用其中断,但我在您的代码中看不到关于此的指令。我很少在其他微控制器上这样做,但这是完全可能的,并且会导致相同ISR的递归调用。不过,我不确定AVR
实际上,中断被绑定到其ISR的固定地址。每个中断只能有一个ISR。(抛开一些巧妙的技巧,例如内存存储或RAM中的跳转向量。)
如果是这样的话,我的假设是一次一个步进电机是正确的吗
在我看来,在ISR的每次运行中,那些“时间已经到了”的电机都是步进的,不必深入了解您的来源。例如,查看步进器[*].di
有了ISR作为一个整体独立运行的知识,您可以调查源并跟踪其流程
假设在进行下一步时调用ISR,对于当时必须步进的每台电机。假设两台电机分别以100 Hz和200 Hz的频率运行。ISR将以200 Hz的频率调用,但第一台电机仅每隔一秒调用一次
所以答案是:
“从外部看,所有电机都是并联的,每个电机都有自己的速度。”我强烈建议在进行MCU编程时学习基本汇编程序
中断的基本原理是,当进入ISR时,典型的MCU会自动设置一个全局中断掩码。AVR也不例外——它源自“摩托罗拉学派”在全局中断掩码被称为I
并存储在条件代码寄存器中的情况下,AVR调用此寄存器。这是整个MCU中最重要的寄存器,因为除了中断处理之外,所有执行指令的结果也在此处报告
每当触发ISR时,状态
寄存器将自动保存在堆栈上,以便在执行ISR后,继续进行计算。一旦保存寄存器,MCU将自动清除I
位,并阻止所有其他中断触发
I
也可以使用SEI
或CLI
指令手动设置。从ISR内部执行此操作意味着您允许挂起的中断进入,可能与您已经执行的中断类型相同。请注意,每个中断都使用自己的堆栈空间,因此理论上可能执行一半的ISR,然后让中的另一个中断,冻结执行,并让另一个中断代替执行。它的工作方式类似于递归
即使启用了全局中断掩码,触发中断的硬件仍可能设置触发中断的标志。这意味着,一旦您的ISR执行完毕且中断掩码被禁用,其他未决中断可能会立即执行。这是根据某些中断优先级计划指定来完成的由MCU制造商和/或程序员执行。但不能同时执行多个中断
特别是在PWM的情况下,在多个PWM通道同时运行的情况下,可以有一个中断来标记占空比的开始
关于从中断中修改共享内存,这是一个完全不同的故事。我建议阅读。循环()
为每个电机设置一个目标相对位置,然后等待所有电机达到其目标位置。执行一系列这样的步骤
在每个定时器中断时,对于尚未达到其目标的每个电机,都会产生一个步进脉冲。(事实上,这稍微复杂一点,因为每个电机都有速度和加速度曲线,所以在
void runNoWait()
{
setNextInterruptInterval();
}
void loop()
{
static const int sequence[] = { 200,200,200,200,200,200,200,200,
400,-400,200,-200,600,-600} ;
static const sequence_steps = sizeof(sequence) / sizeof(*sequence) ;
static sequence_index = 0 ;
// If sequence not complete...
if( sequence_index < sequence_steps )
{
// If all motor positions achieved...
if( remainingSteppersFlag == 0x00 )
{
// For each motor set up next position
for( int k = 0; k < NUM_STEPPERS; k++)
{
prepareMovement( k, sequence[sequence_index] ) ;
}
// Start motors
runNoWait() ;
// Next step in sequence
sequence_index++ ;
}
}
// Do other (non-blocking) stuff here while
// simultaneously executing motor sequence
...
}
void allStop()
{
remainingSteppersFlag = 0 ;
}
void loop()
{
...
// Stop sequence immediately on button press
if( digitalRead(buttonPin) == LOW )
{
allStop() ;
sequence_index = sequence_steps ;
}
...
}