目录
1.event的基本概念
2.event的特点
1) 事件是依附在任务中的,事件是与任务要关联在一起的,事件组中的任务之间是独立的,每个事件中发生则将该event中的位置1,没发生则将event的位置0,在stm32中有24个标志位可以用于事件的设置;
2)事件仅用于同步任务,不能传输数据;
3)事件无排队性,也就是说,多次向任务中设置同一事件,则等效于只设置1次事件;
4)允许多个任务对同一事件进行读写操作,即设置event标志位,获取event标志位;
5)在等待事件中,如果超时,那么等待的任务也可以激活
3.event的运行机制
发送event时,指定事件的句柄,指定事件的标志位(将该标志位置1),一次可以同时指定多个事件标志位;
xEventGroupSetBits(key_event, EVENTBIT_1);
接受event时,事件所在的任务根据感兴趣的事件来接受单个或多个事件,在xEventGroupWaitBits中还需要指定xClearOnExit,即退出时是否清空标志位,pdTRUE:在函数xEventGroupWaitBits退出前清空标志位,pdFALSE:在函数xEventGroupWaitBits退出前不清空标志位;xWaitForAllBits用于设置事件的逻辑关系,pdTRUE:事件之间是逻辑与关系,pdFALSE:事件之间是逻辑或关系;xTicksToWait设置任务等待事件的时间,注意,如果超过指定的时间片,当前的任务也能判定激活,多以可以根据xEventGroupWaitBits()返回的值来判定是否等待的事件到来的。
xEventGroupWaitBits(key_event,
EVENTBIT_ALL, //等待的event标志位
pdTRUE, //退出xEventGroupWaitBits之前,event标志位是否清 除,若不清除,那么当3个标志位一起到来后,xEventGroupWaitBits持续激活态
pdFALSE, //event事件之间的关系,& 还是 | 的关系,pdTRUE: &, pdFALSE:|
portMAX_DELAY);
任务A对事件1或事件2感兴趣(逻辑或),任务B对事件1和事件2感兴趣(逻辑与),那么任务A当事件1或事件2任意哪个事件到来就会激活任务A,任务B当事件1和事件2同时到来时才激活任务B。
4.event与semphore的区别
事件在一定条件下是可以替代信号量的,当事件只有一个时,可以实现与二值信号量同样的功能,任务与任务,任务与中断之间的同步。
信号量具有计数性,即每来一次信号量semphore都会对当前的信号量值进行累加或累减(在信号量值没满或没空的情况下)
事件是无序的,即不管来多少次事件都作为一次事件的触发。
5.event的应用场景
事件是用于同步任务的,但不能传递数据,所以一般在应用场景中,一般用于一个任务在等待多个事件标志,事件标志之间可以是“逻辑与”,也可以是“逻辑或”,即一个任务要响应多个事件后才能与另外任务同步,否则就是将当前任务挂起等待。
如,一辆巴士车A可承载10人,那么每个人就可以作为一个事件位,司机就是调度器,司机可以根据成员情况决定是否发车,司机可以等待10人全坐满(逻辑与),也可以只有部分人坐满(逻辑或),司机根据需求发车,即发送事件,到达车站后,乘客需要换成到另外一辆巴士B(任务B),巴士B根据情况,可以选择等全车满后(逻辑与)再出发,也可以部分人满(逻辑或)就出发,没等到想要的人就可以延长等待时间。
6.demo分析
实现:任务A发送key的按键event事件,任务B响应按键的event事件。
main.c文件
int main(void)
{
//1. init_hardware
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //初始化delay
uart_init(115200); //初始化uart
LED_Init(); //初始化led
init_key(); //初始化key
//2.初始化thread
APP_task();
return 0;
}
taskA和taskB
void APP_task(void)
{
xTaskCreate((TaskFunction_t)start_task,
(const char *)"start_task",
(uint16_t)START_STACK_SIZE,
NULL,
(UBaseType_t)START_TASK_PRIO,
(TaskHandle_t *)&startTask_handler);
vTaskStartScheduler(); //开启任务调度
}
static void start_task(void *param)
{
EventGroupHandle_t key_event = xEventGroupCreate(); //创建一个事件event
taskENTER_CRITICAL(); //进入临界区
//创建获取event的任务
xTaskCreate((TaskFunction_t )get_event_task,
(const char* )"get_event",
(uint16_t )GET_EVENT_TASK_STACK_SIZE,
(void* )key_event,
(UBaseType_t )GET_EVENT_TASK_PRIO,
(TaskHandle_t* )&get_event_task_handler);
//创建设置event的任务
xTaskCreate((TaskFunction_t )set_event_task,
(const char* )"set_event",
(uint16_t )SET_EVENT_TASK_STACK_SIZE,
(void* )key_event,
(UBaseType_t )SET_EVENT_TASK_PRIO,
(TaskHandle_t* )&set_event_task_handler);
vTaskDelete(startTask_handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
static void set_event_task(void *param)
{
u8 key_value = 0;
//引用key event
EventGroupHandle_t key_event = (EventGroupHandle_t)param;
while(1){
if(key_event != NULL){
key_value = KEY_Scan(0);
switch(key_value){
case KEY0_PRESS:
xEventGroupSetBits(key_event, EVENTBIT_0);
printf("KEY0 press\r\n");
break;
case KEY1_PRESS:
xEventGroupSetBits(key_event, EVENTBIT_1);
printf("KEY1 press\r\n");
break;
case KEY_UP_PRESS:
xEventGroupSetBits(key_event, EVENTBIT_2);
printf("KEY_UP press\r\n");
break;
default:
break;
}
LED0 = ~LED0;
}
delay_xms(10);
}
}
static void get_event_task(void *param)
{
EventBits_t EventValue;
//引用key event
EventGroupHandle_t key_event = (EventGroupHandle_t)param;
while(1){
EventValue = xEventGroupWaitBits(key_event,
EVENTBIT_ALL, //等待的event标志位
pdTRUE, //退出xEventGroupWaitBits之前,event标志位是否清除,若不清除,那么当3个标志位一起到来后,xEventGroupWaitBits持续激活态
pdTRUE, //event事件之间的关系,& 还是 | 的关系,pdTRUE: &, pdFALSE:|
portMAX_DELAY);
printf("eventValue = %d\r\n", EventValue);
printf("--------------------------------------------------------------\r\n");
LED1 = ~LED1;
delay_xms(10);
}
}
taskA轮询按键,有按键按下后,触发按键事件;taskB响应3个按键先后到来的事件,每次等待事件后均清除标志位,以方便下次再次响应。注意,任务的传入参数即为事件event