本节我们来讲讲freeRTOS的事件标志组。它也是一种用于任务间通信和同步的机制,和信号量有一些相似的功能,但也有自己的特点。
一个事件标志组有多个事件位,每个事件位表示了一个事件的标志。
比如我们用事件标志组的bit0表示事件A、bit1表示事件B、bit2表示事件C,那么这个事件标志组至少可以表示3个事件是否发生。
之前我们讲过信号量,它用作信号同步时,只能表示一个资源的有无;而事件标志组,它可以同时表示多个资源的有无。
上述的例子,相当于这个事件标志组实现了等效于3个二值信号量的功能,任务可以在一个事件标志组上同时等待A、B、C三个事件。
任务在等待事件标志组的事件时,可以选等待该组中的一个或某几个事件位。比如上述例子中,虽然事件标志组表示了A、B、C三个事件,但是用户可以设置为只等待A和B。
此外,事件标志组与信号量不同的另一点,是它可以选择在等待到某个事件位时是否对该事件位清零。而使用信号量时,获取到一个信号量时,信号量的计数会自动减1。
freeRTOS提供的事件标志组,由数据类型EventGroupHandle_t定义。使用前需要确认FreeRTOSConfig.h文件中configUSE_16_BIT_TICKS这个宏的定义,如果定义为1,则一个事件标志组可以最多存储8个事件位,如果定义位0,则可以存储24个事件位。
下面讲解一下freeRTOS中操作事件标志组常用的一些函数。
创建事件标志组:
EventGroupHandle_t xEventGroupCreate( void );//创建一个事件标志组,返回的是创建成功的事件标准组句柄
这个函数实际上是动态创建的事件标志组,如果想使用静态创建,需要用xEventGroupCreateStatic()函数。
设置事件位:
最主要是xEventGroupSetBits()、xEventGroupClearBits()两个函数,作用是把事件位置1或清0。函数原型为:
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear); //清0事件标志组,xEventGroup为要操作的事件标准组句柄,uxBitsToClear为要清的事件位,可以同时清多个位
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); //设置事件标志组指定位为1,xEventGroup为要操作的事件标准组句柄,uxBitsToClear为要置1的事件位
上述两个函数只能用在任务中,如果要在中断中设置事件标志组,要使用后缀为ISR的一套函数:xEventGroupSetBitsFromISR()和xEventGroupClearBitsFromISR()。
等待事件位:
EventBits_t xEventGroupWaitBits(
EventGroupHandle_t xEventGroup, /*要等待的事件标志组*/
const EventBits_t uxBitsToWaitFor, /*要等待的事件位*/
const BaseType_t xClearOnExit, /*所等待的事件位是否清零,pdTRUE为清零,pdFALSE不变*/
const BaseType_t xWaitForAllBits, /*是否等待所有位,pdTRUE为等待uxBitsToWaitFor指定的所有位,pfFALSE只要uxBitsToWaitFor指定的其中一位置1就返回 */
const TickType_t xTicksToWait ); /*等待超时时间*/
获取事件标志组的值:
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );//获取事件标准组的值(不会改变它的值)
在中断中需要使用xEventGroupGetBitsFromISR这个函数。
下面我们以一个例子来演示事件标志组的使用。
和前几期的例子一样,我们还是使用cubemx建立三个任务,优先级各不相同。
生成keil工程:
编写代码如下,首先是事件标志组的创建:
我们先编写在最低优先级的任务DefaultTask中发送事件,第1s发送事件位bit0,第2s发生事件位bit1,如此循环:
在中等优先级任务Task02中,等待事件位bit0和bit1,都等到后,清零,并发送事件位bit3:
在高优先级任务Task03中,等待事件位bit3,等到后不清零:
这个程序运行结果如下图:
初始时,优先级较高的两个任务都在等待事件,只有最低优先级任务DefaultTask可以运行;
第1s时DefaultTask发送了事件bit0,第2s时DefaultTask发送了事件bit1;
由于Task02设置的是同时等待bit0和bit1,所以,到DefaultTask发完bit1时,Task02才等到了它需要的所有事件位,等到之后事件位清0;
然后,Task02发送了事件位bit3;
Task03等待到bit3后,由于设置的是不清零,该bit3事件位它是一直有效的;所以Task03之后循环运行到等待事件位bit3时不会再被阻塞,而是立即返回执行。会不停地打印输出Task03 has waited event bit3。
好了,本节的内容就到这里了。
如果觉得有用可以关注作者微信号“小白白学电子”,在公众号可以找到代码和资料下载地址: