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 或低功耗定时器唤醒。
|