一.简介
相等于闹钟功能。
其由vTaskStartScheduler()函数开启任务调度的时候,同时创建一个用于管理软件定时器的任务,叫做软件定时器服务任务。
软件定时器与硬件定时器对比:
硬件定时器在裸机项目中是由外设提供的功能。
优点:
数量不限,可以创建多个。硬件定时器数量有限
使用简单,成本低
缺点:
精度不够硬件定时器高。(软件定时器以系统时钟为基准,系统时钟中断优先级较低,容易被打断)
在软件定时器的回调中不可以使用会导致阻塞的api,因为软件定时器回调函数本身不是任务
二.软件定时器的命令队列
FreeRTOS 提供了许多软件定时器相关的API函数,这些API函数大多都是往定时器的队列中写入消息(发送命令),这个队列叫做软件定时器命令队列,是提供给FreeRTOS中的软件定时器使用的,用户是不能直接访问的。
三.api
//创建
TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction )TimerHandle_t xTimerCreateStatic( const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction,StaticTimer_t *pxTimerBuffer )//开启
xTimerStart( xTimer, xTicksToWait )
xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken )//停止
xTimerStop( xTimer, xTicksToWait )
xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken )//重置
xTimerReset( xTimer, xTicksToWait )
xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken )//更改周期时间
xTimerChangePeriod( xTimer, xNewPeriod, xTicksToWait )
xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken )
四.软件定时器服务任务
//任务开启流程
vTaskStartScheduler()----->xTimerCreateTimerTask()----->prvCheckForValidListAndQueue();----->创建两个列表一个队列,当前定时器列表与溢出列表//两个列表vListInitialise( &xActiveTimerList1 );vListInitialise( &xActiveTimerList2 );//一个命令队列xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) );//创建任务xTaskCreate( prvTimerTask, configTIMER_SERVICE_TASK_NAME, configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle );
//任务处理
//从pxCurrentTimerList列表头部获取下一个定时器
xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
prvProcessTimerOrBlockTask()//获取当前时间
1 prvSampleTimeNow()
//判断是否超时
2 if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )//超时处理2.1 prvProcessExpiredTimer( xNextExpireTime, xTimeNow );//从列表移除2.1.1 uxListRemove( &( pxTimer->xTimerListItem ) );//判断是否是周期定时器2.1.2 if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )//如果是周期定时器则重新装载2.1.3 if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE )//如果不是周期定时器则改变timer状态2.3.4 pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;//未超时处理,判断溢出列表是否为空2.2 xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );//把当前定时器任务加入到等待列表中,等待消息2.3 vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );
需要注意的是,当定时器任务加入到等待列表之后,无法接收队列消息,只有等待系统时间片到达唤醒时,才可以调用prvProcessReceivedCommands()函数进行队列消息接收处理。