STM32怎样实现延时?

Cortex-M3 Systick定时器实现精准微秒级延时教程

答案是操作Systick系统嘀嗒定时器。这个定时器比较特殊,它属于Cortex-M3处理器内核外设,故并非STM32所特有,而是所有以CM3为内核的MCU都具有的一种定时器。CM3提供了4个寄存器来控制Systick的行为,其中的校准数值寄存器不常用,一般只用到以下3个。
在这里插入图片描述
在core_cm3.h中对Systick寄存器的定义如下。SysTick_BASE表示SysTick控制及状态寄存器的起始地址,SysTick_Type结构体的成员即为按地址顺序排列的4个寄存器,SysTick就是把从SysTick_BASE开始的连续16个字节的区域定义为嘀嗒时钟。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以通过操作SysTick寄存器以实现系统延时,这里给出一种实现us级、ms级和s级延时的实现方法。以us级延时为例,首先设置了重装载数值寄存器大小,这个值决定了每经过多长时间SysTick的当前倒计数值减为0,它取决于时钟源的时钟频率。例如时钟频率为AHB72MHz的话,想实现1us定时,则LOAD寄存器设置为72,表示每经历72个系统嘀嗒数SysTick完成一次倒计数过程,也就是经历72*(1/72000000)s即1us。设置VAL寄存器为0,可清除CTRL寄存器的位COUNTFLAG。设置CTRL寄存器为5的意思是,将SysTick时钟源设为内核时钟即频率为72MHz,设置位TICKINT为0即倒数到0时不发生异常请求,因为这里没有使用SysTick中断,设置位ENABLE为1使能定时器。到这里定时器配置就做完了,定时器开始倒计数。接着对于每一个微秒,在定时器倒计数过程期间,不断查询寄存器CTRL的位COUNTFLAG的值,如果该位变为1则表明一次倒计数过程完毕即经历的1us,此时for循环跳到下一个微秒继续重复此操作,最终实现延时目标微秒数。循环完成后操作CTRL寄存器关闭定时器。ms级延时的实现过程也一样。

#define DELAY_1US_TICK_NUM (72)
#define DELAY_1MS_TICK_NUM (72000)
void delay_us(u32 nus) {
	u32 i;
	SysTick->LOAD = DELAY_1US_TICK_NUM;
	SysTick->VAL = 0;
	SysTick->CTRL = 5;
	for(i = 0;i < nus;i++) {
		while(!((SysTick->CTRL)&(1<<16))) {}
	}
	SysTick->CTRL = 0;	
}
void delay_ms(u32 nms) {
	u32 i;
	SysTick->LOAD = DELAY_1MS_TICK_NUM;
	SysTick->VAL = 0;
	SysTick->CTRL = 5;
	for(i = 0;i < nms;i++) {
		while(!((SysTick->CTRL)&(1<<16))) {}
	}
	SysTick->CTRL = 0;	
}
void delay_s(u32 ns) {
	delay_ms(ns*1000);
}
STM32 使用 **SysTick 定时器**(系统滴答定时器)可以非常方便地实现 **毫秒级延时(ms)**,这是 STM32 HAL 库默认使用的系统时钟源。 --- ## ✅ SysTick 简介 SysTick 是 ARM Cortex-M 内核的一个内置定时器,常用于: - 提供系统节拍(tick); - 实现 `HAL_GetTick()` 和 `HAL_Delay()` 函数; - 毫秒级精确延时; - 系统调度(如 FreeRTOS); --- ## ✅ 1. SysTick 初始化(HAL 库自动完成) 在 `main()` 函数中调用: ```c HAL_Init(); ``` 这个函数会自动初始化 SysTick,使其每 **1ms** 触发一次中断,并调用 `HAL_IncTick()` 增加系统时间计数器。 你也可以手动初始化 SysTick: ```c SysTick_Config(SystemCoreClock / 1000); // 1ms 中断一次 ``` 其中 `SystemCoreClock` 是当前系统时钟频率(如 80 MHz)。 --- ## ✅ 2. 使用 HAL_Delay() 实现毫秒级延时 这是最简单的方法,HAL 库已经封装好了: ```c HAL_Delay(1000); // 延时 1000ms = 1s ``` 其内部实现基于 `HAL_GetTick()`: ```c void HAL_Delay(uint32_t Delay) { uint32_t tickstart = HAL_GetTick(); while ((HAL_GetTick() - tickstart) < Delay); } ``` --- ## ✅ 3. 手动使用 SysTick 寄存器实现延时 如果你不想依赖 HAL 库,也可以直接操作 SysTick 寄存器实现延时。 ### 示例:使用 SysTick 实现精确延时(毫秒级) ```c void SysTick_Delay_ms(uint32_t ms) { SysTick->CTRL = 0; // 清除控制寄存器 SysTick->LOAD = (SystemCoreClock / 1000) * ms; // 设置延时时间(ms) SysTick->VAL = 0; // 清除当前计数值 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk; // 使能 SysTick while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); // 等待计数到 0 SysTick->CTRL = 0; // 关闭 SysTick } ``` ### ✅ 使用方法: ```c SysTick_Delay_ms(500); // 延时 500ms ``` --- ## ✅ 4. 使用 HAL_GetTick() 实现非阻塞延时(适合中断中使用) ```c static uint32_t last_time = 0; if ((HAL_GetTick() - last_time) >= 1000) { // 每隔 1s 执行一次 last_time = HAL_GetTick(); HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); } ``` --- ## ✅ 总结 | 方法 | 是否阻塞 | 是否依赖 HAL | 适用场景 | |------|----------|----------------|-----------| | `HAL_Delay()` | ✅ 阻塞 | ✅ 是 | 简单延时 | | `SysTick_Delay_ms()` | ✅ 阻塞 | ❌ 否 | 精确控制 | | `HAL_GetTick()` | ❌ 非阻塞 | ✅ 是 | 多任务延时 | | `SysTick` 中断 | ❌ 非阻塞 | ❌ 否 | 系统调度、RTOS | --- ##
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值