一个事件标志组有多个事件位,每个事件位表示了一个事件的标志。 比如我们用事件标志组的bit0表示事件A、bit1表示事件B、bit2表示事件C,那么这个事件标志组至少可以表示3个事件是否发生。 相比于信号量,它用作信号同步时,只能表示一个资源的有无;而事件标志组,它可以同时表示多个资源的有无。
上述的例子,相当于这个事件标志组实现了等效于3个二值信号量的功能,任务可以在一个事件标志组上同时等待A、B、C三个事件。 任务在等待事件标志组的事件时,可以选等待该组中的一个或某几个事件位。比如上述例子中,虽然事件标志组表示了A、B、C三个事件,但是用户可以设置为只等待A和B。
此外,事件标志组与信号量不同的另一点,是它可以选择在等待到某个事件位时是否对该事件位清零。而使用信号量时,获取到一个信号量时,信号量的计数会自动减1。
创建KEYTask
和 GetEventTask
两个任务。前者负责检测按键,用于设置事件标志位;后者负责等待接收事件。
配置两个按键任务,FreeRTOS v1版本无法自动生成事件组,这里需手动生成。
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
//创建事件标志
#define Event_Key0 (0x01<<0)
#define Event_Key1 (0x01<<1)
#define Event_KeyUp (0x01<<2)
/* USER CODE END PD */
//..............
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
EventGroupHandle_t Event_Key_Handle = NULL; //事件组句柄
/* USER CODE END Variables */
//..............
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
Event_Key_Handle = xEventGroupCreate();//创建事件组
/* USER CODE END Init */
//..............
}
对两个任务进行编写
void StartKeyTask(void const * argument)
{
/* USER CODE BEGIN StartKeyTask */
/* Infinite loop */
for(;;)
{
osDelay(20);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == 0){
xEventGroupSetBits(Event_Key_Handle, Event_Key0);
}
else if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0){
xEventGroupSetBits(Event_Key_Handle, Event_Key1);
}
else if(HAL_GPIO_ReadPin(KEY_UP_GPIO_Port, KEY_UP_Pin) == 1){
xEventGroupSetBits(Event_Key_Handle, Event_KeyUp);
}
}
/* USER CODE END StartKeyTask */
}
/* USER CODE BEGIN Header_StartGetEventTask */
/**
* @brief Function implementing the GetEventTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartGetEventTask */
void StartGetEventTask(void const * argument)
{
/* USER CODE BEGIN StartGetEventTask */
EventBits_t myEventBits_1;
/* Infinite loop */
for(;;)
{
myEventBits_1 = xEventGroupWaitBits(Event_Key_Handle, Event_Key0|Event_Key1|Event_KeyUp, pdTRUE, pdFALSE, portMAX_DELAY);
if(myEventBits_1 == Event_Key0){
HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
}
else if(myEventBits_1 == Event_Key1){
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
}
else if(myEventBits_1 == Event_KeyUp){
HAL_GPIO_WritePin(GPIOD, LED0_Pin|LED1_Pin, GPIO_PIN_SET);
}
osDelay(1);
}
/* USER CODE END StartGetEventTask */
}
EventGroupHandle_t xEventGroupCreate( void );
/*
创建一个事件组,返回它的句柄。
* 此函数无需动态分配内存,所以需要先有一个StaticEventGroup_t结构体,并传入它的指针
* 返回值: 返回句柄,非NULL表示成功
*/
/*
* xEventGroup: 事件组句柄,你要删除哪个事件组
*/
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
/* 设置事件组中的位
* xEventGroup: 哪个事件组
* uxBitsToSet: 设置哪些位?
* 如果uxBitsToSet的bitX, bitY为1, 那么事件组中的bitX, bitY被设置为1
* 可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0
* 返回值: 返回原来的事件值(没什么意义, 因为很可能已经被其他任务修改了)
*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet );
先引入一个概念:unblock condition。一个任务在等待事件发生时,它处于阻塞状态;当期望的时间发生时,这个状态就叫"unblock condition",非阻塞条件,或称为"非阻塞条件成立";当"非阻塞条件成立"后,该任务就可以变为就绪态。
使用xEventGroupWaitBits来等待事件,可以等待某一位、某些位中的任意一个,也可以等待多位;等到期望的事件后,还可以清除某些位。
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
【FreeRtos学习笔记】STM32 CubeMx——EventGroup(事件组)
韦东山freeRTOS系列教程之【第八章】事件组(event group)
STM32CubeMX之freeRTOS事件组
STM32CubeIDE+FreeRTOS事件实验