FreeRTOS学习之路,以STM32F103C8T6为实验MCU(2-7:软件定时器)

学习之路主要为FreeRTOS操作系统在STM32F103(STM32F103C8T6)上的运用,采用的是标准库编程的方式,使用的IDE为KEIL5。

注意!!!本学习之路可以通过购买STM32最小系统板以及部分配件的方式进行学习,也可以通过Proteus仿真的方式进行学习。

后续文章会同时发表在个人博客(jason1016.club)、CSDN;

视频会发布在bilibili(UID:399951374)

一、概念(干啥用的)

不调用硬件定时器资源,用软件模拟定时器,但是只能起到计时作用,也没有定时器外设准

软件定时器允许设置一段时间,当设置的时间到达之后就执行指定的功能函数,被定时器调用的这个功能函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期,简而言之,当定时器的定时周期到了以后就会执行回调函数 。

软件定时器的回调函数是在定时器服务任务中执行的,所以一定不能在回调函数中调用任何会阻塞任务的 API 函数!比如,定时器回调函数中千万不能调用 vTaskDelay()、vTaskDelayUnti(),还有一些访问队列或者信号量的非零阻塞时间的 API 函数也不能调用。

二、原理(他是怎么工作的)

定时器是一个可选的、不属于 FreeRTOS 内核的功能,它是由定时器服务(或 Daemon)任务来提供的。FreeRTOS 提供了很多定时器有关的 API 函数,这些 API 函数大多都使用 FreeRTOS的队列发送命令给定时器服务任务。这个队列叫做定时器命令队列。定时器命令队列是提供给FreeRTOS 的软件定时器使用的,用户不能直接访问!

三、配置

cpp 复制代码
/***************************************************************************************************************/
/*                                FreeRTOS与软件定时器有关的配置选项                                            */
/***************************************************************************************************************/
#define configUSE_TIMERS                        1                               //为1时启用软件定时器
#define configTIMER_TASK_PRIORITY                (configMAX_PRIORITIES-1)        //软件定时器优先级
#define configTIMER_QUEUE_LENGTH                5                               //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH            (configMINIMAL_STACK_SIZE*2)    //软件定时器任务堆栈大小

四、软件定时器的类型

|-------|---------------------------|
| 单次定时器 | 定时器回调函数就执行一次 |
| 周期定时器 | 一旦启动以后就会在执行完回调函数以后自动的重新启动 |

五、软件定时器的操作函数

1、复位软件定时器

有时候我们可能会在定时器正在运行的时候需要复位软件定时器,复位软件定时器的话会重新计算定时周期到达的时间点,这个新的时间点是相对于复位定时器的那个时刻计算的,并不是第一次启动软件定时器的那个时间点。

cpp 复制代码
//任务级复位软件定时器
BaseType_t xTimerReset( TimerHandle_t xTimer,        //xTimer: 要复位的软件定时器的句柄。
                        TickType_t xTicksToWait )    //xTicksToWait: 设置阻塞时间,调用函数 xTimerReset ()开启软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_RESET 命令,既然是向队列发送消息,那肯定会涉及到入队阻塞时间的设置。
/*返回值:
    pdPASS: 软件定时器复位成功,其实就是命令发送成功。
    pdFAIL: 软件定时器复位失败,命令发送失败*/
    
//中断级复位软件定时器
aseType_t xTimerResetFromISR( TimerHandle_t xTimer,                    //xTimer: 要复位的软件定时器的句柄。
                              BaseType_t * pxHigherPriorityTaskWoken );//pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
/*返回值:
    pdPASS: 软件定时器复位成功,其实就是命令发送成功。
    pdFAIL: 软件定时器复位失败,命令发送失败。*/

2、创建软件定时器

cpp 复制代码
//动态方法
TimerHandle_t xTimerCreate( const char * const pcTimerName,             //pcTimerName: 软件定时器名字,名字是一串字符串,用于调试使用。
                            TickType_t xTimerPeriodInTicks,             //xTimerPeriodInTicks : 软件定时器的定时器周期, 单位是时钟节拍数。可以借助portTICK_PERIOD_MS 将 ms 单位转换为时钟节拍数。举个例子,定时器的周期为 100 个时钟节拍的话,那么 xTimerPeriodInTicks 就为100,当定时器周期为 500ms 的时候 xTimerPeriodInTicks 就可以设置为(500/ portTICK_PERIOD_MS)。
                            UBaseType_t uxAutoReload,                   //uxAutoReload: 设置定时器模式,单次定时器还是周期定时器?当此参数为 pdTRUE的时候表示创建的是周期定时器。如果为 pdFALSE 的话表示创建的是单次定时器。
                            void * pvTimerID,                           //pvTimerID: 定时器 ID 号,一般情况下每个定时器都有一个回调函数,当定时器定时周期到了以后就会执行这个回调函数。但是 FreeRTOS 也支持多个定时器共用同一个回调函数,在回调函数中根据定时器的 ID 号来处理不同的定时器。
                            TimerCallbackFunction_t pxCallbackFunction )//pxCallbackFunction: 定时器回调函数,当定时器定时周期到了以后就会调用这个函数。
/*返回值:
    NULL: 软件定时器创建失败。
    其他值: 创建成功的软件定时器句柄。*/

3、开启软件定时器

cpp 复制代码
//任务级开启软件定时器
BaseType_t xTimerStart( TimerHandle_t xTimer,     //xTimer: 要开启的软件定时器的句柄。
                        TickType_t xTicksToWait ) //xTicksToWait: 设置阻塞时间,调用函数 xTimerStart()开启软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_START 命令,既然是向队列发送消息,那肯定会涉及到入队阻塞时间的设置。
/*返回值:
    pdPASS: 软件定时器开启成功,其实就是命令发送成功。
    pdFAIL: 软件定时器开启失败,命令发送失败。*/
    
//中断级开启软件定时器
BaseType_t xTimerStartFromISR( TimerHandle_t xTimer,                    //xTimer: 要开启的软件定时器的句柄。
                               BaseType_t * pxHigherPriorityTaskWoken );//pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
/*返回值:
    pdPASS: 软件定时器开启成功,其实就是命令发送成功。
    pdFAIL: 软件定时器开启失败,命令发送失败。*/

4、停止软件定时器

cpp 复制代码
//任务级停止软件定时器
BaseType_t xTimerStop ( TimerHandle_t xTimer,     //xTimer: 要停止的软件定时器的句柄。
                        TickType_t xTicksToWait ) //xTicksToWait: 设置阻塞时间,调用函数 xTimerStop()停止软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_STOP 命令,既然是向队列发送消息,那肯定会涉及到入队阻塞时间的设置。
/*返回值:
    pdPASS: 软件定时器停止成功,其实就是命令发送成功。
    pdFAIL: 软件定时器停止失败,命令发送失败。*/
    
//中断级停止软件定时器
BaseType_t xTimerStopFromISR( TimerHandle_t xTimer,                    //xTimer: 要停止的软件定时器句柄。
                              BaseType_t * pxHigherPriorityTaskWoken );//pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
/*返回值:
    pdPASS: 软件定时器停止成功,其实就是命令发送成功。
    pdFAIL: 软件定时器停止失败,命令发送失败。*/
相关推荐
chenbingjie_c2 小时前
C++ 进阶核心知识点总结:模板、内存分区、new/delete、内存池
开发语言·c++
福兮说3 小时前
前端下载大文件,点了按钮半天没反应:fetch + blob 的三个问题和三种替代写法
前端·javascript·性能优化·文件下载
GreenTea3 小时前
我把 Agent 的 while 循环拆掉了:一种你可能没想到的 Agent 架构
前端·后端·架构
科技观察哨4 小时前
六足平台选型与纳米定位系统集成:HEB-640六自由度位移台在半导体光刻对准中的参数边界与国产替代评估
前端·人工智能
Escalating_xu4 小时前
【C 语言】深入理解指针(1·下):指针运算、野指针、assert 与传址实战
java·c语言·开发语言
实心儿儿4 小时前
Qt — Qt 事件
开发语言·qt
niucloud-admin4 小时前
JAVA V6 多商户商城 开发文档——web前端
前端
周杰偷奶茶4 小时前
【Java】数据类型与变量
java·开发语言
code斗4 小时前
Java数据结构:堆详解
java·开发语言·数据结构
颜进强4 小时前
16 · NestJS LifecycleEvents 生命周期事件:五个钩子、三条边界,和 rag-server 的优雅停机
前端·后端·ai编程