一、简介
事件标志位:用一个位,来表示事件是否发生
事件标志组:一组事件标志位的集合,可以简单的理解时间标志组,就是一个整体。
事件标志租的特点:
它的每一个位表示一个时间(高8位不算);
每一个事件的含义,由用户自己决定,如:bit0表示按键是否按下,bit1表示是否接收到消息...(这些位的值为1:表示事件发生了;值为0,表示事件未发生)
任意任务或中断都可以读写这些位;
可以等待某一位成立,或者等待多位同时成立;
虽然使用了 32 位无符号的数据类型变量来存储事件标志, 但其中的高8位用作存储事件标志组的控制信息,低24位用作存储事件标志 ,所以说一个事件组最多可以存储 24 个事件标志!
事件标志组、队列和信号量的区别?
二、相关API函数
三、实验
代码:
main.c
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "freertos_demo.h"
#include "Delay.h"
#include "sys.h"
#include "usart.h"
#include "LED.h"
#include "Key.h"int main(void){ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4 uart_init(115200); delay_init();Key_Init();LED_Init();// 创建任务FrrrRTOS_Demo();}
freertos_demo.c
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include "LED.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"/******************************************************************任务配置****************************************************/
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_TASK_STACK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);//任务优先级
#define TASK1_PRIO 2
//任务堆栈大小
#define TASK1_STACK_SIZE 128
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);//任务优先级
#define TASK2_PRIO 3
//任务堆栈大小
#define TASK2_STACK_SIZE 128
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);#define EVENTBIT0 (1<<0)
#define EVENTBIT1 (1<<1)/******************************************************************任务函数****************************************************/
EventGroupHandle_t eventgroud_handle;void FrrrRTOS_Demo(void)
{//创建开始任务xTaskCreate((TaskFunction_t )start_task, //任务函数( char* )"start_task", //任务名称(uint16_t )START_TASK_STACK_SIZE, //任务堆栈大小(void* )NULL, //传递给任务函数的参数(UBaseType_t )START_TASK_PRIO, //任务优先级(TaskHandle_t* )&StartTask_Handler); //任务句柄 // 启动任务调度vTaskStartScheduler();}void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //进入临界区/*创建事件标志组*/eventgroud_handle = xEventGroupCreate();if(eventgroud_handle != NULL){printf("\r\n事件标志组创建成功\r\n");}//创建1任务xTaskCreate((TaskFunction_t )task1, (const char* )"task1", (uint16_t )TASK1_STACK_SIZE, (void* )NULL, (UBaseType_t )TASK1_PRIO, (TaskHandle_t* )&Task1_Handler); //创建2任务xTaskCreate((TaskFunction_t )task2, (const char* )"task2", (uint16_t )TASK2_STACK_SIZE, (void* )NULL,(UBaseType_t )TASK2_PRIO,(TaskHandle_t* )&Task2_Handler); vTaskDelete(NULL); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}//1 实现队列写入和信号量释放函数
void task1(void *pvParameters)
{uint8_t key = 0;
// EventBits_t eventbit;while(1){key = Key_GetNum();if(key == 2){xEventGroupSetBits( eventgroud_handle,EVENTBIT0); //将事件标志组bit0位置1}else if(key == 3){xEventGroupSetBits( eventgroud_handle,EVENTBIT1); //将事件标志组bit0位置1}vTaskDelay(10);}
}// 任务2 获取队列集消息函数
void task2(void *pvParameters)
{EventBits_t event_bit = 0;// 任务主循环while (1){event_bit = xEventGroupWaitBits(eventgroud_handle, //事件标志组句柄EVENTBIT0|EVENTBIT1, //等待事件标志组的bit0和bit1pdTRUE, //成功等待到事件标志位后,清除事件标志组中的bit位pdTRUE, //等待时间标志组bit0和bit1位都置1,都成立 portMAX_DELAY); //死等 printf("等待到的事件标志位值为:%d\r\n",event_bit);}
}
key.c
#include "stm32f10x.h" // Device header
#include "FreeRTOS.h"
#include "task.h"
#include "usart.h"
#include "Delay.h"/*** 函 数:按键初始化* 参 数:无* 返 回 值:无* 按键:PB4/PB12/PB14*/
void Key_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟/*GPIO初始化*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_12 | GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);
}/*** 函 数:按键获取键码* 参 数:无* 返 回 值:按下按键的键码值,范围:0~3,返回0代表没有按键按下* 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手*/
uint8_t Key_GetNum(void)
{uint8_t KeyNum = 0; //定义变量,默认键码值为0if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0) //读PB4输入寄存器的状态,如果为0,则代表按键1按下{KeyNum= GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4);delay_xms(20); //延时消抖while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0); //等待按键松手delay_xms(20); //延时消抖KeyNum = 1; //置键码为1}if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0) {KeyNum= GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);delay_xms(20); while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0); delay_xms(20); KeyNum = 2; }if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0) {KeyNum= GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14);delay_xms(20); while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0); delay_xms(20); KeyNum = 3; }return KeyNum; //返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}
四、实验解析
只有两个按键同时按下时,才会打印;
五、重点
动态方式创建事件标志组API函数:
EventGroupHandle_t xEventGroupCreate ( void ) ;
清除事件标志位API函数:
EventBits_t ( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
设置事件标志位API函数:
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
等待事件标志位API函数:
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait );
同步函数:
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait) ;