这个 ISR 程序是如何工作的?
How does this ISR routine work?
我目前正在尝试为步进电机编写步进信号,最近发现 atmel 已经编写了这个 application note,
并为此目的提供了一些代码。我必须提供给我的电机的信号是脉冲调制信号,其中信号的频率决定了速度,而不是它们提供的 4 针信号。该代码在 github (link) 上可用。
但我目前正在质疑控制电机所有阶段(停止、加速、运行、减速)的 ISR 例程。
更具体地说,它如何跟踪负责更改状态的 step_count 。
#pragma vector=TIMER1_COMPA_vect
__interrupt void speed_cntr_TIMER1_COMPA_interrupt( void )
{
// Holds next delay period.
unsigned int new_step_delay;
// Remember the last step delay used when accelrating.
static int last_accel_delay;
// Counting steps when moving.
static unsigned int step_count = 0;
// Keep track of remainder from new_step-delay calculation to incrase accurancy
static unsigned int rest = 0;
OCR1A = srd.step_delay;
switch(srd.run_state) {
case STOP:
step_count = 0;
rest = 0;
// Stop Timer/Counter 1.
TCCR1B &= ~((1<<CS12)|(1<<CS11)|(1<<CS10));
status.running = FALSE;
break;
case ACCEL:
sm_driver_StepCounter(srd.dir);
step_count++;
srd.accel_count++;
new_step_delay = srd.step_delay - (((2 * (long)srd.step_delay) + rest)/(4 * srd.accel_count + 1));
rest = ((2 * (long)srd.step_delay)+rest)%(4 * srd.accel_count + 1);
// Chech if we should start decelration.
if(step_count >= srd.decel_start) {
srd.accel_count = srd.decel_val;
srd.run_state = DECEL;
}
// Chech if we hitted max speed.
else if(new_step_delay <= srd.min_delay) {
last_accel_delay = new_step_delay;
new_step_delay = srd.min_delay;
rest = 0;
srd.run_state = RUN;
}
break;
case RUN:
sm_driver_StepCounter(srd.dir);
step_count++;
new_step_delay = srd.min_delay;
// Chech if we should start decelration.
if(step_count >= srd.decel_start) {
srd.accel_count = srd.decel_val;
// Start decelration with same delay as accel ended with.
new_step_delay = last_accel_delay;
srd.run_state = DECEL;
}
break;
case DECEL:
sm_driver_StepCounter(srd.dir);
step_count++;
srd.accel_count++;
new_step_delay = srd.step_delay - (((2 * (long)srd.step_delay) + rest)/(4 * srd.accel_count + 1));
rest = ((2 * (long)srd.step_delay)+rest)%(4 * srd.accel_count + 1);
// Check if we at last step
if(srd.accel_count >= 0){
srd.run_state = STOP;
}
break;
}
srd.step_delay = new_step_delay;
}
在我看来,step_count 是否在 ISR 开始时设置为零,并在状态 ACCEL、运行 或 DECEL 中递增。
快速调试确实显示变量增加到我想要的值,但我真的不知道如何。
我知道遗漏了一些非常简单的东西。
您需要了解 static
应用于函数局部变量时的工作原理。
即static unsigned int step_count = 0;
表示第一次进入函数step_count
设置为0,并不是每次进入函数都设置
static
表示它不是堆栈变量,它与全局变量 space 在同一内存中,只是只能在声明它的函数内部访问。
这三个变量是静态的。这意味着它们只会被初始化一次:
// Remember the last step delay used when accelrating.
static int last_accel_delay;
// Counting steps when moving.
static unsigned int step_count = 0;
// Keep track of remainder from new_step-delay calculation to incrase accurancy
static unsigned int rest = 0;
如果您遵循代码,您会发现它们用于从一个中断到下一个中断保持状态。
我目前正在尝试为步进电机编写步进信号,最近发现 atmel 已经编写了这个 application note, 并为此目的提供了一些代码。我必须提供给我的电机的信号是脉冲调制信号,其中信号的频率决定了速度,而不是它们提供的 4 针信号。该代码在 github (link) 上可用。
但我目前正在质疑控制电机所有阶段(停止、加速、运行、减速)的 ISR 例程。 更具体地说,它如何跟踪负责更改状态的 step_count 。
#pragma vector=TIMER1_COMPA_vect
__interrupt void speed_cntr_TIMER1_COMPA_interrupt( void )
{
// Holds next delay period.
unsigned int new_step_delay;
// Remember the last step delay used when accelrating.
static int last_accel_delay;
// Counting steps when moving.
static unsigned int step_count = 0;
// Keep track of remainder from new_step-delay calculation to incrase accurancy
static unsigned int rest = 0;
OCR1A = srd.step_delay;
switch(srd.run_state) {
case STOP:
step_count = 0;
rest = 0;
// Stop Timer/Counter 1.
TCCR1B &= ~((1<<CS12)|(1<<CS11)|(1<<CS10));
status.running = FALSE;
break;
case ACCEL:
sm_driver_StepCounter(srd.dir);
step_count++;
srd.accel_count++;
new_step_delay = srd.step_delay - (((2 * (long)srd.step_delay) + rest)/(4 * srd.accel_count + 1));
rest = ((2 * (long)srd.step_delay)+rest)%(4 * srd.accel_count + 1);
// Chech if we should start decelration.
if(step_count >= srd.decel_start) {
srd.accel_count = srd.decel_val;
srd.run_state = DECEL;
}
// Chech if we hitted max speed.
else if(new_step_delay <= srd.min_delay) {
last_accel_delay = new_step_delay;
new_step_delay = srd.min_delay;
rest = 0;
srd.run_state = RUN;
}
break;
case RUN:
sm_driver_StepCounter(srd.dir);
step_count++;
new_step_delay = srd.min_delay;
// Chech if we should start decelration.
if(step_count >= srd.decel_start) {
srd.accel_count = srd.decel_val;
// Start decelration with same delay as accel ended with.
new_step_delay = last_accel_delay;
srd.run_state = DECEL;
}
break;
case DECEL:
sm_driver_StepCounter(srd.dir);
step_count++;
srd.accel_count++;
new_step_delay = srd.step_delay - (((2 * (long)srd.step_delay) + rest)/(4 * srd.accel_count + 1));
rest = ((2 * (long)srd.step_delay)+rest)%(4 * srd.accel_count + 1);
// Check if we at last step
if(srd.accel_count >= 0){
srd.run_state = STOP;
}
break;
}
srd.step_delay = new_step_delay;
}
在我看来,step_count 是否在 ISR 开始时设置为零,并在状态 ACCEL、运行 或 DECEL 中递增。
快速调试确实显示变量增加到我想要的值,但我真的不知道如何。
我知道遗漏了一些非常简单的东西。
您需要了解 static
应用于函数局部变量时的工作原理。
即static unsigned int step_count = 0;
表示第一次进入函数step_count
设置为0,并不是每次进入函数都设置
static
表示它不是堆栈变量,它与全局变量 space 在同一内存中,只是只能在声明它的函数内部访问。
这三个变量是静态的。这意味着它们只会被初始化一次:
// Remember the last step delay used when accelrating.
static int last_accel_delay;
// Counting steps when moving.
static unsigned int step_count = 0;
// Keep track of remainder from new_step-delay calculation to incrase accurancy
static unsigned int rest = 0;
如果您遵循代码,您会发现它们用于从一个中断到下一个中断保持状态。