http://www.openedv.com/thread-75729-1-1.html
在上贴我分享了32外设的一个小程序,但是用SysTick定时器生成的延时函数在主函数和中断中同时使用时,会造成中断完成之后返回主函数时,延时函数卡死,究其原因,先看代码:
[mw_shl_code=c,true]/*****************************
* @file
elay.c
* @brief:initializing SysTick registers as base time for delay and set us&ms delay
* @author:zx
* @date: 2016/5/18
* @version: V0.1
* @attention: none
*****************************/
#include "Delay.h"
void SysTick_Init(void)
{
//SysTick_CLKSource_HCLK 72MHz
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //配置SysTick时钟源为8分频 即 72MHz/8 也可选择不分频
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; //计数器减到0时 不产生异常中断
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关定时器
SysTick->CTRL &= ~SysTick_CTRL_COUNTFLAG_Msk; //异常标志位清零
SysTick->LOAD = 9; // 72MHz/8/9 = 1us 我要每1us产生一次异常则就在重装寄存器中存9
SysTick->VAL = 0; //默认计数器内容是0
}
void Delay_us(u32 us)
{
SysTick->VAL = 0;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开定时器
while(us--)
{
while(!(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk)); //判断标志位是否置位,没有就等待
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关定时器
}
void Delay_ms(u32 ms)
{
while(ms--)
{
Delay_us(1000); // 延时1ms
}
}[/mw_shl_code]
上面是问题代码,在,顺序执行延时的时候一点事也不会有,但是一旦产生了延时嵌套,就造成了主函数卡死。
我先说说原因:systick定时器是一个递减计数器,我在Delay_us代码中,先开定时器,延时之后再关定时器,所以当主函数正在延时时(此时定时器开),中断发生,并且中断内也调用了延时函数,那么此时他也会对systick进行开——关的操作,注意:问题就是关操作,当中断关掉定时器后,返回主函数的延时,延时由于一直在等待标志位而一直处于while等待,但是此时,定时器是关闭的,也就是说,主函数永远也不可能等到标志位置位的发生,所以陷入了无限循环,导致程序卡死。
思考:从主函数延时到中断延时,再到返回中断延时,对于主函数延时的精度会有什么样的影响呢?由于跳出中断以及主函数发生中断时计数器内的计数值的不确定性,导致返回中断会有几百纳秒的延时。
其次,程序的卡死看似解决,但是多次测试之后发现还会有那么几次会卡死,有待进一步探索。
一周热门 更多>