FreeRTOS入门知识(任务通知(二)以及定时器浅析)(七)
文章目录
- 摘要
- 1.7.3 任务通知-轻量级队列
- 1.7.4 任务通知-事件组
- 1.8、软件定时器使用
- 1.8.1 软件定时器的使用---守护任务执行TImer超时任务
- 1.8.2 定时器任务的一般使用---初步了解
- 1、要使用定时器必须创建它,得到他的句柄
- 2、接下来就是实际创建:
- 3、创建定时器:
- 4、实现回调函数
- 5、启动定时器:
- 1.8.2 定时器防止抖动
摘要
简单分析一下任务通知
针对FreeRTOS的定时器初步认识
1.7.3 任务通知-轻量级队列
常规队列需要确定队列长度
写数据,写满以后可以等待(阻塞)或者返回
读数据,读完以后可以等待(阻塞)或者返回
任务通知使用队列不一样,
TCB里面是一个Value、State
同样发送数据,要么覆盖,要么不覆盖,因为Value只能接受一个值。
1.7.4 任务通知-事件组
而如果是事件组,那么必须满足对应的事件才能唤醒相关任务。
等待的任务并没有指定什么位,因此无论写入什么数据,都会唤醒等待的任务。但是只是唤醒执行,也必须要满足对应的设置条件才能达到我们的想要的结果。
唤醒以后执行不同的分支,只有满足设置条件,才能执行想要的。任务通知不能指定等待什么,只要生产者产生了Bit,那么就会唤醒消费者,所以我们需要在消费者内部设置是否是我们需要的。
而真正的事件组,必须要全部满足才能唤醒。
1.8、软件定时器使用
FreeRTOS的定时器使用还是区别于裸机的定时器使用。
1.8.1 软件定时器的使用—守护任务执行TImer超时任务
本质是一样的通过定时器设置一个固定时间间隔的中断,中断来了就会执行对应的任务(定时器任务超时函数)回调函数,但是需要注意的是不能再中断中执行,不然会影响FreeRTOS的实时性,因此需要一个守护任务来执行这些回调函数。Tick会唤醒守护任务函数,并且需要优先级较高,如果任务优先级较低,那么里面的任务都没有机会执行。
并且在开启配置的时候,必须定义守护任务函数的优先级、以及一个队列、栈空间大小。
其他任务想设置这个Timer任务,只能通过发消息,传输到守护任务,那么就需要队列。
重新在梳理一下,对于定时器函数,我们可能会在某些任务中调用,那么就会周期性的执行一些任务,而这些任务又因为实时性不能再这些定时器函数中执行,那么就只能安排一个位置,那就是内核中的守护任务模块,这个里面就是我们原本定时器函数中需要执行的任务,但是我们又怎么控制这些守护者里面的任务呐,那就是让这些定时器函数发送一些命令给守护者任务,这样守护者任务函数就知道怎么执行内部的任务了。
守护任务是FreeRTOS内核自动创建的系统任务(需配置configUSE_TIMERS=1
),专门负责统一管理所有软件定时器的生命周期和回调执行。所有定时器的回调函数均在守护任务的上下文中执行,而非 在中断或用户任务中 直接运行。这避免了高实时性任务被耗时操作阻塞。
-
命令传递流程:
当用户调用定时器API(如
xTimerStart()
、xTimerReset()
)时,这些函数不会直接操作定时器,而是向定时器命令队列(Timer Command Queue)发送指令(如"启动定时器"命令)。 -
队列管理:
守护任务持续监听此队列,按顺序取出命令并执行对应操作(如启动定时器、修改周期等)。队列长度由
configTIMER_QUEUE_LENGTH
配置,避免溢出。 -
延迟执行:
定时器到期时,守护任务会调用其回调函数,但执行时机受任务调度影响(若守护任务优先级较低,可能被高优先级任务抢占)。
-
实时性保障:
回调函数必须简短且非阻塞(禁止调用
vTaskDelay()
等函数),否则会阻塞守护任务,导致其他定时器无法触发。
而使用队列,就意味着这些定时器函数里面都有一个xTaskWait
,这是因为向队列可能会满,因此肯会需要等待写入,如果你不想等待,那就会返回任务写失败。
定时器状态:
刚创建的时候是一个冬眠状态,然后当我们进行启动、复位、改变周期的时候就会让这个定时器变为运行状态,也就是开始计时,等待超时时间的到来,然后对应的函数任务执行。
1.8.2 定时器任务的一般使用—初步了解
两个目标:
任务1—使用定时器100ms后打印某些信息。
任务2—优先级和守护任务的优先级不一样,看守护任务能否被更高优先级的任务给打断。
1、要使用定时器必须创建它,得到他的句柄
使用动态分配内存的方法创建定时器* pcTimerName:定时器名字, 用处不大, 尽在调试时用到* xTimerPeriodInTicks: 周期, 以 Tick 为单位* uxAutoReload: 类型, pdTRUE 表示自动加载, pdFALSE 表示一次性* pvTimerID: 回调函数可以使用此参数, 比如分辨是哪个定时器* pxCallbackFunction: 回调函数* 返回值: 成功则返回 TimerHandle_t, 否则返回 NULLTimerHandle_t xTimerCreate( const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction );
2、接下来就是实际创建:
声明一个句柄static TimerHandle_t xMyTimerHandle;主要是用来操作这个定时器,或者说用这个Handle来传递一些信息。
3、创建定时器:
xMyTimerHandle = xTimerCreate("mytimer", 100, pdTRUE, NULL, MyTimerCallbackFunction);MyTimerCallbackFunction:这个定时器的回调函数。
4、实现回调函数
在这里实现具体的回调函数,然后把这个函数的首地址给传进去。
void MyTimerCallbackFunction( TimerHandle_t xTimer )
{static int cnt = 0;flagTimer = !flagTimer;printf("MyTimerCallbackFunction_t cnt = %d\r\n", cnt++);
}
5、启动定时器:
任务1中启动定时器,启动定时器任务的本质就是把某些命令通过定时器的命令队列传递给守护者函数。就是通过这个xMyTimerHandle
传递。可以看出我们的回调函数通过xMyTimerHandle
传递给了守护者任务,只不过任务1给了这个定时器一个启动的契机。
void Task1Function(void * param)
{volatile int i = 0;xTimerStart(xMyTimerHandle, 0); /* */while (1){printf("Task1Function ...\r\n");}
}
因为我们把守护者任务设置的优先级最高。所以 可以看出任务1会被我们的守护任务给打断。
如果守护者任务的优先级较低,那么就不会触发了。这样定时器的任务是没有办法抢占任务1的。
1.8.2 定时器防止抖动
例如按键产生多次抖动,或者理解成滤波操作。例如之前分析开源框架按键
基于按键开源MultiButton框架深入理解代码框架(一)(指针的深入理解与应用)-CSDN博客
基于按键开源MultiButton框架深入理解代码框架(二)(指针的深入理解与应用)-CSDN博客
基于按键开源MultiButton框架深入理解代码框架(三)(指针的深入理解与应用)_mutilbutton长按-CSDN博客
具体为什么抖动以及怎么滤波上述已经完整分析,而我们主要是看一下FreeRTOS中的思路是什么样子,体会其中的思想。这种思想可以迁移到AD采样等多种地方。
发生三次中断
其实跟裸机中的思路差不多,都是这个意思,裸机是等待60ms,而在FreeRTOS中是产生三次中断,只有第三次的中断才是最终需要的,相当于是人为的利用定时器产生60ms。这个60ms跟裸机中持续检测电平思路是一样的,先持续进入中断三次,只有最后一次中断才会调用定时器处理函数,单纯的就是产生延迟。
多次抖动就是多次进入中断,那么只要不都抖动,就不会进入这个中断,定时器就不会复位,然后等待一段时间就会产生一个超时任务在任务守护者中执行。
如果觉得我的内容对您有帮助,希望不要吝啬您的赞和关注,您的赞和关注是我更新优质内容的最大动力。
专栏介绍
《嵌入式通信协议解析专栏》
《PID算法专栏》
《C语言指针专栏》
《单片机嵌入式软件相关知识》
《FreeRTOS源码理解专栏》
《嵌入式软件分层架构的设计原理与实践验证》
文章源码获取方式:
如果您对本文的源码感兴趣,欢迎在评论区留下您的邮箱地址。我会在空闲时间整理相关代码,并通过邮件发送给您。由于个人时间有限,发送可能会有一定延迟,请您耐心等待。同时,建议您在评论时注明具体的需求或问题,以便我更好地为您提供针对性的帮助。
【版权声明】
本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议。这意味着您可以自由地共享(复制、分发)和改编(修改、转换)本文内容,但必须遵守以下条件:
署名:您必须注明原作者(即本文博主)的姓名,并提供指向原文的链接。
相同方式共享:如果您基于本文创作了新的内容,必须使用相同的 CC 4.0 BY-SA 协议进行发布。
感谢您的理解与支持!如果您有任何疑问或需要进一步协助,请随时在评论区留言,笔者一定知无不言,言无不尽。