FreeRTOS软件定时器
简介
软件定时器的基本概念
定时器:是指从指定的时刻开始,经过一个指定时间,然后触发一个超时事件,用户可以自定义定时器的周期与频率。类似生活中的闹钟,我们可以设置闹钟每天什么时候响,还能设置响的次数,是响一次还是每天都响。
硬件定时器:芯片本身提供的定时器,外部晶振输入提供时钟,通常精度高、中断触发方式
软件定时器:是由操作系统提供的一类系统接口,构建在硬件定时器的基础上,使系统能够提供不受硬件定时器的资源限制的定时器服务,实现的功能与硬件定时器类似。
软硬定时器使用区别:使用硬件定时器时,定时时间到达后会触发中断,用户在中断中处理信息;使用软件定时器时,需要在创建定时器时指定时间到达后要调用的函数(也称作超时函数/回调函数),在回调函数中处理信息。
注意:软件定时器回调函数的上下文是任务,回调函数中不能有任何阻塞任务运行的情况
FreeRTOS定时器功能上的支持
-
裁剪:能通过宏关闭软件定时器功能
-
软件定时器创建
-
软件定时器启动
-
软件定时器停止
-
软件定时器复位
-
软件定时器删除
-
单次模式和周期模式
-
单次模式:启动后,定时时间到后,只执行一次回调函数,之后该定时器删除,不再执行
-
周期模式:启动后,根据定时时间周期性的执行回调函数,直到用户将定时器删除。
-
软件定时器应用场景
硬件定时器资源不足,对定时精度要求不高的任务。比如可以定时闪烁LED灯作为工作状态指示灯。
软件定时器的精度
在操作系统中,通常软件定时器以系统节拍周期为计时单位。系统节拍是系统的心跳节拍,表示系统时钟的频率,类似人的心跳,1秒能跳动多少下。
系统节拍配置为configTICK_RATE_HZ,该宏在 FreeRTOSConfig.h 中有定义,默认是 1000。表示1秒钟跳动1000下,每跳动一下即为1ms。
软件定时器的所定时数值必须是节拍周期的整数倍,由于节拍定义了系统中定时器能够分辨的精确度,系统可以根据实际系统 CPU 的处理能力和实时性需求设置合适的数值,系统节拍周期值越小,精度越高,但是系统开销也越大。
软件定时器运作机制
软件定时器是可选的系统资源,在创建定时器的时候会分配一块内存空间。FreeRTOS的软件定时器采用消息队列进行通信,利用“定时器命令队列”向软件定时器任务发送一些命令,任务在接收到命令就会去处理命令对应的程序,比如启动定时器,停止定时器等。
使用软件定时器需要注意几点
- 软件定时器的回调函数中应快进快出,绝对不允许使用任何可能引软件定时器起任务挂起或者阻塞的 API 接口,在回调函数中也绝对不允许出现死循环
- 软件定时器使用了系统的一个队列和一个任务资源,软件定时器任务的优先级默认为configTIMER_TASK_PRIORITY,为了更好响应,该优先级应设置为所有任务中最高的优先级
- 创建单次软件定时器,该定时器超时执行完回调函数后,系统会自动删除该软件定时器,并回收资源
- 定时器任务的堆栈大小默认为 configTIMER_TASK_STACK_DEPTH 个字节。
软件定时器函数接口
软件定时器的功能是在定时器任务中实现的,(定时器任务在开启任务调度器时由内核自动创建),软件定时器的很多API函数通过一个名字叫“定时器命令队列”的队列来给定时器任务发送命令,该定时器命令队列由RTOS内核提供,且应用程序不能直接访问,其消息队列的长度由宏configTIMER_QUEUE_LENGTH定义。
软件定时器任务:在开启任务调度时创建,可以通过系统裁剪决定是否使用此任务。
软件定时器是一个任务,在下一个定时器到了之前的这段时间,系统要把任务状态转移为阻塞态,让其他的任务能正常运行,这样子就使得系统的资源能充分利用。
软件定时器任务的处理很简单,如果当前有软件定时器在运行,那么它大部分的时间都在等待定时器到期时间的到来,或者在等待对软件定时器操作的命令,而如果没有软件定时器在运行,那定时器任务的绝大部分时间都在阻塞中等待定时器的操作命令
软件定时器动态创建函数 xTimerCreate( ),每个软件定时器只需要很少的RAM空间,创建成功后处于休眠状态,可以使用_xTimerStart()、xTimerReset()、xTimerStartFromISR() 、 xTimerResetFromISR() 、 xTimerChangePeriod() 和xTimerChangePeriodFromISR()_这些函数将其状态转换为活跃态。
/*-------------------------------------------------------------------------------------------
软件定时器创建函数
pcTimerName:软件定时器名字,文本形式,纯粹是为了调试(FreeRTOS使用定时器时通过句柄,而不是名字)
xTimerPeriodInTicks:软件定时器的周期,单位为系统节拍周期(即 tick)
uxAutoReload:设置为pdTURE使用周期模式,设置pdFALSE使用单次模式
pvTimerID:软件定时器ID,数字形式
pxCallbackFunction:软件定时器的回调函数(用户自己实现)
返回值是一个TimerHandle_t类型的句柄
----------------------------------------------------------------------------------------------*/
TimerHandle_t xTimerCreate(const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction )
使用实例
static TimerHandle_t Swtmr1_Handle = NULL;//软件定时器句柄
Swtmr1_Handle = xTimerCreate((const char*)"AutoReloadTimer",
(TickType_t)1000,/* 定时器周期 1000(tick) */
(UBaseType_t)pdTRUE,/* 周期模式 */
(void* )1,/* 为每个计时器分配一个索引的唯一 ID */
(TimerCallbackFunction_t)Swtmr1_Callback); /* 回调函数 */);
if(Swtmr1_Handle != NULL)
{
printf("软件定时器1创建成功\r\n");
xTimerStart(Swtmr1_Handle,0); //开启周期定时器
}
static void Swtmr1_Callback(void* parameter)
{
//软件定时器的回调函数,用户自己实现
}
软件定时器启动函数 xTimerStart( )
软件定时器在创建完成时是处于休眠状态,需要用相关API函数进行启动。系统开始调度时会自动创建一个定时器任务_prvTimerTask( )_,刚开始没有运行的定时器,此任务处于阻塞状态,定时器启动函数是通过定时器命令队列向定时器发送一个启动命令,定时器任务获得命令后解除阻塞,然后执行启动软件定时器命令。
/*------------------------------------------------------------------------------------------------
软件定时器启动函数
xTimer:要操作的软件定时器句柄
xTicksToWait:软件定时器启动命令
返回值:成功pdPASS,失败pdFALSE
-------------------------------------------------------------------------------------------------*/
BaseType_t xTimerStart( xTimer, xTicksToWait );
软件定时器启动函数 xTimerStartFromISR( ) (中断中调用)
/*------------------------------------------------------------------------------------------------
软件定时器启动函数
xTimer:要操作的软件定时器句柄
pxHigherPriorityTaskWoken:判断退出中断后是否要进行任务切换
返回值:成功pdPASS,失败pdFALSE
-------------------------------------------------------------------------------------------------*/
BaseType_t xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken )
软件定时器停止函数 xTimerStop( )
用来停止一个已经启动的软件定时器,同样是通过发送通知命令实现。
/*-----------------------------------------------------------------------------------------------
软件定时器停止函数
xTimer:软件定时器句柄
xBlockTime:用户指定超时时间
-------------------------------------------------------------------------------------------------*/
BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xBlockTime );
//使用实例
static TimerHandle_t Swtmr1_Handle =NULL; //软件定时器句柄
/* 周期模式的软件定时器 1,定时器周期 1000(tick)*/
Swtmr1_Handle=xTimerCreate((const char* )"AutoReloadTimer",
(TickType_t )1000, //定时器周期 1000(tick)
(UBaseType_t )pdTRUE, //周期模式
(void*)1, //为每个计时器分配一个索引的唯一 ID
(TimerCallbackFunction_t)Swtmr1_Callback);//回调函数
if (Swtmr1_Handle != NULL)
{
/**************************************************************************************
xTicksToWait:如果在调用 xTimerStart()时队列已满,则以 tick 为单位指定调用任务应保持
在 Blocked(阻塞)状态以等待 start 命令成功发送到 timer 命令队列的时间。
如果在启动调度程序之前调用 xTimerStart(),则忽略 xTicksToWait。在这里设置等待时间为 0.
**************************************************************************************/
xTimerStart(Swtmr1_Handle,0); //开启周期定时器
}
static void test_task(void* parameter)
{
while (1)
{
/* 用户自己实现任务代码 */
xTimerStop(Swtmr1_Handle,0); //停止定时器
}
}
软件定时器停止函数 xTimerStopFromISR( )(中断中调用)
用来停止一个已经启动的软件定时器,同样是通过发送通知命令实现。
/*-----------------------------------------------------------------------------------------------
软件定时器停止函数
xTimer:软件定时器句柄
pxHigherPriorityTaskWoken:用来判断退出中断前是否进行任务切换
返回值:成功pdPASS,失败pdFALSE
-------------------------------------------------------------------------------------------------*/
BaseType_t xTimerStopFromISR(TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken);
软件定时器删除函数 xTimerDelete( )
用于删除一个已经被创建成功的软件定时器,删除之后就无法使用该定时器,并且定时器相应的资源也会被系统回收释放。
/*-----------------------------------------------------------------------------------------------
软件定时器删除函数
xTimer:软件定时器句柄
xTicksToWait:用户指定的超时时间
返回值:成功pdPASS,失败pdFALSE
-------------------------------------------------------------------------------------------------*/
xTimerDelete( xTimer, xTicksToWait )
FreeRTOS软件定时器的笔记总计完毕,以后有新的认识会继续更新此笔记—2020-11-28