2. 非阻塞式延时
(1) 定时器中断延时
原理:利用定时器中断触发延时结束事件。
代码示例:
volatile uint8_t delay_done = 0;
void TIMER_IRQ_Handler() {
if (TIMER->SR & TIMER_FLAG_UPDATE) {
delay_done = 1;
TIMER->SR &= ~TIMER_FLAG_UPDATE;
}
}
void delay_ms(uint32_t ms) {
TIMER->ARR = ms * 1000; // 设置定时器自动重装载值
TIMER->CR1 |= TIMER_ENABLE; // 启动定时器
while (!delay_done); // 等待中断标志
delay_done = 0;
}
优点:释放 CPU 资源,可与其他任务并行执行。
缺点:需配置中断和定时器,代码复杂度稍高。
(2) 硬件定时器 + 非阻塞查询
原理:使用硬件定时器记录时间戳,通过差值计算是否超时。
代码示例:
uint32_t get_tick() {
return TIMER->CNT; // 获取当前定时器计数值
}
void delay_non_blocking(uint32_t start_tick, uint32_t delay_ticks) {
while ((get_tick() - start_tick) < delay_ticks);
}
// 调用示例:
uint32_t start = get_tick();
delay_non_blocking(start, 1000); // 延时 1000 个定时器周期
优点:非阻塞,适合主循环中处理多任务。
缺点:需主动调用时间检查。
3. 高级延时方案
(1) SysTick 定时器(ARM Cortex-M 内核)
原理:利用 Cortex-M 内置的 SysTick 定时器实现精准延时。
代码示例:
void SysTick_Init() {
SysTick->LOAD = SystemCoreClock / 1000 - 1; // 1ms 中断一次
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
}
void delay_ms(uint32_t ms) {
uint32_t start = SysTick->VAL;
while (ms--) {
while (((start - SysTick->VAL) & 0xFFFFFF) >= (SystemCoreClock / 1000));
start = SysTick->VAL;
}
}
优点:高精度,与内核时钟同步。
缺点:依赖特定硬件(如 ARM Cortex-M)。
(2) RTOS 延时(如 FreeRTOS)
原理:利用实时操作系统(RTOS)的任务调度机制实现延时。
代码示例:
#include "FreeRTOS.h"
#include "task.h"
void task_function() {
while (1) {
vTaskDelay(pdMS_TO_TICKS(100)); // 延时 100ms
// 执行其他任务
}
}
优点:完全非阻塞,支持多任务并发。
缺点:需引入 RTOS,增加系统复杂度。
(3) PWM 或 DMA 硬件延时
原理:利用 PWM 输出或 DMA 传输自动控制延时(如生成精确脉冲)。
适用场景:需要硬件级精准延时的场景(如 WS2812 LED 驱动)。
4. 其他特殊实现
看门狗定时器:复用看门狗定时器实现超时检测(需谨慎使用)。
低功耗模式延时:在低功耗模式下使用 RTC 或低功耗定时器唤醒。
|