大家讨论下,进入定时器溢出中断服务函数时应该先清除中断标志位?还是执行完中断服务程序再清除?

2019-08-17 01:02发布

现有2个定时器中断,TIM3定时器50ms中断一次,TIM4定时器1ms中断一次,其中TIM4定时器优先级高于TIM3,且TIM4中断服务函数执行时间长于1ms,如果进入TIM4定时器溢出中断服务函数时先清除中断标志位,发现TIM3中断根本无法执行,但是TIM4中断服务内的函数必须1ms调用一次进行采样。应该怎么设计好呢?
1)因为TIM4中断服务程序执行时间大于1ms,如果进入定时器溢出中断服务函数时马上清除中断标志位,是不是会执行到一半的时候又发生TIM4中断了?TIM永远在等待状态
2)如果是执行完中断服务程序后再清除中断标志,是不是意味着TIM4里面的函数并不是严格上的1m调用一次?
[mw_shl_code=c,true]//定时器3中断服务程序 void TIM3_IRQHandler(void) //500ms中断一次 { if(TIM3->SR&0X0001)//溢出中断 { LED0=!LED0; LED3=!LED3; } TIM3->SR&=~(1<<0);//清除中断标志位 } //通用定时器中断初始化 //这里时钟选择为APB1的2倍,而APB1为36M //arr:自动重装值。 //psc:时钟预分频数 //这里使用的是定时器3! void TIM3_Int_Init(u16 arr,u16 psc) //500ms中断一次 { RCC->APB1ENR|=1<<1; //TIM3时钟使能 TIM3->ARR=arr; //设定计数器自动重装值 TIM3->SC=psc; //预分频器设置 TIM3->DIER|=1<<0;   //允许更新中断 TIM3->CR1|=0x01; //使能定时器3 MY_NVIC_Init(3,1,TIM3_IRQn,2);//抢占1,子优先级3,组2 } //定时器 4 中断服务程序 void TIM4_IRQHandler(void) //1ms中断一次 { static u8 i=0; if(TIM4->SR&0X0001) //溢出中断 { TIM4->SR&=~(1<<0); //清除中断标志位 //中断函数执行时间大于1ms Angle_Calcu(); //计算角加速度 Kalman_Filter_X(Angle_x,Gyro_y); //卡尔曼滤波器 Yijielvbo(Angle_x,Gyro_y); //一阶滤波算法 Erjielvbo(Angle_x,Gyro_y); } } //通用定时器 4 中断初始化 //这里时钟选择为 APB1 的 2 倍,而 APB1 为 36M //arr:自动重装值。 //psc:时钟预分频数 //这里使用的是定时器 4! void TIM4_Int_Init(u16 arr,u16 psc) //1ms中断一次 { RCC->APB1ENR|=1<<2; //TIM4 时钟使能,TIM4在APB1上;T2~T7都在APB1 TIM4->ARR=arr; //设定计数器自动重装值//刚好 1ms TIM4->SC=psc; //预分频器 7200,得到 10Khz 的计数时钟 TIM4->DIER|=1<<0; //允许更新中断 TIM4->CR1|=0x01; //使能定时器 4 MY_NVIC_Init(1,1,TIM4_IRQn,2);//抢占 1,子优先级 2,组 2 }[/mw_shl_code] [mw_shl_code=c,true]谢谢![/mw_shl_code]
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
2条回答
brook_z
1楼-- · 2019-08-17 06:05
第一种情况不会发生,不会一直产生中断的,一定会是退出之后再次进入的。
关于:如果是执行完中断服务程序后再清除中断标志,是不是意味着TIM4里面的函数并不是严格上的1m调用一次?
由于你的执行时间本来就大于1ms,TIM4本来就不会严格执行1ms调用一次,你可以用一个I/O输出高低电平测试就知道了。
caichengxin621
2楼-- · 2019-08-17 06:57
回复【2楼】brook_z:
---------------------------------
通过反复实验验证,已经得出答案了。结论大概是这样:进入定时器中断服务马上清除中断标志位,即便程序执行时间过长,也不会重新进入定时器中断,此时的中断应该是悬挂起来,等到当前的中断服务执行完了会再一次进入定时器中断,如此反复。
    实验过程如下:
        1)在50ms定时器中断中加上500ms的延时,无论是马上清除中断标识还是执行完中断服务再清除,状态灯还是会500ms闪烁。
//定时器3中断服务程序  
void TIM3_IRQHandler(void) //50ms


if(TIM3->SR&0X0001)//溢出中断
{  
LED1=!LED1;
delay_ms(500);
TIM3->SR&=~(1<<0);//清除中断标志位
}         
}
    2)所以,为了不影响其他优先级的执行,正确的做法是等中断服务执行完之后再清除中断标志位。

一周热门 更多>