STM32开启定时器就立即进Update中断问题探索

问题描述:意外发现定时器再刚使能后立即就进了中断,且是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中的更新标志没有置位,定时器更新中断打开后依然立即触发了一次中断,这就有点奇怪了,所以改库函数还是有点行不通,只能用手动清楚标志位的方法。

参考鸣谢:
https://blog.csdn.net/ygt666/article/details/79586390

http://www.51hei.com/bbs/dpj-40940-1.html

猜你喜欢

转载自blog.csdn.net/weixin_44788542/article/details/113111139