FreeRTOS学习笔记:事件组
学习了事件组
任务 A 写入数据后------->仅唤醒一个等待该数据的任务
对于信号量,互斥量也是一样
任务 A 写入数据后give -------->仅唤醒一个等待该数据的任务
而事件组是一种广播机制
一个任务A写入一个数据----------->唤醒多个数据
事件组

唤醒谁?
队列、信号量:事件发生时,只会唤醒一个任务
事件组:事件发生时,会唤醒所有符号条件的任务,简单地说它有"广播"的作用
等待一位,或者多位?
只发生一个 or
都发生 and
是否清除事件?
队列、信号量:是消耗型的资源,队列的数据被读走就没了;
信号量被获取后就减少了事件组:被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件
高八位用来表示 或/与
-
事件触发:
- 任务 A 执行时,通过 FreeRTOS 函数(如
xEventGroupSetBits)将事件组的bit0置为1; - 任务 B 执行时,同理将
bit2置为1。
- 任务 A 执行时,通过 FreeRTOS 函数(如
-
事件等待与唤醒:
- 任务 C:调用
xEventGroupWaitBits,设置等待条件为bit0 | bit2(任意一个满足),一旦bit0或bit2被置1,任务 C 会被唤醒执行; - 任务 D:调用
xEventGroupWaitBits,设置等待条件为bit0 & bit2(需同时满足),只有bit0和bit2都 被置1,任务 D 才会被唤醒。
- 任务 C:调用
事件组的使用:
上图为例
1,使用时先创建事件组
2,任务A/B设置任务组,设置事件组里的某一位、某些位
3,任务C/D进行等待任务组,等待什么事件?可以等待某一位、某些位中的任意一个,也可以等待多位。得到事件时,要不要清除?可选择清除、不清除。
函数:
创建
使用事件组之前,要先创建,得到一个句柄;使用事件组时,要使用句柄来表明使用哪个事件组。
有两种创建方法:动态分配内存、静态分配内存。函数原型如下:
/* 创建一个事件组,返回它的句柄。
* 此函数内部会分配事件组结构体
* 返回值: 返回句柄,非NULL表示成功
*/
EventGroupHandle_t xEventGroupCreate( void );
/* 创建一个事件组,返回它的句柄。
* 此函数无需动态分配内存,所以需要先有一个StaticEventGroup_t结构体,并传入它的指针
* 返回值: 返回句柄,非NULL表示成功
*/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer );
设置
可以设置事件组的某个位、某些位:
在任务中使用xEventGroupSetBits()
1>>0 bit0 置1 1>>7 bit7置
/* 设置事件组中的位
* xEventGroup: 哪个事件组
* uxBitsToSet: 设置哪些位?
* 如果uxBitsToSet的bitX, bitY为1, 那么事件组中的bitX, bitY被设置为1
* 可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0
* 返回值: 返回原来的事件值(没什么意义, 因为很可能已经被其他任务修改了)
*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet );
等待
使用xEventGroupWaitBits来等待事件,可以等待某一位、某些位中的任意一个,也可以等待多位;等到期望的事件后,还可以清除某些位。
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
| 参数 | 说明 |
|---|---|
| xEventGroup | 等待哪个事件组? |
| uxBitsToWaitFor | 等待哪些位?哪些位要被测试? |
| xWaitForAllBits | 怎么测试?是"AND"还是"OR"? pdTRUE: 等待的位,全部为1; pdFALSE: 等待的位,某一个为1即可 |
| xClearOnExit | 函数提出前是否要清除事件? pdTRUE: 清除uxBitsToWaitFor指定的位 pdFALSE: 不清除 |
| xTicksToWait | 如果期待的事件未发生,阻塞多久。 可以设置为0:判断后即刻返回; 可设置为portMAX_DELAY:一定等到成功才返回; 可以设置为期望的Tick Count,一般用*pdMS_TO_TICKS()*把ms转换为Tick Count |
| 返回值 | 返回的是事件值, 如果期待的事件发生了,返回的是"非阻塞条件成立"时的事件值; 如果是超时退出,返回的是超时时刻的事件值。 |
三个小车A B C,进车站
广播 :A先跑 ,B与C等待A跑完然后设置事件组才能动
如果B与C的优先级相同,一起跑,否则,高优先级先运行
OR:A或B到站后,只要一个到站,C再启动
AND:A与B一起到站,C才能启动
改进MPU6050姿态控制

MPU6050是读I2C操作,很耗时,所以放到任务中,通过vTaskDelay函数让任务及时得到我摇晃板子的动作。但是,如果没有摇晃板子,还是一直在While中执行,浪费CPU资源,那么就通过中断改进

如何唤醒任务呢?在中断里设置事件
等待事件,只有得到事件后才会触发读取I2C操作,得不到事件就一直处于阻塞状态

MPU6050

采用PB5作为中断,进行配置


当中断触发时,产生高电平
配置为上升沿触发
中断使能

一:系统中断 通过事件组进行触发
- MPU6050初始化时
动态创建事件组

- 创建一个函数,设置事件组,作用为: 在中断 / 任务上下文里,给事件组 g_xEventMPU6050 的第 0 位(bit0)置

- 等待事件组,在MPU6050任务中等待
只有事件触发时,任务才能调用

- 最后在中断函数中,写入MPU6050_Callback()函数

当 GPIO_PIN_5 触发外部中断(比如接了 MPU6050 的中断输出引脚),就会调用 MPU6050_Callback 做后续处理
二:MPU6050中断设置
资料:
https://blog.csdn.net/sjf8888/article/details/97912391

0XFF全部使能

涉及函数:
动态创建
/* 创建一个事件组,返回它的句柄。
* 此函数内部会分配事件组结构体
* 返回值: 返回句柄,非NULL表示成功
*/
EventGroupHandle_t xEventGroupCreate( void );
设置事件组(中断中使用)
/* 设置事件组中的位
* xEventGroup: 哪个事件组
* uxBitsToSet: 设置哪些位?
* 如果uxBitsToSet的bitX, bitY为1, 那么事件组中的bitX, bitY被设置为1
* 可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0
* pxHigherPriorityTaskWoken: 有没有导致更高优先级的任务进入就绪态? pdTRUE-有, pdFALSE-没有
* 返回值: pdPASS-成功, pdFALSE-失败
*/
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t * pxHigherPriorityTaskWoken );
等待事件组
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
| xEventGroup | 等待哪个事件组? |
| uxBitsToWaitFor | 等待哪些位?哪些位要被测试? |
| xWaitForAllBits | 怎么测试?是"AND"还是"OR"? pdTRUE: 等待的位,全部为1; pdFALSE: 等待的位,某一个为1即可 |
| xClearOnExit | 函数提出前是否要清除事件? pdTRUE: 清除uxBitsToWaitFor指定的位 pdFALSE: 不清除 |
| xTicksToWait | 如果期待的事件未发生,阻塞多久。 可以设置为0:判断后即刻返回; 可设置为portMAX_DELAY:一定等到成功才返回; 可以设置为期望的Tick Count,一般用*pdMS_TO_TICKS()*把ms转换为Tick Count |
| 返回值 | 返回的是事件值, 如果期待的事件发生了,返回的是"非阻塞条件成立"时的事件值; 如果是超时退出,返回的是超时时刻的事件值。 |
更多推荐



所有评论(0)