使用过HAL库的都知道,HAL_Delay()是一个ms级延时函数,并且会至少产生1ms的延时,由于系统滴答定时器的中断优先级默认为最低,在中断中不可调用,否则会导致程序阻塞。
在STM32的编程中,不可避免的要使用到us级延时,那么怎么做到us级延时呢?笔者将在本篇文章中详细介绍。注意:本文章只做应用,SysTick原理细节不会讲述过多(懒得讲)
SysTick介绍
SysTick是一个24位的递减计数器,并且捆绑在NVIC中,可以称为内核外设。
在M3内核中,SysTick工作时钟选择位复位值为0,默认使用外部时钟源
在F1的时钟树中可以发现,Cortex系统时钟是主时钟AHB的8分频,SysTick的工作时钟频率就是72/8 = 9MHZ。
在M4内核中,SysTick似乎没有嵌套到NVIC中,而是作为一个独立的内核外设。
注意M4的SysTick工作时钟的复位值不是0,而是1。
SysTick应用
注:以下代码以系统工作主时钟为80MHZ为例
Delay_Init()初始化
TIme_Base代表系统主频,如果为80MHZ,传参传入80即可,如果是M3系列设备,需要将Time_Base/8再赋值给Count_Base
void Delay_Init(uint8_t Time_Base){ // M4:SysTick 时钟默认HCLK 计一个数的时间是 1/80 us
Count_Base += Time_Base;
}
Delay_us()延时函数实现
注意:SysTick是一个24位的递减计数器,计到0后减1重装载计数值。最大计时时间:2^32/80MHZ = 53.68秒。
void Delay_us(uint32_t Time_Count){
Time_Count *= Count_Base; // 一共需要计多少us
uint32_t Count_Old = SysTick->VAL; // 这里需要注意的是,Systick是一个24位的递减计数器
uint32_t Count_New = 0;
uint32_t Count = 0;
uint32_t Reload = SysTick -> LOAD;
while(1){
Count_New = SysTick->VAL;
if(Count_New != Count_Old){
if(Count_New < Count_Old){
Count += Count_Old - Count_New;
}else{
Count += Reload - Count_New + Count_Old;
}
Count_Old = Count_New;
if(Count >= Time_Count){
break;
}
}
}
}
Delay_ms()延时函数
HAL_Delay()可以重写,调用Delay_ms(),这样在中断中也可以使用。
void Delay_ms(uint32_t Time_Count){
Delay_us(1000 * Time_Count);
}
void HAL_Delay(uint32_t Delay){
Delay_ms(Delay);
}
尾言
本应用代码参考正点原子SysTick例程,如有描述错误之处,还请斧正,谢谢!