FreeRTOS 软件定时器(Timer)源码分析
FreeRTOS 的软件定时器是一种基于系统节拍(tick)的机制,允许用户创建和管理定时任务。以下是其核心实现逻辑和关键源码解析:
软件定时器的工作原理
FreeRTOS 的软件定时器由两个核心组件构成:
- 定时器服务任务(Daemon Task):一个独立的 FreeRTOS 任务,负责处理定时器的到期回调。
- 定时器命令队列:用于接收其他任务或中断发送的定时器操作命令(如启动、停止、重置等)。
定时器管理通过 xTimerCreate() 创建,通过 xTimerStart() 等 API 触发操作,实际执行由服务任务完成。
关键数据结构
typedef struct tmrTimerControl
{
const char *pcTimerName; // 定时器名称(调试用)
ListItem_t xTimerListItem; // 链表节点,用于插入延迟队列
TickType_t xTimerPeriodInTicks; // 定时周期(tick数)
UBaseType_t uxAutoReload; // 是否为自动重载定时器
void *pvTimerID; // 用户标识符(ID)
TimerCallbackFunction_t pxCallbackFunction; // 回调函数
} xTIMER;
定时器通过链表组织,服务任务按到期时间排序管理。
定时器相关API源码分析:
|
函数 |
描述 |
|
xTimerCreate() |
动态方式创建软件定时器 |
|
xTimerStart() |
开启软件定时器定时 |
|
xTimerStartFromISR() |
在中断中开启软件定时器定时 |
|
xTimerStop() |
停止软件定时器定时 |
|
xTimerStopFromISR() |
在中断中停止软件定时器定时 |
主要分析以上函数.
一.xTimerCreate()
/************************
参数:
1.定时器名字(自己随便取)
2.时间间隔/ms
3.是否重载(单次还是周期性)
4.回调函数地址
************************/
TimerHandle_t xTimerCreate( const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const BaseType_t xAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction )
{
/****************************分配timer结构体地址********************/
Timer_t * pxNewTimer;
pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) );
/******************************************************************/
/***************************如果分配成功***************************/
if( pxNewTimer != NULL )
{
/**********设置当前定时器状态*************/
pxNewTimer->ucStatus = 0x00;
/************timer结构体配置,创建定时器任务的消息队列**********/
prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, xAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
}
return pxNewTimer;
}
二.xTimerStart()/xTimerStop()/xTimerStartFromISR()/xTimerStopFromISR()
#define xTimerStart( xTimer, xTicksToWait ) \
xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )
#define xTimerStop( xTimer, xTicksToWait ) \
xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xTicksToWait ) )
#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) \
xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START_FROM_ISR, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) \
xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP_FROM_ISR, 0, ( pxHigherPriorityTaskWoken ), 0U )
BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, //定时器任务句柄
const BaseType_t xCommandID, //开启还是关闭?
const TickType_t xOptionalValue, //
BaseType_t * const pxHigherPriorityTaskWoken,//是否切换上下文
const TickType_t xTicksToWait ) //阻塞时间
{
BaseType_t xReturn = pdFAIL;
DaemonTaskMessage_t xMessage; //定时器任务(守护进程)用的消息队列
configASSERT( xTimer ); //断言,要创建成功才能使用
if( xTimerQueue != NULL ) //xTimerQueue在TimerCreate中分配
{
/***************配置消息结构体,发送给xTimerQueue******************/
xMessage.xMessageID = xCommandID;
xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
xMessage.u.xTimerParameters.pxTimer = xTimer;
/****************依据xCommandID 决定消息发送方式******************/
if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )
{
if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
{
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
}
else
{
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
}
}
else
{
xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
}
/************************消息添加到队列尾************************/
traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
}
else //没有消息队列
{
mtCOVERAGE_TEST_MARKER();
}
return xReturn;
}
- 无论是否是中断服务程序,Tmer的start和stop都是由xTimerGenericCommand()函数完成,而此函数主要通过调用QueueSend函数完成对定时器服务任务传递指令
- 服务任务的主逻辑在
prvTimerTask()函数中(位于timers.c),核心流程如下:
- 检查定时器队列:从
xTimerQueue接收命令(如启动、停止)。 - 处理到期定时器:遍历链表,检查当前时间是否达到定时器的
xTimerListItem.xItemValue(到期时间)。 - 执行回调:调用
pxCallbackFunction,若为自动重载定时器则重新插入链表。回调函数在服务任务上下文中运行,需注意:避免阻塞操作(可能影响其他定时器)。不可调用
vTaskDelete(NULL)终止服务任务。
void prvTimerTask(void *pvParameters)
{
TickType_t xNextExpireTime;
BaseType_t xListWasEmpty;
for (;;)
{
xQueueReceive(xTimerQueue, &xMessage, portMAX_DELAY);
// 处理命令(如 xTimerStart() 发送的命令)
prvProcessReceivedCommands();
// 处理到期定时器
prvProcessExpiredTimers(xNextExpireTime);
}
}
配置选项
关键配置宏(在 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)
注意事项
- 定时精度:依赖系统节拍,最小间隔为 1 tick。
- 上下文限制:
xTimerStart()等 API 不可在中断中直接调用,需使用xTimerStartFromISR()。 - 资源消耗:每个定时器占用约 40 字节 RAM(依赖架构),服务任务增加调度开销。
通过分析源码可优化定时器使用场景,例如高精度需求需结合硬件定时器。
2051

被折叠的 条评论
为什么被折叠?



