学习RT-thread(事件集)
1. RT-thread事件集
1.1 RT-thread事件集概念
事件集也是线程间同步的机制之一,一个事件集可以包含多个事件,利用事件集可以完成一对多,多对 多的线程间同步。下面以坐公交为例说明事件,在公交站等公交时可能有以下几种情况:
1. 小红 坐公交去公园,只有一种公交可以到达目的地,等到此公交即可出发。

2. 小红坐公交去公园,有 3 种公交都可以到达目的地,等到其中任意一辆即可出发。

3. 小红约小明 一起去公园,则小红必须要等到 “同伴小明到达公交站” 与“公交到达公交站”两个条件都 满足后,才能出发去公园。

1.2 事件集工作机制
事件集主要用于线程间的同步,与信号量不同,它的特点是可以实现一对多,多对多的同步。即一个线 程与多个事件的关系可设置为:其中任意一个事件唤醒线程,或几个事件都到达后才唤醒线程进行后续 的处理;同样,事件也可以是多个线程同步多个事件。这种多个事件的集合可以用一个 32 位无符号整型 变量来表示,变量的每一位代表一个事件,线程通过 “逻辑与” 或“逻辑或”将一个或多个事件关联起来, 形成事件组合。事件的 “逻辑或” 也称为是独立型同步,指的是线程与任何事件之一发生同步;事件 “逻辑 与” 也称为是关联型同步,指的是线程与若干事件都发生同步。

事件集特点
1. 事件只与线程相关,事件间相互独立:每个线程可拥有 32 个事件标志,采用一个 32 bit 无符号整 型数进行记录,每一个 bit 代表一个事件;
2. 事件仅用于同步,不提供数据传输功能;
3. 事件无排队性,即多次向线程发送同一事件 (如果线程还未来得及读走),其效果等同于只发送一 次。
2. 事件集相关函数
2.1 创建/删除函数
创建事件集函数:
rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag);

删除事件集函数:
rt_err_t rt_event_detach(rt_event_t event);


2.2 发送事件/接收事件函数
发送事件函数:
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);

接收事件函数:
rt_err_t rt_event_recv(rt_event_t event,rt_uint32_t set,rt_uint8_t option,rt_int32_t timeout,rt_uint32_t* recved);

option的指可取:
/* 选择 逻辑与 或 逻辑或 的方式接收事件 */RT_EVENT_FLAG_ORRT_EVENT_FLAG_AND/* 选择清除重置事件标志位 */RT_EVENT_FLAG_CLEAR
3. 事件集实操
实验要求:
场景:监听到多种事件同时成立就响应
1.创建三个线程和一个事件集
2.线程1,检测按键1事件,然后发送事件
3.线程2,检测按键2事件,然后发送事件
4.线程3,接收按键1和按键2事件都满足之后,翻转灯的的状态
CubeMX配置:
根据原理图

配置成

代码实现:
#include "main.h"
#include "usart.h"
#include "gpio.h"#include <rtthread.h>struct rt_thread thread_handle1;struct rt_thread thread_handle2;struct rt_thread thread_handle3;struct rt_event event;char thread_stack1[256];char thread_stack2[256];char thread_stack3[256];void SystemClock_Config(void);void thread_test1(void *parameter)
{while(1){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11)==GPIO_PIN_RESET){rt_thread_delay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11)==GPIO_PIN_RESET){rt_kprintf("thread1:事件1发送\n");rt_event_send(&event,0x01);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11)==GPIO_PIN_RESET);}rt_thread_delay(20);}
}void thread_test2(void *parameter)
{while(1){if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)==GPIO_PIN_RESET){rt_thread_delay(20);if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)==GPIO_PIN_RESET){rt_kprintf("thread2:事件2发送\n");rt_event_send(&event,0x02);}while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)==GPIO_PIN_RESET);}rt_thread_delay(20);}}void thread_test3(void *parameter)
{rt_uint32_t rev;while(1){rt_event_recv(&event,0x01|0x02,RT_EVENT_FLAG_AND| RT_EVENT_FLAG_CLEAR,RT_WAITING_FOREVER,&rev);if(rev==(0x01|0x02)){rt_kprintf("翻转灯的亮灭状态!\r");HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_12);}}
}int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();rt_event_init(&event,"event1",RT_IPC_FLAG_FIFO);rt_thread_init(&thread_handle1,"thread1",thread_test1,NULL,thread_stack1,256,10, 10);rt_thread_init(&thread_handle2,"thread2",thread_test2,NULL,thread_stack2,256,10, 10);rt_thread_init(&thread_handle3,"thread3",thread_test3,NULL,thread_stack3,256,10, 10);rt_thread_startup(&thread_handle1);rt_thread_startup(&thread_handle2);rt_thread_startup(&thread_handle3);while (1){}
实验现象:
1.打开串口终端观察实验现象(当两事件都发生之后才会翻转状态):

