一、软件定时器简介
1、软件定时器概述
软件定时器允许设置一段时间,当设置的时间到达之后就执行指定的功能函数,被定时器调用的这个功能函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期,简而言之,当定时器的定时周期到了以后就会执行回调函数。
2、回调函数的注意事项
软件定时器的回调函数是在定时器服务任务中执行的,所以一定不能在回调函数中调用任何会阻塞任务的API函数!比如,定时器回调函数中千万不能调用vTaskDelay()、vTaskDelayUnti(),还有一些访问队列或者信号量的非零阻塞时间的API函数也不能调用。
二、定时器服务任务/Daemon任务
1、定时器服务任务与队列
定时器是一个可选的、不属于FreeRTOS内核的功能,它是由定时器服务(或Daemon)任务来提供的。FreeRTOS提供了很多定时器有关的API函数,这些API函数大多都使用FreeRTOS的队列发送命令给定时器服务任务。这个队列叫做定时器命令队列。定时器命令队列是提供给FreeRTOS的软件定时器使用的,用户不能直接访问!
上图左侧部分属于用户应用程序的一部分,并且会在某个用户创建的用户任务中调用。图中右侧部分是定时器服务任务的任务函数,定时器命令队列将用户应用任务和定时器服务任务连接在一起。在这个例子中,应用程序调用了函数xTimerReset(),结果就是复位命令会被发送到定时器命令队列中,定时器服务任务会处理这个命令。应用程序是通过函数xTimerReset()间接的向定时器命令队列发送了复位命令,并不是直接调用类似xQueueSend()这样的队列操作函数发送的。
2、定时器相关配置
软件定时器有一个定时器服务任务和定时器命令队列,这两个东西肯定是要配置的,配置方法和我们前面讲解的FreeRTOSCofig.h一样,而且相关的配置也是放到文件FreeRTOSConfig.h中的,涉及到的配置如下:
- 1、configUSE_TIMERS
如果要使用软件定时器的话宏configUSE_TIMERS一定要设置为1,当设置为1的话定时器服务任务就会在启动FreeRTOS调度器的时候自动创建。 - 2、configTIMER_TASK_PRIORITY
设置软件定时器服务任务的任务优先级,可以为0~(configMAX_PRIORITIES-1)。优先级一定要根据实际的应用要求来设置。如果定时器服务任务的优先级设置的高的话,定时器命令队列中的命令和定时器回调函数就会及时的得到处理。 - 3、configTIMER_QUEUE_LENGTH
此宏用来设置定时器命令队列的队列长度。 - 4、configTIMER_TASK_STACK_DEPTH
此宏用来设置定时器服务任务的任务堆栈大小,单位为字,不是字节!对于STM32来说一个字是4字节。由于定时器服务任务中会执行定时器的回调函数,因此任务堆栈的大小一定要根据定时器的回调函数来设置。
三、单次定时器和周期定时器
软件定时器分两种:单次定时器和周期定时器,单次定时器的话定时器回调函数就执行一次,比如定时1s,当定时时间到了以后就会执行一次回调函数,然后定时器就会停止运行。对于单次定时器我们可以再次手动重新启动(调用相应的API函数即可),但是单次定时器不能自动重启。相反的,周期定时器一旦启动以后就会在执行完回调函数以后自动的重新启动,这样回调函数就会周期性的执行。
上图中Timer1为单次定时器,定时器周期为100,Timer2为周期定时器,定时器周期为200。
四、软件定时器相关API函数
1、复位软件定时器
FreeRTOS提供了两个API函数来完成软件定时器的复位,如下表所示:
函数 | 描述 |
---|
xTimerReset() | 复位软件定时器,用在任务中。 |
xTimerResetFromISR() | 复位软件定时器,用在中断服务函数中。 |
- ①、函数xTimerReset()
复位一个软件定时器,此函数只能用在任务中,不能用于中断服务函数!此函数是一个宏,真正执行的是函数xTimerGenericCommand(),函数原型如下:
BaseType_txTimerReset(TimerHandle_t xTimer,
TickType_t xTicksToWait)
参数 | 描述 |
---|
xTimer | 要复位的软件定时器的句柄。 |
xTicksToWait | 设置阻塞时间,调用函数xTimerReset()开启软件定时器其实就是向定时器命令队列发送一条tmrCOMMAND_RESET命令,既然是向队列发送消息,那 |
肯定会涉及到入队阻塞时间的设置。 | |
返回值 | pdPASS:软件定时器复位成功。pdFAIL:软件定时器复位失败。 |
- ②、函数xTimerResetFromISR()
此函数是xTimerReset()的中断版本,此函数用于中断服务函数中!此函数是一个宏,真正执行的是函数xTimerGenericCommand(),函数原型如下:
BaseType_txTimerResetFromISR(TimerHandle_t xTimer,
BaseType_t* pxHigherPriorityTaskWoken);
参数 | 描述 |
---|
xTimer | 要复位的软件定时器的句柄。 |
pxHigherPriorityTaskWoken | 记录退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。 |
返回值 | pdPASS:软件定时器复位成功。pdFAIL:软件定时器复位失败。 |
2、创建软件定时器
使用软件定时器之前要先创建软件定时器,软件定时器创建函数如下表所示:
函数 | 描述 |
---|
XTimerCreate() | 使用动态方法创建软件定时器。 |
xTimerCreateStatic() | 使用静态方法创建软件定时器。 |
此函数用于创建一个软件定时器,所需要的内存通过动态内存管理方法分配。新创建的软件定时器处于休眠状态,也就是未运行的。函数xTimerStart()、xTimerReset()、xTimerStartFromISR() 、xTimerResetFromISR() 、 xTimerChangePeriod()和
xTimerChangePeriodFromISR()可以使新创建的定时器进入活动状态,此函数的原型如下:
TimerHandle_t xTimerCreate(
const char*const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload,
void* pvTimerID,
TimerCallbackFunction_t pxCallbackFunction)
参数 | 描述 |
---|
peTimerName | 软件定时器名字,名字是一串字符串,用于调试使用。 |
xTimerPeriodInTicks | 软件定时器的定时器周期,单位是时钟节拍数。可以借助portTICK_PERIOD_MS将ms单位转换为时钟节拍数。举个例子,定时器的周期为100个时钟节拍的话,那么xTimerPeriodInTicks就为100,当定时器周期为500ms的时候xTimerPeriodInTicks就可以设置=为(500/portTICK_PERIOD_MS)。 |
uxAutoReload | 设置定时器模式,单次定时器还是周期定时器?当此参数为pdTRUE的时候表示创建的是周期定时器。如果为pdFALSE的话表示创建的是单次定时器。 |
pvTimerID | 定时器ID号,一般情况下每个定时器都有一个回调函数,当定时器定时周期到了以后就会执行这个回调函数。但是FreeRTOS也支持多个定时器共用同一个回调函数,在回调函数中根据定时器的ID号来处理不同的定时器。 |
pxCallbackFunction | 定时器回调函数,当定时器定时周期到了以后就会调用这个函数。 |
返回值 | NULL:软件定时器创建失败。其他值:创建成功的软件定时器句柄。 |
- ②、函数xTimerCreateStatic()
此函数用于创建一个软件定时器,所需要的内存需要用户自行分配。新创建的软件定时器处于休眠状态,也就是未运行的。函数xTimerStart()、xTimerReset()、xTimerStartFromISR()、xTimerResetFromISR()、xTimerChangePeriod()和xTimerChangePeriodFromISR()可以使新创建的定时器进入活动状态,此函数的原型如下:
TimerHandle_t xTimerCreateStatic(
const char*const pcTimerName
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload
void* pvTimerID,
TimerCallbackFunction_t pxCallbackFunction,
StaticTimer_t* pxTimerBuffer)
参数 | 描述 |
---|
peTimerName | 软件定时器名字,名字是一串字符串,用于调试使用。 |
xTimerPeriodInTicks | 软件定时器的定时器周期,单位是时钟节拍数。可以借助portTICK_PERIOD_MS将ms单位转换为时钟节拍数。举个例子,定时器的周期为100个时钟节拍的话,那么xTimerPeriodInTicks就为100,当定时器周期为500ms的时候xTimerPeriodInTicks就可以设置=为(500/portTICK_PERIOD_MS)。 |
uxAutoReload | 设置定时器模式,单次定时器还是周期定时器?当此参数为pdTRUE的时候表示创建的是周期定时器。如果为pdFALSE的话表示创建的是单次定时器。 |
pvTimerID | 定时器ID号,一般情况下每个定时器都有一个回调函数,当定时器定时周期到了以后就会执行这个回调函数。但是FreeRTOS也支持多个定时器共用同一个回调函数,在回调函数中根据定时器的ID号来处理不同的定时器。 |
pxCallbackFunction | 定时器回调函数,当定时器定时周期到了以后就会调用这个函数。 |
pxTimerBuffer | 参数指向一个StaticTimer_t类型的变量,用来保存定时器结构体 |
返回值 | NULL:软件定时器创建失败。其他值:创建成功的软件定时器句柄。 |
3、开始软件定时器
如果软件定时器停止运行的话可以使用FreeRTOS提供的两个开启函数来重新启动软件定时器。
函数 | 描述 |
---|
xTimerStart() | 开启软件定时器,用于任务中。 |
xTimerStartFromISR() | 开启软件定时器,用于中断中。 |
- ①、函数xTimerStart()
启动软件定时器,函数xTimerStartFromISR()是这个函数的中断版本,可以用在中断服务函数中。如果软件定时器没有运行的话调用函数xTimerStart()就会计算定时器到期时间,如果软件定时器正在运行的话调用函数xTimerStart()的结果和xTimerReset()一样。此函数是个宏,真正执行的是函数xTimerGenericCommand,函数原型如下:
BaseType_txTimerStart(TimerHandle_t xTimer,
TickType_t xTicksToWait )
参数 | 描述 |
---|
xTimer | 要开启的软件定时器的句柄。 |
xTicksToWait | 设置阻塞时间,调用函数xTimerStart()开启软件定时器其实就是向定时器命令队列发送一条tmrCOMMAND_START命令,既然是向队列发送消息,那肯定会涉及到入队阻塞时间的设置。 |
返回值 | pdPASS:软件定时器开启成功,其实就是命令发送成功。pdFAIL:软件定时器开启失败,命令发送失败。 |
- ②、函数xTimerStartFromISR()
此函数是函数xTimerStart()的中断版本,用在中断服务函数中,此函数是一个宏,真正执行的是函数xTimerGenericCommand(),此函数原型如下:
BaseType_t xTimerStartFromISR(TimerHandle_t xTimer,
BaseType_t*pxHigherPriorityTaskWoken);
参数 | 描述 |
---|
xTimer | 要开启的软件定时器的句柄。 |
pxHigherPriorityTaskWoken | 标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。 |
返回值 | pdPASS:软件定时器开启成功,其实就是命令发送成功。pdFAIL:软件定时器开启失败,命令发送失败。 |
4、停止软件定时器
既然有开启软件定时器的API函数,那么肯定也有停止软件定时器的函数,FreeRTOS也提供了两个用于停止软件定时器的API函数,如下表所示:
函数 | 描述 |
---|
xTimerStop() | 关闭软件定时器,用于任务中。 |
xTimerStopFromISR() | 关闭软件定时器,用于中断中。 |
- ①、函数xTimerStop()
此函数用于停止一个软件定时器,此函数用于任务中,不能用在中断服务函数中!此函数是一个宏,真正调用的是函数xTimerGenericCommand(),函数原型如下:
BaseType_txTimerStop(TimerHandle_t xTimer,
TickType_t xTicksToWait)
参数 | 描述 |
---|
xTimer | 要停止的软件定时器的句柄。 |
xTicksToWait | 设置阻塞时间,调用函数xTimerStop()停止软件定时器其实就是向定时器命令队列发送一条tmrCOMMAND_STOP命令,既然是向队列发送消息,那肯定会涉及到入队阻塞时间的设置。 |
返回值 | pdPASS:软件定时器停止成功,其实就是命令发送成功。pdFAIL:软件定时器停止失败,命令发送失败。 |
- ②、函数xTimerStopFromISR()
此函数是xTimerStop()的中断版本,此函数用于中断服务函数中!此函数是一个宏,真正执行的是函数xTimerGenericCommand(),函数原型如下:
BaseType_txTimerStopFromISR(TimerHandle_t xTimer,
BaseType_t* pxHigherPriorityTaskWoken );
参数 | 描述 |
---|
xTimer | 要停止的软件定时器的句柄。 |
pxHigherPriorityTaskWoken | 标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。 |
返回值 | pdPASS:软件定时器停止成功,其实就是命令发送成功。pdFAIL:软件定时器停止失败,命令发送失败。 |
FreeRTOS软件定时器就讲解到这里啦!!!