学习之路主要为FreeRTOS操作系统在STM32F103(STM32F103C8T6)上的运用,采用的是标准库编程的方式,使用的IDE为KEIL5。
注意!!!本学习之路可以通过购买STM32最小系统板以及部分配件的方式进行学习,也可以通过Proteus仿真的方式进行学习。
后续文章会同时发表在个人博客(jason1016.club)、CSDN;
视频会发布在bilibili(UID:399951374)
一、概念
前面我们学习了使用信号量来完成同步,但是使用信号量来同步的话任务只能与单个的事件或任务进行同步。有时候某个任务可能会需要与多个事件或任务进行同步,此时信号量就无能为力了。FreeRTOS 为此提供了一个可选的解决方法,那就是事件标志组(实现某个任务与多个事件和任务的同步)。
1、事件位(事件标志)【数组元素】
事件位用来表明某个事件是否发生,事件位通常用作事件标志,比如下面的几个例子:
● 当收到一条消息并且把这条消息处理掉以后就可以将某个位(标志)置 1,当队列中没有消息需要处理的时候就可以将这个位(标志)置 0。
● 当把队列中的消息通过网络发送输出以后就可以将某个位(标志)置 1,当没有数据需要从网络发送出去的话就将这个位(标志)置 0。
● 现在需要向网络中发送一个心跳信息,将某个位(标志)置 1。现在不需要向网络中发送心跳信息,这个位(标志)置
2、事件组【数组】
一个事件组就是一组的事件位,事件组中的事件位通过位编号来访问,同样,以上面列出的三个例子为例:
● 事件标志组的 bit1 表示是否有消息需要从网络中发送出去。
● 事件标志组的 bit2 表示现在是否需要向网络发送心跳信息。
二、事件标志组设置
1、创建事件标志组
//动态方案
EventGroupHandle_t xEventGroupCreate( void )
/*返回值:
NULL: 事件标志组创建失败。
其他值: 创建成功的事件标志组句柄。*/
2、设置事件位
//任务级指定事件位清零
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, //xEventGroup: 要操作的事件标志组的句柄。
const EventBits_t uxBitsToClear ); //uxBitsToClear: 要清零的事件位,比如要清除 bit3 的话就设置为 0X08。可以同时清除多个bit,如设置为 0X09 的话就是同时清除 bit3 和 bit0。
/*返回值:
任何值: 将指定事件位清零之前的事件组值。*/
//中断级指定事件位清零
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, //xEventGroup: 要操作的事件标志组的句柄。
const EventBits_t uxBitsToSet );//uxBitsToClear: 要清零的事件位,比如要清除 bit3 的话就设置为 0X08。可以同时清除多个bit,如设置为 0X09 的话就是同时清除 bit3 和 bit0。
/*返回值:
pdPASS: 事件位清零成功。
pdFALSE: 事件位清零失败。*/
//任务级指定事件位置1
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, //xEventGroup: 要操作的事件标志组的句柄。
const EventBits_t uxBitsToSet ); //uxBitsToClear: 指定要置 1 的事件位,比如要将 bit3 值 1 的话就设置为 0X08。可以同时将多个 bit 置 1,如设置为 0X09 的话就是同时将 bit3 和 bit0 置 1。
/*返回值:
任何值: 在将指定事件位置 1 后的事件组值。*/
//中断级指定事件位置1
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, //xEventGroup: 要操作的事件标志组的句柄。
const EventBits_t uxBitsToSet, //uxBitsToClear: 指定要置 1 的事件位,比如要将 bit3 值 1 的话就设置为 0X08。可以同时将多个 bit 置 1,如设置为 0X09 的话就是同时将 bit3 和 bit0 置 1。
BaseType_t * pxHigherPriorityTaskWoken ); //pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
/*返回值:
pdPASS: 事件位置 1 成功。
pdFALSE: 事件位置 1 失败。*/
3、获取事件标志组值
//任务级获取事件标志位
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup ) //xEventGroup: 要获取的事件标志组的句柄。
//返回值:任何值: 当前事件标志组的值。
//中断级别
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) //xEventGroup: 要获取的事件标志组的句柄。
//返回值:任何值: 当前事件标志组的值。
4、等待指定的事件位
某个任务可能需要与多个事件进行同步,那么这个任务就需要等待并判断多个事件位(标志),使用函数 xEventGroupWaitBits()可以完成这个功能。调用函数以后如果任务要等待的事件位还没有准备好(置 1 或清零)的话任务就会进入阻塞态,直到阻塞时间到达或者所等待的事件位准备好。
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, //xEventGroup: 指定要等待的事件标志组。
const EventBits_t uxBitsToWaitFor, //uxBitsToWaitFord:指定要等待的事件位,比如要等待bit0和(或)bit2的时候此参数就是0X05,如果要等待 bit0 和(或)bit1 和(或)bit2 的时候此参数就是 0X07,以此类推。
const BaseType_t xClearOnExit, //xClearOnExit: 此参数要是为 pdTRUE 的话,那么在退出此函数之前由参数 uxBitsToWaitFor所设置的这些事件位就会清零。如果设置位 pdFALSE 的话这些事件位就不会改变。
const BaseType_t xWaitForAllBits, //xWaitForAllBits: 此参数如果设置为 pdTRUE 的话,当 uxBitsToWaitFor 所设置的这些事件位都置 1,或者指定的阻塞时间到的时候函数 xEventGroupWaitBits()才会返回。当此函数为 pdFALSE 的话,只要 uxBitsToWaitFor 所设置的这些事件位其中的任意一个置 1 ,或者指定的阻塞时间到的话函数xEventGroupWaitBits()就会返回。
const TickType_t xTicksToWait ); //xTicksToWait: 设置阻塞时间,单位为节拍数。
//返回值:任何值: 返回当所等待的事件位置 1 以后的事件标志组的值,或者阻塞时间到。根据这个值我们就知道哪些事件位置 1 了。如果函数因为阻塞时间到而返回的话那么这个返回值就不代表任何的含义。