定时器和延时函数选型

1,定时器和延时使用场景对比

场景分类 具体子场景 推荐方式 原因/备注
硬件初始化 时钟稳定等待(如 PLL 起振) 硬件循环 delay 调度器未启动,不能用 OS 延时
外设复位释放(如 LCD 复位脉冲 100ms) 硬件循环 delay 同上,或者用硬件定时器(如 SysTick 裸机轮询)
软件初始化 数据结构、变量赋值 无需延时 -
等待其他模块就绪标志(如传感器上电初始化完成) 阻塞 delay + 检查标志 简单实现,但会占用任务;推荐用事件/队列
任务内操作 周期性读取传感器(允许抖动) vTaskDelay 阻塞任务,适合低优先级周期任务
高精度周期控制(PWM、电机控制) 硬件定时器 OS 软件定时器精度不足(受 tick 限制)
一次性延时后修改 GPIO 软件定时器 不占用任务堆栈,不影响其他任务实时性
与多个异步事件同步(如等待超时或收到消息) 队列/事件组 + 超时 vTaskDelay 无法同时等待事件
中断上下文 中断中需要短延时(去抖动、总线保持) 绝对禁止 delay 必须用硬件定时器或直接退出中断
中断后需要延时处理(如按键长按检测) 启动软件定时器 中断中启动定时器,回调中处理长按逻辑
低功耗 CPU 进入睡眠模式,需要定时唤醒 硬件定时器(RTC/WDT) OS 软件定时器依赖系统 tick,睡眠时可能不工作
空闲任务自动休眠(Tickless) OS 内置机制 FreeRTOS/LiteOS 支持 tickless,使用硬件定时器作为唤醒源
通信 UART/I2C 接收超时检测 软件定时器或带超时的队列接收 队列接收时直接使用 xQueueReceive(..., timeout) 更好,内部阻塞不占CPU
模拟 I2C 的 SCL 时钟延时 硬件循环 delay 微秒级延时,OS 无法满足
用户交互 按键消抖(20ms) 软件定时器 避免阻塞主任务,消抖期间系统仍可响应其他操作
LED 闪烁(1Hz) 软件定时器或任务 + delay 定时器方式更节省任务资源;任务方式更直观
调试与监测 串口打印心跳 vTaskDelay 简单,无需额外创建定时器
看门狗喂狗 周期软件定时器 喂狗必须可靠且不依赖某个任务可能被饿死
系统行为 系统启动后先进行 500ms 预热 起始任务中 vTaskDelay 预热期间无需做其他事,阻塞当前任务即可
多个外设需要按顺序延时上电(如先开 3.3V,20ms 后再开 1.8V) 软件定时器链或任务顺序 delay 简单用任务 delay,复杂用定时器链(首个定时器回调启动第二个)

系统启动后(复位后),某个 GPIO 引脚立即输出高电平 ,经过 10ms 后自动恢复为低电平

2,定时器实现

复制代码
#include "los_swtmr.h"
#include "gpio.h"

// 定时器回调函数
void TimerCallback(UINT32 arg) {
    GPIO_SetLow(PIN_LED);   // 恢复低电平
}

void main(void) {
    // 硬件初始化
    GPIO_Init(PIN_LED, OUTPUT);
    GPIO_SetHigh(PIN_LED);

    // 创建单次软件定时器
    UINT32 timerId;
    SWTMR_CTRL_S stCtrl = {0};
    stCtrl.uwMode = LOS_SWTMR_MODE_ONCE;   // 单次模式
    stCtrl.uwInterval = 10;                // 10ms(注意:LiteOS 定时器单位是 tick,默认 1ms/tick)
    stCtrl.pfnHandler = (SWTMR_PROC_FUNC)TimerCallback;
    LOS_SwtmrCreate(&stCtrl, &timerId);
    LOS_SwtmrStart(timerId);

    // 启动 LiteOS 调度器
    LOS_Start();
}

任务内使用 LOS_TaskDelay(阻塞)

复制代码
#include "los_task.h"
#include "gpio.h"

UINT32 vPulseTask(UINT32 arg) {
    GPIO_Init(PIN_LED, OUTPUT);
    GPIO_SetHigh(PIN_LED);
    LOS_TaskDelay(10);      // 阻塞当前任务 10ms
    GPIO_SetLow(PIN_LED);
    return LOS_OK;
}

void main(void) {
    UINT32 taskId;
    TSK_INIT_PARAM_S taskParam = {0};
    taskParam.pfnTaskEntry = (TSK_ENTRY_FUNC)vPulseTask;
    taskParam.usTaskPrio = 1;
    taskParam.uwStackSize = 0x800;
    taskParam.pcName = "PulseTask";
    LOS_TaskCreate(&taskId, &taskParam);
    LOS_Start();
}
特性 软件定时器(单次/周期) delay(阻塞延时)
是否阻塞 不阻塞任何任务(回调在定时器任务/中断中执行) 阻塞调用该函数的任务
上下文要求 回调中不能调用阻塞 API(如队列接收、delay) 只能在任务中调用
CPU 占用 极低,仅系统时钟中断 + 定时器任务 阻塞期间让出 CPU,唤醒后继续
精度 取决于系统时钟 tick,通常 1ms ~ 10ms 相同
典型用途 超时处理、非阻塞的延时动作、周期性维护 简单的顺序延时、初始化等待

补充: freertos的实现

复制代码
#include "FreeRTOS.h"
#include "timers.h"
#include "gpio.h"   // 假设的 GPIO 操作函数

// 定时器回调函数:将引脚设为低电平
void vTimerCallback(TimerHandle_t xTimer) {
    GPIO_SetLow(PIN_LED);   // 恢复低电平
}

void main(void) {
    // 硬件初始化
    GPIO_Init(PIN_LED, OUTPUT);
    GPIO_SetHigh(PIN_LED);  // 立即输出高电平

    // 创建单次定时器,周期 10ms(单位:Tick,假设 configTICK_RATE_HZ = 1000)
    TimerHandle_t xTimer = xTimerCreate("OneShot", pdMS_TO_TICKS(10), pdFALSE,
                                         NULL, vTimerCallback);
    if (xTimer != NULL) {
        xTimerStart(xTimer, 0);  // 启动定时器,非阻塞
    }

    // 启动调度器(之后定时器会在系统时钟中断/软件定时器任务中执行)
    vTaskStartScheduler();

    // 不会执行到这里
    for(;;);
}
  • xTimerStart 立即返回,不阻塞当前上下文。

  • 10ms 后系统自动调用回调,在软件定时器任务(或中断)中完成电平切换。

  • 不影响其他任务运行,适合在多任务环境中让高电平脉冲独立完成。

延时函数实现

复制代码
#include "FreeRTOS.h"
#include "task.h"
#include "gpio.h"

void vPulseTask(void *pvParameters) {
    GPIO_Init(PIN_LED, OUTPUT);
    GPIO_SetHigh(PIN_LED);      // 高电平
    vTaskDelay(pdMS_TO_TICKS(10)); // 阻塞当前任务 10ms
    GPIO_SetLow(PIN_LED);       // 低电平
    vTaskDelete(NULL);          // 任务结束,可选
}

void main(void) {
    xTaskCreate(vPulseTask, "Pulse", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    vTaskStartScheduler();
}
  • 任务进入阻塞状态,让出 CPU 给其他就绪任务。

  • 实现简单,但占用一个任务堆栈,且该任务在 10ms 内无法做其他事。

相关推荐
三品吉他手会点灯2 小时前
STM32F103 学习笔记-22-DMA(第1节)-DMA功能框图讲解和DMA初始化结构体讲解
笔记·stm32·单片机·嵌入式硬件·学习
ThornArmor4 小时前
【控制篇】斩断无休止空转:4-bit 指令集里的跳转律令与时序状态机
c语言·汇编·c++·单片机·嵌入式硬件
篮子里的玫瑰4 小时前
STM32/MCU【IAP在线升级】全流程深度解析与实战指南
stm32·单片机·嵌入式硬件
深圳市青牛科技实业有限公司5 小时前
D3815C30V/0.8A高调光比 LED恒流驱动器介绍
单片机·嵌入式硬件·人机交互·摄像机
Plankton_Li5 小时前
嵌入式国密加密:STM32L4 + MIRACL 库实现 SM2 加解密
stm32·单片机·嵌入式软件
高速上的乌龟5 小时前
Lattice LFCPNX-100 HSB+Fpga开发详解:2.2 Marvell MV-Q3244 Phy的Podl电路详解
单片机·嵌入式硬件·fpga开发·软件工程
nuoxin1146 小时前
HI3516CRNCV610-20S/富利威
网络·人工智能·单片机·嵌入式硬件·硬件工程
三佛科技-134163842126 小时前
KP311BHWGA 集成整流桥堆二极管非隔离BUCK降压芯片(负压输出电源IC) 典型应用电路
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
嵌入式×边缘AI:打怪升级日志6 小时前
中断入门 — PIR 中断控制板载 LED
单片机·嵌入式硬件