FreeRTOS-事件组

以下内容为个人的初学记录,如有错误,欢迎指正。

概述

事件组用一个整数来表示,每一位表示一个事件,事件未完成(未发生)为0,已完成(发生)为1。任务之间可以通过事件置0/1来实现相互之间的沟通;

前面的队列、信号量、互斥量都能唤醒一个任务,而事件组可以唤醒多个任务。比如有多个任务等待事件bit0的发生,当bit0置1后,多个任务将被唤醒;

事件组的高8位固定由内核使用,总位数由configUSE_16_BIT_TICKS决定:

configUSE_16_BIT_TICKS总位数
116
032

函数

【创建事件组】

/*动态*/
EventGroupHandle_t xEventGroupCreate( void ); 
/*静态*/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer); 

【删除事件组】

void vEventGroupDelete(EventGroupHandle_t xEventGroup);

xEventGroup:事件组句柄

【设置事件】

EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, 
								const EventBits_t usBitsToSet);

/*中断中设置*/
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, 
           				const EventBits_t uxBitsToSet, 
           				BaseType_t * pxHigherPriorityTaskWoken ); 

usBitsToSet:设置哪些位为1。比如0x11就将bit4和bit0设置为1;
pxHigherPriorityTaskWoken:有更高优先级被唤醒时会被设置为pdTRUE,是提示需要进行上下文切换的标志位;

在中断中设置事件组会导致多个任务被唤醒,造成不确定性,因而xEventGroupSetBitsFromISR与其他的FromISR函数有不同之处。1

【等待事件】

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, 
                                 const EventBits_t uxBitsToWaitFor, 
                                 const BaseType_t xClearOnExit, 
                                 const BaseType_t xWaitForAllBits, 
                                 TickType_t xTicksToWait ); 

xClearOnExit:函数退出前是否清除事件

  1. pdTRUE;
  2. pdFALSE;

xWaitForAllBits:是否是等待(所选的)所有位置1才算等待结束

  1. pdTRUE:等待所有,即所选的bit之间是&&(与)的关系
  2. pdFALSE: 不等待所有,即是II(或)的关系

xTicksToWait :阻塞时长;

清除事件也可以用xEventGroupClearBits()函数清除,但是在等待函数和清除函数中间可能会被切换出去,导致事件组被修改,并不是一个原子操作(不会被其他代码路径中断)

【同步点】

有时候事件的进展需要知道其他任务的事件完成情况,因而需要同步:

EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, 
							const EventBits_t uxBitsToSet, 
							const EventBits_t uxBitsToWaitFor, 
							TickType_t xTicksToWait ); 

uxBitsToSet:设置自己的事件;
uxBitsToWaitFor:等待其他任务的事件(直接是&&的关系);

练习

模拟一个项目从开启、准备、测试、完成的流程:

#define START		0x01
#define PREPARE		0x02
#define SOFTWARE	0x04
#define TEST		0x08

创建三个任务——准备、测试、开启与完成,优先级递增。

xTaskCreate(Prepare_Task, "software", 128, NULL, 1, NULL);
Test_Returned = xTaskCreate(Test_Task, "test", 128, NULL, 2, NULL);
Programme_Returned = xTaskCreate(Programme_Task, "programme", 128, NULL, 3, NULL);

优先级最高的Programme_Task发起事件START,并同步等待TEST事件;

void Programme_Task(void* argument){
	printf("start\r\n");
	xEventGroupSync(EventGroup, START, TEST, portMAX_DELAY);
	while(1){
		printf("comlete the programme\r\n");
	}
}

Prepare_Task收到项目启动的通知后开始着手准备

void Prepare_Task(void* argument){
	xEventGroupWaitBits(EventGroup, START, pdTRUE, pdTRUE, portMAX_DELAY);
	for(int i=0; i<5; i++){
		printf("prepare %d\r\n", i);
	}
	xEventGroupSetBits(EventGroup, PREPARE);
}

事件PREPARE完成后,Test_Task退出阻塞,结束等待事件

void Test_Task(void* argument){
	xEventGroupWaitBits(EventGroup, PREPARE, pdTRUE, pdTRUE, portMAX_DELAY);
	for(int i=0; i<5; i++){
		printf("testing...\r\n");
	}
	xEventGroupSetBits(EventGroup, TEST);
	while(1){
	}
}

TEST完成后同步回Programme_Task,Programme_Task退出阻塞,宣布项目完成:
在这里插入图片描述

原来创建四个任务(4*128word),但是发现四个任务似乎内存不够导致Programme_Task创建失败,最后将两个任务改为一个任务(Prepare_Task)。


  1. 值得注意的是,ISR中的函数,比如队列函数xQueueSendToBackFromISR、信号量函数xSemaphoreGiveFromISR,它们会唤醒某个任务,最多只会唤醒1个任务。 但是设置事件组时,有可能导致多个任务被唤醒,这会带来很大的不确定性。所以xEventGroupSetBitsFromISR函数不是直接去设置事件组,而是给一个FreeRTOS后台任务 (daemon task) 发送队列数据,由这个任务来设置事件组。
    如果后台任务的优先级比当前被中断的任务优先级高,xEventGroupSetBitsFromISR会设置*pxHigherPriorityTaskWoken为pdTRUE。
    如果daemon task成功地把队列数据发送给了后台任务,那么
    xEventGroupSetBitsFromISR的返回值就是pdPASS。
    原文:
    《FreeRTOS入门与工程实践-基于STM32F103》教程-基于DShanMCU-103(STM32F103)
    ↩︎

  • 26
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值