delay 函数是最常用的工具函数之一,如果它不可靠了,结果会比较令人头疼。
- STM32 中基于 SysTick 实现的 delay_ms/delay_us 是不可重入的,不可重入的原因很简单,因为在 delay 函数中对 SysTick 的寄存器进行了“写操作”:
SysTick->LOAD = DELAY_Nus * DELAY_FAC_US; //时间加载
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL = 0x01 ;
- 同时,SysTick->CTRL 的状态标志位即使只是读取也会改变状态
- 因此,想靠 SysTick 实现可重入的 delay 是不可能的,只能使用笨方法。靠
uint32_t i = N; while(i--);
根据单片机的执行频率以及测试调优,找到一个相对准确的经验值 N。72MHz的 STM32F103的1um 的 N 值测试:- 10000000 次的执行最快时间为 833333 um
- N 的值为: 12
/* 测试 while 空循环 10M 次需要的时间,以此为依据写可重入的 delay 用于中断内部 */
void TEST_DelayReen(void)
{
char numstr[11] = {'\0'};
uint32_t temp = 10000000, tmp2;
SysTick->LOAD = 0xFFFFFF; //最大值 16777215 , SysTIck工作频率9MHz
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL = 0x01 ; //开始倒数
while(temp--);
/* 关闭所有中断测试多次,收到的稳定值是 9277215 */
Dec2Str(SysTick->VAL, numstr);
USART1_SendData(numstr, 11);
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
- 最后(很重要),因为如果这个函数被中断,那么这次 delay 的时间就是设置的时间 N 加上中断的执行时间。所以在主流程中最好还是使用 SysTick 实现的 delay,而可重入的 delay 只在中断中用就行。