stm32定时器中断使用(ARR寄存器注意)
1.自动重装载器介绍
**自动重装载寄存器 ARR **是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。在物理上这个寄存器对应2个寄存器,一个是程序员可以写入或读出的寄存器,称为preload register(预装载寄存器),另一个是程序员看不见的、但在操作中真正起作用的寄存器,称为shadow register(影子寄存器)。
2.ARR使用注意
stm32定时器更新中断时使用自动重装载寄存器时需要注意其自身的影子寄存器。
根据TIMx_CR1寄存器中APRE位的设置,preload register的内容可以随时传送到shadow register,即两者是连通的(permanently),或者在每一次更新事件(UEV)时才把preload register的内容传送到shadow register
预装载寄存器ARR传送到影子寄存器,有两种方式,一种是立刻更新,一种是等触发事件之后更新;这两种方式主要取决于寄存器TIMx->CR1中 APRE 位
使用Cubemx进行stm32代码生成时,通常会让你选择是否使能 auto-reload preload 选项,根据网上对HAL库的使用和博主对定时器的使用都会建议 使能 此处。
-
Enable auto-reload preload 代码使用为如下红框处
对 auto-reload preload 使能 即 APRE = 1
此时当ARR值被修改时,必须在下一次事件UEV发生后才能更新影子寄存器的值
-
Disable auto-reload preload
不使能 auto-reload preload 即 APRE = 0
此时当ARR值被修改时,同时马上更新影子寄存器的值
个人使用时出错总结
本人使用定时器通过中断改变IO端口的高低电平输出PWM波形时,按照网上各个博主所说使能了 auto-reload preload,并且本人在定时器中断代码中直接修改ARR寄存器。最终未能输出直接想要的PWM波形。经过多日排查发现是 使能 auto-reload preload 的问题,过程比较煎熬,但是坚持过来了。
使用的中断代码如下
void TIM2_IRQHandler(void)
{
static uint8 i = 1;
if (TIM2->SR&0X0001)
{
switch(i)
{
case 1:
//SERVO0(1);//虚拟
TIM2PWMChange(ServoPwm[0]);
break;
case 2:
TIM2PWMChange(2500 - ServoPwm[0]);
break;
case 3:
SERVO1(1);//2-7都是真实舵机
TIM2PWMChange(ServoPwm[1]);
break;
case 4:
SERVO1(0);
TIM2PWMChange(2500 - ServoPwm[1]);
break;
case 5:
SERVO2(1);//2-7都是真实舵机
TIM2PWMChange(ServoPwm[2]);
break;
case 6:
SERVO2(0);
TIM2PWMChange(2500 - ServoPwm[2]);
break;
case 7:
SERVO3(1);//2-7都是真实舵机
TIM2PWMChange(ServoPwm[3]);
break;
case 8:
SERVO3(0);
TIM2PWMChange(2500 - ServoPwm[3]);
break;
case 9:
SERVO4(1);//2-7都是真实舵机
TIM2PWMChange(ServoPwm[4]);
break;
case 10:
SERVO4(0);
TIM2PWMChange(2500 - ServoPwm[4]);
break;
case 11:
SERVO5(1);//2-7都是真实舵机
TIM2PWMChange(ServoPwm[5]);
break;
case 12:
SERVO5(0);
TIM2PWMChange(2500 - ServoPwm[5]);
break;
case 13:
SERVO6(1);//2-7都是真实舵机
TIM2PWMChange(ServoPwm[6]);
break;
case 14:
SERVO6(0);
TIM2PWMChange(2500 - ServoPwm[6]);
break;
case 15:
TIM2PWMChange(ServoPwm[7]);
break;
case 16:
TIM2PWMChange(2500 - ServoPwm[7]);
i = 0;
break;
}
}
i++;
TIM2->SR&=~(1<<0);//清除中断标志位
}
以上代码为驱动六个舵机的代码,由于各个舵机周期必须是20ms,区间必须是500-2500,所以加入两个虚拟舵机(空操作,加以理解),以上代码参考幻尔科技LeArm机械臂代码。
如果使用如上代码时 使能 auto-reload preload ,便导致当进入 case 2 时,此时进行一次中断更新,此时重装载值为 TIM2PWMChange(ServoPwm[0])中ServoPwm[0] 设定的值,整体上就每次延迟一个,跟我最初设定值正好相反而且设定的值各往前一个移动。