文章目录
- 1.延时函数
- 1.1 vTaskDelay()
- 1.2 vTaskDelayUntil()
- 1.3 系统时钟节拍
- 2.软件定时器
-
- 3.总结
1.延时函数
当任务需要调用延时函数延时时,任务会进入阻塞态,同时发生任务切换,指导延时完成,任务重回阻塞态。
1.1 vTaskDelay()
(1)相对延时
vTaskDelay
延时函数实现的是相对延时,其主要特点是时间计算的节点是将调用 API 的时刻作为起点。
void vTaskDelay( const TickType_t xTicksToDelay )
- 参数为时间节拍数,当
configTICK_RATE_HZ
为1000
时,所以参数数值等于延时ms
数
(2)延时过程
延时函数的主要功能就是将计算任务唤醒时间,并插入到延时列表中
- 任务唤醒时间点 = 调用函数的时刻 + 延时时间值
- 延时列表有两个:
xDelayedTaskList1
和 xDelayedTaskList2
,其中 xDelayedTaskList2
是溢出时使用的列表
唤醒时间点作为列表项的列表值,当任务插入到延时列表中后,按照延时时间从小到大的顺序排序(即列表值)。
vTaskDelay()
prvAddCurrentTaskToDelayedList()
xTimeToWake = xConstTickCount + xTicksToWait; #以当前值为起点计算唤醒时间xTimeToWake
listSET_LIST_ITEM_VALUE() #把xTimeToWake插入任务列表项的列表值
vListInsert() #任务插入延迟列表
1.2 vTaskDelayUntil()
vTaskDelayUntil()
函数实现的是绝对延时,时间计算的起点是上一次任务被唤醒的时间,即任务函数执行的时刻。
void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
const TickType_t xTimeIncrement )
pxPreviousWakeTime
:上一次任务被唤醒的时间点,第一次调用时初始化为进入 while(1)
的时间节点,后续会自动更新xTimeIncrement
:延时节拍数
1.3 系统时钟节拍
(1)滴答定时器
滴答定时器,也叫系统节拍定时器 Systick
,系统运行需要有个系统时钟节拍,xTickCount
就是 FreeRTOS
的系统时钟节拍定时器。每次 SysTick
产生中断后,xTickCount
就会加一。
(2)系统时钟节拍函数
系统时钟节拍函数是 SysTick
中断服务函数调用xPortSysTickHandler()
的,过程如下
(3)唤醒过程-引自Here
要唤醒任务,必须把任务从延迟列表中移到就绪列表,于是追朔延迟列表的调用者,可以其中一个调用者是listGET_OWNER_OF_HEAD_ENTRY()
,继续追朔,调用者是xTaskIncrementTick()
,继续追朔,调用者是xPortSysTickHandler()
,到此追朔完成,上一文已经提及,xPortSysTickHandler()
是SysTick
中断的服务函数,周期性地进行工作。
下面是唤醒的调用层次,唤醒的核心代码在xTaskIncrementTick()
中
xPortSysTickHandler() #中断服务函数
xTaskIncrementTick() #更新xTickCount计数
pxTCB = listGET_OWNER_OF_HEAD_ENTRY() #获取延迟列表项
xItemValue = listGET_LIST_ITEM_VALUE() #获取唤醒时间
if( xConstTickCount < xItemValue ) #如果到达唤醒时间
uxListRemove() #把任务从延迟列表移除
prvAddTaskToReadyList( pxTCB ); #任务插入就绪列表
以上简单总结为:调用延时函数后,计算唤醒时间并加入任务属性中,然后任务加入延迟列表,每个SysTick
中断周期内就会检查延迟列表中的任务是否到达唤醒时间,如果是,就从延迟列表中移到就绪列表,唤醒完成。
2.软件定时器
2.1 定时器概述
定时器的定时周期到了以后会执行一次回调函数。定时器在 FreeRTOS
是一个可选配置,需要在 FreeRTOSConfig.h
中设置,它是由定时器服务任务和定时器命令队列来实现。
注意:不能再回调函数中调用任何会阻塞任务的 API
,如 vTaskDelay()
.
在 FreeRTOSConfig.h
中配置的信息都是跟任务和队列创建相关的参数
#define configUSE_TIMERS 0
#define configTIMER_TASK_PRIORITY (2)
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)
软件定时器分为单次定时器和周期定时器。
- 单次定时器启动时间到了之后,执行一次回调函数便停止运行
- 周期定时器执行完回调函数之后会自动重启
2.2 定时器 API
(1)定时器创建
API | 功能 |
---|
xTimerCreate() | 动态方法创建软件定时器 |
xTimerCreateStatic() | 静态方法创建软件定时器 |
软件定时器创建时会申请一段内存空间,用来存放软件定时器结构体Timer_t
,返回值为定时器句柄,也是申请得到的内存首地址。
- 创建成功的定时器是休眠状态的,需要调用复位或启动函数进行激活
TimerHandle_t xTimerCreate( const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction )
{
Timer_t * pxNewTimer;
pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) );
if( pxNewTimer != NULL )
{
pxNewTimer->ucStatus = 0x00;
prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
}
return pxNewTimer;
}
(2)定时器操控
API | 功能 |
---|
xTimerStart() | 开启软件定时器,用于任务中 |
xTimerStartFromISR() | 开启软件定时器,用于中断中 |
xTimerReset() | 复位软件定时器,用于任务中 |
xTimerResetFromISR() | 复位软件定时器,用于中断中 |
xTimerStop() | 停止软件定时器,用于任务中 |
xTimerStopFromISR() | 停止软件定时器,用于中断中 |
3.总结
FreeRTOS
提供两种延时:相对延时和绝对延时,两种延时计算的时间起点不一样SysTick
中断服务函数中会判断延时列表中的任务是否到达延时时间,如果到了便添加到就绪列表中- 定时器有单次和周期之分,由定时器服务任务与命令队列实现,创建时也需要申请内存空间
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)