FREERTOS_定时器——创建和基本使用

一、核心基础概念

  1. 软件定时器本质:基于系统时钟 tick 实现,由内核的 "定时器服务任务" 管理,触发时执行预设回调函数;
  2. 两种工作模式
    • 周期模式:定时器到期后自动重装载,持续触发回调(如周期性闪烁);
    • 单次模式:定时器到期后停止,仅触发一次回调(如延时 3 秒后恢复默认状态);
  3. 回调函数限制 :必须是void vCallback(TimerHandle_t xTimer)格式,不能调用阻塞 API (如vTaskDelay()xQueueReceive()),仅执行短时间操作。

二、定时器的创建与启动流程

1、包含头文件
复制代码
#include "FreeRTOS.h"
#include "timers.h" // 定时器API声明在此头文件
2、定义定时器句柄
复制代码
TimerHandle_t xMyTimer; // 定时器句柄
3、创建定时器(核心步骤)
复制代码
xMyTimer = xTimerCreate(
  "MyTimer",            // 定时器名称(仅调试用,可自定义)
  pdMS_TO_TICKS(500U),  // 定时周期(毫秒转FreeRTOS tick数)
  pdTRUE,               // 工作模式:pdTRUE=周期,pdFALSE=单次
  (void *)0,            // 定时器ID(区分多个定时器,自定义)
  vMyTimerCallback      // 定时器到期回调函数(必须实现)
);
4、启动定时器

创建后需调用xTimerStart()启动,否则定时器不会工作

复制代码
if(xMyTimer != NULL) {
  xTimerStart(xMyTimer, 0); // 0=非阻塞启动,立即返回
}

三、定时器的基本使用(核心操作)

1、 回调函数实现(核心逻辑载体)
复制代码
// 定时器回调函数(必须符合格式要求)
void vMyTimerCallback(TimerHandle_t xTimer) {
  // 示例:翻转LED(仅执行短时间操作)
  HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
  
  // 注意:不能调用 vTaskDelay()、xQueueReceive() 等阻塞API
}
2、常用API(动态操作定时器)
函数 作用 关键参数说明
xTimerStart() 启动定时器(创建后首次启动) xTicksToWait:启动超时时间(0 = 非阻塞)
xTimerReset() 重置定时器(重新开始计时) 适用于单次模式重复触发,或周期模式重新计时
xTimerChangePeriod() 动态修改定时器周期 第 3 个参数为超时时间(如 0 = 非阻塞修改)
xTimerStop() 停止定时器(停止后需重新启动才生效) xTicksToWait:停止超时时间
3、周期与 tick 数转换

FreeRTOS 定时器周期以 "tick 数" 为单位,需用pdMS_TO_TICKS(ms)将毫秒转换为 tick 数(适配系统时钟频率):

复制代码
// 500毫秒 → 对应tick数(自动适配 configTICK_RATE_HZ)
pdMS_TO_TICKS(500U)

四、例子------单次

时器启动后只触发一次回调函数,触发完成后就自动停止,不会重复执行

创建
复制代码
TimerHandle_t xSwitchTimer; // 模式切换定时器(单次模式)
void vSwitchTimerCallback(TimerHandle_t xTimer); // 模式切换定时器回调函数

  // 1.2 模式切换定时器(单次模式,触发后只执行一次)
  xSwitchTimer = xTimerCreate(
    "SwitchTimer",
    pdMS_TO_TICKS(SWITCH_TIMER_DELAY),
    pdFALSE,               // 单次模式
    (void *)1,             // 定时器ID=1
    vSwitchTimerCallback
  );
回调函数
复制代码
/* 模式切换定时器回调函数:3秒后执行,恢复默认模式 */
void vSwitchTimerCallback(TimerHandle_t xTimer)
{
  // 定时器到期,恢复LED默认模式
  xCurrentLedMode = LED_MODE_DEFAULT;
}

xSwitchTimer单次模式 ,代码中没有在初始化时启动它,而是在按键任务中通过 xTimerReset() 启动 / 重置。

这里我要根据按键触发启动及再次启动它,所以增加了按下按键后再次开启它

复制代码
xTimerReset(xSwitchTimer, 0); // 重置定时器 若定时器已在运行,重置为3秒后触发

五、例子------周期

创建
复制代码
TimerHandle_t xBlinkTimer;  // 基础闪烁定时器(周期模式)
void vBlinkTimerCallback(TimerHandle_t xTimer); // 闪烁定时器回调函数

// 1.1 基础闪烁定时器(周期模式,自动重装载)
  xBlinkTimer = xTimerCreate(
    "BlinkTimer",          // 定时器名称(仅调试用)
    pdMS_TO_TICKS(BLINK_TIMER_PERIOD), // 周期(毫秒转FreeRTOS ticks)
    pdTRUE,                // 模式:pdTRUE=周期模式,pdFALSE=单次模式
    (void *)0,             // 定时器ID(区分多个定时器)
    vBlinkTimerCallback    // 定时器到期回调函数
  );
启动
复制代码
   xTimerStart(xBlinkTimer, 0); // 启动闪烁定时器(0=非阻塞启动)
回调函数
复制代码
/* 定时器回调函数:定时器到期时执行(控制LED翻转)xBlinkTimer  */
void vBlinkTimerCallback(TimerHandle_t xTimer)
{
  // 根据当前LED模式,调整闪烁周期
  switch(xCurrentLedMode) {
    case LED_MODE_FAST:
      // 快闪:修改定时器周期为200ms
      xTimerChangePeriod(xBlinkTimer, pdMS_TO_TICKS(200U),0);
      break;
    case LED_MODE_SLOW:
      // 慢闪:修改定时器周期为800ms
      xTimerChangePeriod(xBlinkTimer, pdMS_TO_TICKS(800U),0);
      break;
    case LED_MODE_DEFAULT:
    default:
      // 默认:恢复500ms周期
      xTimerChangePeriod(xBlinkTimer, pdMS_TO_TICKS(500U),0);
      break;
  }

  // 翻转LED(回调函数中避免长时间操作,仅执行简单逻辑)
  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_10);
}
相关推荐
LlNingyu12 小时前
Go 实现无锁环形队列:面向多生产者多消费者的高性能 MPMC 设计
开发语言·golang·队列·mpmc·数据通道
旖-旎12 小时前
哈希表(存在重复元素||)(4)
数据结构·c++·算法·leetcode·哈希算法·散列表
Lyyaoo.12 小时前
【JAVA基础面经】线程的状态
java·开发语言
Hello小赵12 小时前
C语言如何自定义链接库——编译与调用
android·java·c语言
John.Lewis12 小时前
C++进阶(8)智能指针
开发语言·c++·笔记
無限進步D12 小时前
蓝桥杯赛前刷题
c++·算法·蓝桥杯·竞赛
小贾要学习12 小时前
【Linux】应用层自定义协议与序列化
linux·服务器·c++·json
CoderCodingNo12 小时前
【GESP】C++二级真题 luogu-B4497, [GESP202603 二级] 数数
开发语言·c++·算法
ss27312 小时前
致Java初学者的一封信
java·开发语言
We་ct12 小时前
LeetCode 50. Pow(x, n):从暴力法到快速幂的优化之路
开发语言·前端·javascript·算法·leetcode·typescript·