FreeRTOS软件定时器解析与应用
FreeRTOS软件定时器解析与应用
1.软件定时器基础知识
1)软件定时器概述
前面介绍STM32芯片上的硬件定时器,FreeRTOS还可以提供软件定时器,软件定时器用于计划在未来的某个固定时间执行某个功能,或者以固定的频率定期执行。软件定时器执行函数是软件定时器的回调函数。
软件定时器由FreeRTOS内核实现,并受其控制。它们不需要硬件支持,并且与硬件定时器或硬件计数器无关。请注意,软件定时器的回调函数是在定时器服务任务中执行的,所以一定不能在回调函数中调用任何会阻塞任务的API函数。例如,千万不能在定时器回调函数中调用vTaskDelay()和vTaskDelayUnti()函数,还有一些访问队列或信号量的非零阻塞时间的API函数也不能调用。
FreeRTOS中的软件定时器可以支持单次定时和周期定时。单次定时是指定时一定的时长后执行一次回调函数,然后就停止不再执行。周期定时是指周期性地执行回调函数。
2)软件定时器配置
软件定时器功能是可选的。软件定时器的相关程序代码在“timers.c”文件中定义。要使用软件定时器功能,应在“FreeRTOSConfig.h”文件中配置定时器,配置如下。

2.软件定时器函数分析
软件定时器有创建、复位、开启、停止等函数。因为实际中应用更多的是硬件定时器,它的精度高,消耗CPU资源少,所以本小节只分析软件定时器函数的输入参数和返回值,不具体分析代码。
1)软件定时器创建函数
(1)动态创建定时器函数xTimerCreate()。
动态创建定时器函数xTimerCreate()的定义如下。

输入参数如下。
•pcTimerName:定时器名。
•xTimerPeriodInTicks:定时器定时周期。
•uxAutoReload:是否设置为周期定时器,pdTRUE为周期定时器,pdFALSE为单次定时器。
•pvTimerID:设置定时器ID,不同ID定时器可能会有相同的定时器名,所以设置不同ID加以区分。
•pxCallbackFunction:定时器回调函数,该函数需要用户自定义。
返回参数如下。
•TimerHandle_t:定时器句柄。
(2)静态创建定时器函数xTimerCreateStatic()。
静态创建定时器函数xTimerCreateStatic()所需要的内存需要用户自行分配,其使用方法和动态创建定时器函数一样,此处不再分析。
2)复位定时器函数
(1)任务级复位定时器函数xTimerReset()。
任务级复位定时器函数xTimerReset()用于复位一个软件定时器,此函数只能用在任务中,不能用于中断服务函数。此函数是一个宏,真正执行的是函数xTimerGenericCommand(),函数原型如下。

输入参数如下。
•xTimer:要复位的软件定时器的句柄。
•xTicksToWait:设置阻塞时间。
返回参数如下。
•pdPASS:软件定时器复位成功,即命令发送成功。
•pdFAIL:软件定时器复位失败,即命令发送失败。
(2)中断级定时器复位函数xTimerResetFromISR()。
中断级定时器复位函数xTimerResetFromISR()用于中断服务函数。此函数是一个宏,真正执行的是函数xTimerGenericCommand(),函数原型如下。

输入参数如下。
•xTimer:要复位的软件定时器的句柄。
•pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任务切换,pdTRUE表示退出执行一次任务切换。
返回参数如下。
•pdPASS:软件定时器复位成功,即命令发送成功。
•pdFAIL:软件定时器复位失败,即命令发送失败。
3)开启软件定时器
FreeRTOS提供两个函数来重新启动软件定时器:一个是任务级开启软件定时器函数xTimerS tart(),另一个是中断级开启软件定时器函数xTimerStartFromISR()。
(1)任务级开启软件定时器函数xTimerStart()。
任务级开启软件定时器函数xTimerStart()是一个宏,真正执行的是函数xTimerGenericCommand(),定义如下。

输入参数如下。
•xTimer:要复位的软件定时器的句柄。
•xTicksToWai t:设置阻塞时间。
返回参数如下。
•pdPASS:软件定时器开启成功,即命令发送成功。(https://www.daowen.com)
•pdFAIL:软件定时器开启失败,即命令发送失败。
(2)中断级开启软件定时器函数xTimerStartFromISR()。
中断级开启软件定时器函数xTimerStartFromISR()的宏定义如下。

输入参数如下。
•xTimer:要复位的软件定时器的句柄。
•pxHigherPriori tyTaskWoken:标记退出此函数以后是否进行任务切换,pdTRUE表示退出执行一次任务切换。
返回参数如下。
•pdPASS:软件定时器开启成功,即命令发送成功。
•pdFAIL:软件定时器开启失败,即命令发送失败。
4)停止软件定时器
FreeRTOS也提供了两个用于停止软件定时器的函数:一个是任务级停止软件定时器函数xTimerStop(),另一个是中断级停止软件定时器函数xTimerStopFromISR()。
(1)任务级停止软件定时器函数xTimerStop()。
任务级停止软件定时器函数xTimerStop()是一个宏,真正调用的是函数xTimerGenericCommand(),函数原型如下。

输入参数如下。
•xTimer:要复位的软件定时器的句柄。
•xTicksToWai t:设置阻塞时间。
返回参数如下。
•pdPASS:软件定时器停止成功,即命令发送成功。
•pdFAIL:软件定时器停止失败,即命令发送失败。
(2)中断级停止软件定时器函数xTimerStopFromISR()。
中断级停止软件定时器函数xTimerStopFromISR()的宏定义如下。

输入参数如下。
•xTimer:要复位的软件定时器的句柄。
•pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任务切换,pdTRUE表示退出执行一次任务切换。
返回参数如下。
•pdPASS:软件定时器停止成功,即命令发送成功。
•pdFAIL:软件定时器停止失败,即命令发送失败。
3.软件定时器应用:闪烁灯设计
1)任务要求
利用STM32F1系列MCU和FreeRTOS设计一个每隔1 s闪烁的灯。要求利用FreeRTOS定时器实现1 s周期定时,通过信号量控制方式进行任务通信,记录秒信号,并将秒信号通过串行通信接口输出到计算机串口调试助手。请进行硬件、软件设计,并进行仿真与调试。
2)硬件设计
硬件电路图如图1所示。PB0和PB1处接外部按键,PB10外接一个LED,应用串口2,通过串口转USB接口送到计算机的串口。

图1 硬件电路图
3)软件设计
创建一个软件定时器,时钟源是FreeRTOS的时钟节拍,本例的时钟节拍为1 ms。设计为周期定时器,定时周期为1 s。定时时长计满后,在回调函数timer_callback()中对LED取反,使其闪烁发光。
创建一个软件定时器开启和关闭的任务,按下按键PB0开启定时器,按下按键PB1停止计时。
创建一个二值信号量,在定时器回调函数timer_callback()中释放信号量。
创建一个计数任务,获取二值信号量。如果获取成功,表示定时器定时1 s时间到,已经释放了信号量。
在STM32CubeMX中创建工程,使能二值信号量,使能软件定时器,生成MDK工程文件,在“main.c”文件中添加如下程序。



4)仿真与调试
程序编译调试好后,可通过Keil-MDK模拟仿真,也可以通过硬件用USB连接计算机串口,按下PB0按键后,在串口输出数据,仿真调试效果如图2所示。

图2 仿真调试效果
(1)Task_TimerControl任务优先级最高,会不停地检测按键是否被按下,若PB0被按下,软件定时器开启,并开始计数。
(2)当1 s计时到,回调函数释放一个信号量。
(3)Task_Count任务获取信号量后,进行计数处理,分别对秒、分、小时进行计数,并向串口打印。若未获得信号量,则Task_Count任务将阻塞,并一直等待,直到下一次时间到。