问题描述:意外发现定时器再刚使能后立即就进了中断,且是Update中断,比较奇怪,难道Update中断不是定时器计数溢出后才触发吗?因此写下此文章记录相关情况。
测试平台: STM32F103VET6
驱动库版本:标准库V3.5.0
一、首先上测试代码
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
printf("TIM3 EN\r\n");
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIMx更新中断标志
printf("TIM3IRQ\r\n");
LED0=!LED0;
}
}
结果如下:(定时器是配置的500ms溢出)
可见在TIM使能后立即进了一次中断。后面才正常。
图中是用了串口助手的时间戳功能,TIM3 EN 和TIM3IRQ两条之间时间极短所以串口助手没有区分开时间
二、进一步探究
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
printf("TIM3SR=%08X\r\n",TIM3->SR);
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
printf("TIM3 ITEN\r\n");
printf("TIM3SR=%08X\r\n",TIM3->SR);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
printf("TIM3 ITEN2\r\n");
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
printf("TIM3 EN\r\n");
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
结果如下:
以上情况发现,这个误触发的中断还不是出在开启定时器之后,而是在配置了NVIC TIM中断之后立即就触发了,上述测试我们还发现,TIM_TimeBaseInit之后,TIM3->SR寄存器中的更新中断位还被置位了,导致一配置好TIM3中断立即就触发了中断。
三、解决办法
知道了问题出在哪里就好解决了,在使能中断前手动清除更新中断标记即可。
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
printf("TIM3SR=%08X\r\n",TIM3->SR);
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
printf("TIM3 ITEN\r\n");
printf("TIM3SR=%08X\r\n",TIM3->SR);
// TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
printf("TIM3 ITEN2\r\n");
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
printf("TIM3 EN\r\n");
printf("TIM3SR=%08X\r\n",TIM3->SR);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除更新中断请求位
printf("TIM3SR=%08X\r\n",TIM3->SR);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //使能定时器更新中断
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
正常的结果如下:
至于为什么TIM_TimeBaseInit函数初始化后SR寄存器的更新标志就置位了,与定时器里UG位和URS位的使用,分别在TIMx->EGR和TIMx->CR1寄存器里,应该有一定关系。
在TIM_TimeBaseInit函数的最后一句:
这句置位了TIMx->EGR的0bit也就是UG,但在TIM_TimeBaseInit函数之后立即打印TIMx->EGR的寄存器值已经为0x00了(因为UG是软件置位,硬件自动清除,生效后自动就被清除了),如果注释掉TIM_TimeBaseInit函数的最后一句,测试如下:
由上图的测试结果可见,确实与TIMx->EGR的0bit也就是UG有关系,不使能UG位就不会有SR最后一位被置位了。但不知道为啥,这时SR中的更新标志没有置位,定时器更新中断打开后依然立即触发了一次中断,这就有点奇怪了,所以改库函数还是有点行不通,只能用手动清楚标志位的方法。