一、软件定时器的特性
- 定时器的关键成员:周期、回调函数
- 定时器的指定类型:一次性、可自动重载定时器
- 定时器的状态:运行、休眠
- FreeRTOS的软件定时器基于Tick中断实现,但是由于实时系统不允许在内核、中断中执行不确定时间的代码,因此定时器函数被放到了RTOS守护任务中实现
二、RTOS守护任务
- 优先级:configTIMER_TASK_PRIORITY,默认是2,高于IDLE任务
- 消息队列的长度:configTIMER_QUEUE_LENGTH,默认是10,40字节
- 用户调用定时器函数,通过专用的定时器消息队列,发送给RTOS守护任务,在RTOS守护任务中读消息队列,并执行相应的定时器处理函数
- prvTimerTask在调用vTaskStartScheduler时被创建
三、prvTimerTask任务
- static void prvTimerTask( void *pvParameters )
- {
- TickType_t xNextExpireTime;
- BaseType_t xListWasEmpty;
- for( ;; )
- {
- xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty ); // 从pxCurrentTimerList获得下一个定时器到期时间,升序排列,头表示第一个到期的定时器
- prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty ); // 定时器到期执行prvProcessExpiredTimer,没到期则有时间限制的等待xTimerQueue(最多等xNextExpireTime - xTimeNow)
- prvProcessReceivedCommands(); // 处理接收命令,非阻塞循环读取队列xTimerQueue,处理message,包括启动定时器、停止定时器。修改定时器、删除定时器
- }
- }
- static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow )
- {
- // 定时器到期了,将定时器从 pxTimer->xTimerListItem队列中移除
- // 如果自动重载,则重新计算超时时间,再把timer加入队列,并通过xTimerGenericCommand函数发送tmrCOMMAND_START_DONT_TRACE命令
- // 最后执行定时器的回调函数
- }
复制代码 四、定时器相关函数
- TimerHandle_t xTimerCreate( const char * const pcTimerName, // 定时器名称
- const TickType_t xTimerPeriodInTicks, // 定时器周期
- const UBaseType_t uxAutoReload, // 是否自动重载
- void * const pvTimerID, // ID
- TimerCallbackFunction_t pxCallbackFunction ) // 回调函数
- {
- Timer_t *pxNewTimer;
- pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); // 分配空间
- prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); // 初始化
- return pxNewTimer;
- }
- static void prvInitialiseNewTimer( const char * const pcTimerName,
- const TickType_t xTimerPeriodInTicks,
- const UBaseType_t uxAutoReload,
- void * const pvTimerID,
- TimerCallbackFunction_t pxCallbackFunction,
- Timer_t *pxNewTimer )
- {
- prvCheckForValidListAndQueue();
- pxNewTimer->pcTimerName = pcTimerName;
- pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
- pxNewTimer->uxAutoReload = uxAutoReload;
- pxNewTimer->pvTimerID = pvTimerID;
- pxNewTimer->pxCallbackFunction = pxCallbackFunction;
- vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); // 初始化链表节点
- }
- // 定时器删除函数
- #define xTimerDelete( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xTicksToWait ) )
- // 定时器复位函数
- #define xTimerReset( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_RESET, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )
- // 定时器启动函数
- #define xTimerStart( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )
- // 定时器停止函数
- #define xTimerStop( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xTicksToWait ) )
- // 定时器更改定时周期函数
- #define xTimerChangePeriod( xTimer, xNewPeriod, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xTicksToWait ) )
复制代码 五、守护任务中对不同定时器函数命令的处理
- tmrCOMMAND_START、tmrCOMMAND_RESET、tmrCOMMAND_START_FROM_ISR、tmrCOMMAND_RESET_FROM_ISR、tmrCOMMAND_START_DONT_TRACE(重载),从list移除定时器,调用prvInsertTimerInActiveList将定时器加入pxCurrentTimerList中
- tmrCOMMAND_STOP、tmrCOMMAND_STOP_FROM_ISR,从list中移除定时器
- tmrCOMMAND_CHANGE_PERIOD、tmrCOMMAND_CHANGE_PERIOD_FROM_ISR,从list移除定时器,更新时间通过prvInsertTimerInActiveList加入list
- tmrCOMMAND_DELETE,,从list移除定时器,在vPortFree( pxTimer )释放空间
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |