一.简介
相等于闹钟功能。
其由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()函数进行队列消息接收处理。