STM32 - Delay延时函数
在使用STM32编程时,经常会用到延时,STM32 C3和C4内核,提供了一个非常简单的定时器 SysTick,可以很好的帮助做定时
1. SysTick
1.1 简介
SysTick定时器(System tick timer,系统滴答定时器),常用来做 延时或系统的心跳时钟。
这样可以节省MCU资源,不用浪费一个定时器。
SysTick定时器就是系统滴答定时器,一个24位倒计数定时器,计数到0时将从RELOAD寄存器中自动重装载定时器初值。
只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式也能工作。
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号为15)。
SysTick中断的优先级也可以设置
1.2 寄存器配置
SysTick定时器一共有四个相关寄存器:
CTRL SysTick 控制和状态寄存器
LOAD SysTick 自动重装载除值寄存器
VAL SysTick 当前值寄存器
CALIB SysTick 校准值寄存器(不常用)
SysTick->CTRL 的各位定义如图
SysTick-> LOAD 的定义如图
SysTick-> VAL 的定义如图
2. 延时函数
1) delay_init()
/* 初始化延迟函数
* 当使用 OS 的时候,此函数会初始化 OS 的时钟节拍
* SYSTICK 的时钟固定为 AHB 时钟的 1/8
* SYSCLK:系统时钟频率
*/
void delay_init(u8 SYSCLK) {
#if SYSTEM_SUPPORT_OS //如果需要支持 OS.
u32 reload;
#endif
SysTick->CTRL&=~(1<<2); //SYSTICK 使用外部时钟源(HCL/8)
fac_us=SYSCLK/8; //不论是否使用 OS,fac_us 都需要使用
#if SYSTEM_SUPPORT_OS //如果需要支持 OS.
reload=SYSCLK/8; //每秒钟的计数次数 单位为 M
reload*=1000000/delay_ostickspersec; //根据 delay_ostickspersec 设定溢出时间
//reload 为 24 位寄存器,最大值:16777216,在 168M 下,约合 0.7989s 左右
fac_ms=1000/delay_ostickspersec; //代表 OS 可以延时的最少单位
SysTick->CTRL|=1<<1; //开启 SYSTICK 中断
SysTick->LOAD=reload; //每 1/delay_ostickspersec 秒中断一次
SysTick->CTRL|=1<<0; //开启 SYSTICK
#else
fac_ms=(u16)fac_us*1000; //非 OS 下,代表每个 ms 需要的 systick 时钟数
#endif
}
SysTick 是 MDK 定义了的一个结构体(在 core_m4.h 里面),里面包含 CTRL、LOAD、VAL、
CALIB 等 4 个寄存器,
2)delay_us(u32 n_us)
//延时 nus
//nus 为要延时的 us 数.
//注意:nus 的值,不要大于 798915us
void delay_us(u32 nus) {
u32 temp;
if(nus==0)
return; //nus=0,直接退出
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL=0x01 ; //开始倒数
do {
temp=SysTick->CTRL;
} while((temp&0x01)&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
实现一次延时 nus 的操作
- 先把要延时的 us 数换算成 SysTick 的时钟数
- 然后写入 LOAD 寄存器
- 然后清空当前寄存器 VAL 的内容,
- 再开启倒数功能
- 等到倒数结束,即延时了 nus。最后关闭 SysTick,清空 VAL 的值。,
Notice:
nus值不能太大,必须保证 nus<=(2^24)/fac_us,否则将导致延时时间不准确。
这里特别说明一下:temp&0x01,这一句是用来判断 systick 定时器是否还处于开启状态,可以防止 systick 被意外关闭导致的死循环。