定时器和延时函数选型

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 内无法做其他事。

相关推荐
✎ ﹏梦醒͜ღ҉繁华落℘4 小时前
单片机基础知识---stm32单片机的优先级
stm32·单片机·mongodb
zd8451015006 小时前
RS485 总线详解
单片机·嵌入式硬件
✎ ﹏梦醒͜ღ҉繁华落℘9 小时前
编程基础 --高内聚,低耦合
c语言·单片机
科芯创展10 小时前
1A,1MHz,30VIN,XZ4115,降压恒流LED驱动芯片
单片机·嵌入式硬件
集芯微电科技有限公司10 小时前
四通道2A输出集成功率电感降压模块专为紧凑型方案设计
人工智能·单片机·嵌入式硬件·生成对抗网络·计算机外设
踏着七彩祥云的小丑10 小时前
嵌入式测试学习第 37 天:异常场景测试:断电、拔插、干扰、非法指令
单片机·嵌入式硬件·学习
意法半导体STM3211 小时前
【官方原创】如何为STM32CubeMX2配置Visual Studio Code配置方案
vscode·stm32·单片机·嵌入式硬件·策略模式·stm32cubemx·嵌入式开发
雾削木12 小时前
B语言经典教程现代化重构
java·前端·stm32·单片机·嵌入式硬件
Hello-FPGA12 小时前
Camera Link 与 CoaXPress 技术对比 如何选择你的相机接口
单片机·嵌入式硬件
项目題供诗13 小时前
STM32-USART串口协议(二十二)
stm32·单片机·嵌入式硬件