以下是一个基于 FreeRTOS 的软件定时器(Software Timer) 的完整示例代码,包含初始化、定时器创建、启动和回调函数实现,适用于实际应用场景(如周期性任务控制)。
示例场景
使用软件定时器实现以下功能:
- 每隔 1秒 打印一次系统运行时间。
- 每隔 500毫秒 切换 LED 状态。
代码实现
1. 配置 FreeRTOS(FreeRTOSConfig.h
)
#define configUSE_TIMERS 1 // 启用软件定时器
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) // 定时器任务优先级(建议较高)
#define configTIMER_QUEUE_LENGTH 10 // 定时器命令队列长度
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) // 定时器任务堆栈大小
2. 定义定时器句柄和回调函数
#include "FreeRTOS.h"
#include "timers.h"
// 定义定时器句柄
TimerHandle_t xPrintTimerHandle = NULL;
TimerHandle_t xLedTimerHandle = NULL;
// 定时器1回调函数:打印系统时间
void vPrintTimerCallback(TimerHandle_t xTimer) {
static uint32_t tickCount = 0;
tickCount = xTaskGetTickCount(); // 获取系统节拍数
printf("[Timer] System Ticks: %lu ms\n", tickCount);
}
// 定时器2回调函数:切换LED状态
void vLedTimerCallback(TimerHandle_t xTimer) {
static bool ledState = false;
ledState = !ledState;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, ledState ? GPIO_PIN_SET : GPIO_PIN_RESET);
printf("[Timer] LED Toggled\n");
}
3. 创建并启动定时器(在任务中初始化)
void StartDefaultTask(void *argument) {
// 创建定时器1:1秒周期,自动重载
xPrintTimerHandle = xTimerCreate(
"PrintTimer", // 定时器名称(调试用)
pdMS_TO_TICKS(1000), // 定时周期(1秒)
pdTRUE, // 自动重载(周期性)
(void *)0, // 定时器ID(可传递参数)
vPrintTimerCallback // 回调函数
);
// 创建定时器2:500毫秒周期,自动重载
xLedTimerHandle = xTimerCreate(
"LedTimer",
pdMS_TO_TICKS(500),
pdTRUE,
(void *)0,
vLedTimerCallback
);
// 启动定时器
if (xPrintTimerHandle != NULL && xLedTimerHandle != NULL) {
xTimerStart(xPrintTimerHandle, 0); // 第二个参数是阻塞时间(0表示不阻塞)
xTimerStart(xLedTimerHandle, 0);
}
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000)); // 主任务延时(非必要)
}
}
4. 主函数中启动调度器
int main(void) {
// 硬件初始化(如LED GPIO、串口等)
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
// 创建启动任务
xTaskCreate(StartDefaultTask, "StartTask", 128, NULL, 1, NULL);
// 启动FreeRTOS调度器
vTaskStartScheduler();
while (1) {}
}
关键解释
-
定时器创建
xTimerCreate()
:动态分配定时器对象,需指定名称、周期、重载模式、ID 和回调函数。pdMS_TO_TICKS()
:将毫秒时间转换为 FreeRTOS 节拍数(依赖configTICK_RATE_HZ
)。
-
定时器启动
xTimerStart()
:启动定时器,第二个参数是等待命令发送到队列的最大时间(0表示不阻塞)。
-
回调函数特性
- 回调函数在 定时器任务(Timer Task) 中执行,优先级由
configTIMER_TASK_PRIORITY
决定。 - 不可调用阻塞函数(如
vTaskDelay
),否则会阻塞定时器任务。
- 回调函数在 定时器任务(Timer Task) 中执行,优先级由
输出结果
[Timer] System Ticks: 1000 ms
[Timer] LED Toggled
[Timer] LED Toggled
[Timer] System Ticks: 2000 ms
[Timer] LED Toggled
[Timer] LED Toggled
...
常见问题
-
定时器回调未执行
- 检查
configTIMER_TASK_PRIORITY
是否足够高,避免被其他任务阻塞。 - 确保定时器任务堆栈(
configTIMER_TASK_STACK_DEPTH
)足够。
- 检查
-
定时精度不足
- 软件定时器精度依赖系统节拍(如
configTICK_RATE_HZ=1000
时最小间隔 1ms)。 - 高精度需求请改用硬件定时器。
- 软件定时器精度依赖系统节拍(如
实际应用扩展
- 超时检测:用于通信协议等待应答超时。
- 任务看门狗:定期检查任务是否存活。
- 数据采集:周期性读取传感器数据。