当前位置: 首页 > article >正文

事件组(本质,车辆协同,改进姿态控制)

事件组本质

事件组的概念

事件组可以简单地认为就是一个整数:
的每一位表示一个事件
每一位事件的含义由程序员决定,比如: Bit0 表示用来串口是否就绪, Bit1
表示按键是否被按下
这些位,值为 1 表示事件发生了,值为 0 表示事件没发生
一个或多个任务、 ISR 都可以去写这些位;一个或多个任务、 ISR 都可以去
读这些位
⚫ 可以等待某一位、某些位中的任意一个,也可以等待多位
高八位用来表示是与关系还是或关系
低八位用来表示是哪个任务的开启
如果有若干个等待事件(A,B任务)那么如果触发写事件,那么先会遍历若干事件(A,B)再进行执行若干事件(A,B)

事件组的操作

事件组和队列、信号量等不太一样,主要集中在 2 个地方:
唤醒谁?
队列、信号量:事件发生时,只会唤醒一个任务
事件组:事件发生时,会唤醒所有符号条件的任务,简单地说它有 " 广播 "
作用
是否清除事件?
队列、信号量:是消耗型的资源,队列的数据被读走就没了;信号量被获取
后就减少了
事件组:被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件
以上图为列,事件组的常规操作如下:
先创建事件组
192
任务 C D 等待事件:
等待什么事件?可以等待某一位、某些位中的任意一个,也可以等待多位。
简单地说就是 " " " " 的关系。
得到事件时,要不要清除?可选择清除、不清除。
任务 A B 产生事件:设置事件组里的某一位、某些位

事件组函数 

创建

函数原型:
EventGroupHandle_t xEventGroupCreate( void );
参数:
  • 无参数:此函数不需要传入任何参数。
返回值:
  • EventGroupHandle_t:返回创建的事件组句柄。如果创建成功,返回一个有效的句柄。如果创建失败(例如,内存不足),则返回 NULL
说明:
  • 事件组是一个位掩码,允许多个任务通过设置或清除特定的位来进行同步。任务可以等待某些特定位被设置,或者可以设置特定的位来通知其他任务。
使用场景:
  • 任务间同步:例如,一个任务可以设置某个事件标志,另一个任务等待该标志。
  • 任务间通信:通过设置和等待不同的事件位来实现不同任务间的状态传递。

删除

函数原型:
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
参数:
  • xEventGroup:事件组的句柄,即通过 xEventGroupCreate() 创建的事件组。
返回值:
  • 无返回值:该函数没有返回值。如果事件组成功删除,内存会被释放;如果没有问题,函数执行后不会有任何反馈。
说明:
  • vEventGroupDelete() 用于显式删除一个事件组。在 FreeRTOS 中,事件组是通过内存分配的,因此需要通过 vEventGroupDelete() 来释放占用的内存。若事件组不再需要,调用该函数进行删除是一个良好的做法。
  • 在调用 vEventGroupDelete() 之前,确保没有任务在使用该事件组。特别是,调用该函数时,不应有任务正在等待该事件组的事件位,否则会导致潜在的同步问题。

设置事件

函数原型:
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
 const EventBits_t uxBitsToSet );
参数:
  • xEventGroup: 事件组的句柄(由 xEventGroupCreate() 返回),指定要操作的事件组。
  • uxBitsToSet: 要设置的事件位。这个参数是一个位掩码,可以指定一个或多个事件位,设置这些事件位时,位上对应的值将变为 1。你可以通过按位或操作来设置多个位。
返回值:
  • 返回当前事件组中的所有位的状态(即事件组中每个位的当前值)。这个返回值是一个 EventBits_t 类型,它包含了事件组中所有位的状态,允许调用者检查其他任务可能已经设置的位。
说明:
  • 设置事件位:通过调用 xEventGroupSetBits(),可以设置指定事件组中的某些位。设置事件位后,其他任务(通过 xEventGroupWaitBits())如果等待这些位,就会被唤醒。
  • 位掩码uxBitsToSet 是一个位掩码,使用按位或操作来设置一个或多个事件位。例如,如果要设置第 0 位和第 2 位,可以将掩码设置为 0x05(即 00000101)。
  • 不会清除位xEventGroupSetBits() 只会设置事件位,它不会清除已经设置的位。如果需要清除事件位,可以使用 xEventGroupClearBits()

等待事件

参数说明:
  • xEventGroup:要操作的事件组句柄。该句柄是通过 xEventGroupCreate() 创建的事件组。

  • uxBitsToWaitFor:指定任务等待的事件位。这是一个位掩码,任务将等待至少这些位被设置。位的设置可以是 0 或 1,可以通过 xEventGroupSetBits() 设置这些位。

  • xClearOnExit:布尔值(pdTRUEpdFALSE)。如果为 pdTRUE,在任务成功退出时,事件组中的相关事件位会被清除。否则,位将保持设置状态,等待其他任务或操作再次使用。

  • xWaitForAllBits:布尔值(pdTRUEpdFALSE)。如果为 pdTRUE,任务会等待 所有 指定的事件位都被设置;如果为 pdFALSE,任务只需要等待其中的任何一个位被设置即可。

  • xTicksToWait:任务等待的时间(以滴答为单位)。如果为 portMAX_DELAY,任务会无限等待直到事件位被设置。如果在给定的时间内事件位未被设置,任务将超时并返回。

返回值:
  • 返回值:成功时,函数返回当前事件组的所有事件位状态。返回值是一个事件位掩码,可以通过与操作 (&) 来检查哪个事件位被设置。
  • 如果在超时之前没有设置期望的事件位,返回值将不包含 uxBitsToWaitFor 中的位。
说明:
  • xEventGroupWaitBits() 是一个阻塞函数,通常用于任务之间的同步。它会挂起当前任务,直到一个或多个指定的事件位被设置,或者直到超时为止。

事件组车辆协同

代码

/*
 * Project: N|Watch
 * Author: Zak Kemble, contact@zakkemble.co.uk
 * Copyright: (C) 2013 by Zak Kemble
 * License: GNU GPL v3 (see License.txt)
 * Web: http://blog.zakkemble.co.uk/diy-digital-wristwatch/
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "cmsis_os.h"
#include "FreeRTOS.h"                   // ARM.FreeRTOS::RTOS:Core
#include "task.h"                       // ARM.FreeRTOS::RTOS:Core
#include "event_groups.h"               // ARM.FreeRTOS::RTOS:Event Groups
#include "semphr.h"                     // ARM.FreeRTOS::RTOS:Core

#include "draw.h"
#include "resources.h"

#include "driver_lcd.h"
#include "driver_ir_receiver.h"
#include "driver_rotary_encoder.h"
#include "driver_mpu6050.h"

#define NOINVERT	false
#define INVERT		true


#define CAR_COUNT	3
#define CAR_WIDTH	12
#define CAR_LENGTH	15
#define ROAD_SPEED	6

static SemaphoreHandle_t g_xSemTicks; 
static uint32_t g_xres, g_yres, g_bpp;
static uint8_t *g_framebuffer;
static EventGroupHandle_t g_xEventCar;

struct car {
	int x;
	int y;
	int control_key;
};

struct car g_cars[3] = {
	{0, 0, IR_KEY_1},
	{0, 17, IR_KEY_2},
	{0, 34, IR_KEY_3},
};

static const byte carImg[] ={
	0x40,0xF8,0xEC,0x2C,0x2C,0x38,0xF0,0x10,0xD0,0x30,0xE8,0x4C,0x4C,0x9C,0xF0,
	0x02,0x1F,0x37,0x34,0x34,0x1C,0x0F,0x08,0x0B,0x0C,0x17,0x32,0x32,0x39,0x0F,
};

static const byte clearImg[30] ={0};

static const byte roadMarking[] ={
	0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
};

#if 0
void car_test(void)
{
	g_framebuffer = LCD_GetFrameBuffer(&g_xres, &g_yres, &g_bpp);
	draw_init();
	draw_end();
	
	draw_bitmap(0, 0, carImg, 15, 16, NOINVERT, 0);
	draw_flushArea(0, 0, 15, 16);
	
	draw_bitmap(0, 16, roadMarking, 8, 1, NOINVERT, 0);
	draw_flushArea(0, 16, 8, 1);

	while (1);
}
#endif

static void ShowCar(struct car *pcar)
{
	draw_bitmap(pcar->x, pcar->y, carImg, 15, 16, NOINVERT, 0);
	draw_flushArea(pcar->x, pcar->y, 15, 16);
}

static void HideCar(struct car *pcar)
{
	draw_bitmap(pcar->x, pcar->y, clearImg, 15, 16, NOINVERT, 0);
	draw_flushArea(pcar->x, pcar->y, 15, 16);
}

static void Car1Task(void *params)
{
	struct car *pcar = params;
	struct ir_data idata;
	
	/* 创建自己的队列 */
	QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));
	
	/* 注册队列 */
	RegisterQueueHandle(xQueueIR);

	/* 显示汽车 */
	ShowCar(pcar);
	
	/* 获得信号量 */
	//xSemaphoreTake(g_xSemTicks, portMAX_DELAY);
	
	while (1)
	{
		/* 读取按键值:读队列 */
		//xQueueReceive(xQueueIR, &idata, portMAX_DELAY);
		
		/* 控制汽车往右移动 */
		//if (idata.val == pcar->control_key)
		{
			if (pcar->x < g_xres - CAR_LENGTH)
			{
				/* 隐藏汽车 */
				HideCar(pcar); 
				
				/* 调整位置 */
				pcar->x += 1;
				if (pcar->x > g_xres - CAR_LENGTH)
				{
					pcar->x = g_xres - CAR_LENGTH;
				}
				
				/* 重新显示汽车 */
				ShowCar(pcar);
				
				vTaskDelay(50);
				
				if (pcar->x == g_xres - CAR_LENGTH)
				{
					/* 释放信号量 */
					//xSemaphoreGive(g_xSemTicks);
					xEventGroupSetBits(g_xEventCar,(1<<0));
					vTaskDelete(NULL);
				}
			}
		}
	}
}

static void Car2Task(void *params)
{
	struct car *pcar = params;
	struct ir_data idata;
	
	vTaskDelay(1000);
	
	/* 创建自己的队列 */
	QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));
	
	/* 注册队列 */
	RegisterQueueHandle(xQueueIR);

	/* 显示汽车 */
	ShowCar(pcar);
	
	/* 获得信号量 */
	//xSemaphoreTake(g_xSemTicks, portMAX_DELAY);
	xEventGroupWaitBits(g_xEventCar,(1<<0),pdTRUE,pdFALSE,portMAX_DELAY);
	while (1)
	{
		/* 读取按键值:读队列 */
		//xQueueReceive(xQueueIR, &idata, portMAX_DELAY);
		
		
		/* 控制汽车往右移动 */
		//if (idata.val == pcar->control_key)
		{
			if (pcar->x < g_xres - CAR_LENGTH)
			{
				/* 隐藏汽车 */
				HideCar(pcar);
				
				/* 调整位置 */
				pcar->x += 1;
				if (pcar->x > g_xres - CAR_LENGTH)
				{
					pcar->x = g_xres - CAR_LENGTH;
				}
				
				/* 重新显示汽车 */
				ShowCar(pcar);
				
				//vTaskDelay(50);
				mdelay(50);
				
				if (pcar->x == g_xres - CAR_LENGTH)
				{
					/* 释放信号量 */
					//xSemaphoreGive(g_xSemTicks);
					//vTaskDelete(NULL);
				}
			}
		}
	}
}


static void Car3Task(void *params)
{
	struct car *pcar = params;
	struct ir_data idata;
	
	
	/* 创建自己的队列 */
	QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));
	
	/* 注册队列 */
	RegisterQueueHandle(xQueueIR);

	/* 显示汽车 */
	ShowCar(pcar);

	vTaskDelay(2000);
	
	/* 获得信号量 */
	//xSemaphoreTake(g_xSemTicks, portMAX_DELAY);
	xEventGroupWaitBits(g_xEventCar,(1<<0),pdTRUE,pdFALSE,portMAX_DELAY);
	while (1)
	{
		/* 读取按键值:读队列 */
		//xQueueReceive(xQueueIR, &idata, portMAX_DELAY);
		
		/* 控制汽车往右移动 */
		//if (idata.val == pcar->control_key)
		{
			if (pcar->x < g_xres - CAR_LENGTH)
			{
				/* 隐藏汽车 */
				HideCar(pcar);
				
				/* 调整位置 */
				pcar->x += 1;
				if (pcar->x > g_xres - CAR_LENGTH)
				{
					pcar->x = g_xres - CAR_LENGTH;
				}
				
				/* 重新显示汽车 */
				ShowCar(pcar);
				
				//vTaskDelay(50);
				mdelay(50);
				
				if (pcar->x == g_xres - CAR_LENGTH)
				{
					/* 释放信号量 */
					//xSemaphoreGive(g_xSemTicks);
					vTaskDelete(NULL);
				}
			}
		}
	}
}


void car_game(void)
{
	int x;
	int i, j;
	g_framebuffer = LCD_GetFrameBuffer(&g_xres, &g_yres, &g_bpp);
	draw_init();
	draw_end();
	
	//g_xSemTicks = xSemaphoreCreateCounting(1, 1);
	//g_xSemTicks = xSemaphoreCreateMutex();
	EventGroupHandle_t xEventGroupCreate();

	/* 画出路标 */
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 8; j++)
		{
			draw_bitmap(16*j, 16+17*i, roadMarking, 8, 1, NOINVERT, 0);
			draw_flushArea(16*j, 16+17*i, 8, 1);
		}
	}
	
	/* 创建3个汽车任务 */
#if 0	
	for (i = 0; i < 3; i++)
	{
		draw_bitmap(g_cars[i].x, g_cars[i].y, carImg, 15, 16, NOINVERT, 0);
		draw_flushArea(g_cars[i].x, g_cars[i].y, 15, 16);
	}
#endif
    xTaskCreate(Car1Task, "car1", 128, &g_cars[0], osPriorityNormal, NULL);
    xTaskCreate(Car2Task, "car2", 128, &g_cars[1], osPriorityNormal+2, NULL);
    xTaskCreate(Car3Task, "car3", 128, &g_cars[2], osPriorityNormal+3, NULL);	
}

事件组改进姿态控制

代码

/**********************************************************************
 * 函数名称: MPU6050_Callback
 * 功能描述: MPU6050中断回调函数,它会写事件组
 * 输入参数: 无
 * 输出参数: 无
 * 返 回 值: 无
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2023/09/07	     V1.0	  韦东山	      创建
 ***********************************************************************/
//void EXTI9_5_IRQHandler()
void MPU6050_Callback(void)
{
	/* 设置事件组: bit0 */
	xEventGroupSetBitsFromISR(g_xEventMPU6050, (1<<0), NULL);
}


http://www.kler.cn/a/388889.html

相关文章:

  • uni-app中使用 unicloud 云开发平台③
  • docker运行ActiveMQ-Artemis
  • 重新认识HTTPS
  • C++ QT 工具日志异步分批保存
  • 数据分析那些事儿——关于A/B实验
  • go语言 分布式一致
  • DICOM标准:DICOM医学影像中的覆盖层(Overlay)概念详解
  • Webpack 深度解析与实战指南
  • Notepad++ 最新官网中文版在线下载 附文本编辑器安装与基础使用教程
  • 区块链应用第1讲:基于区块链的智慧货运平台
  • 【算法】(Python)动态规划
  • 网络安全不知道怎么学,看完这篇,中学生都能学会
  • 【SpringBoot】——Spring Validation之用户注册、JWT令牌之用户登入
  • 群控系统服务端开发模式-应用开发-前端登录页面开发
  • 聚观早报 | 奥迪集团Q3财报;小鹏汽车宣布增程计划
  • AppStore 账号切换
  • 0-基于图的组合优化算法学习(NeurIPS 2017)(未完)
  • 鸿蒙基本组件结构
  • 简单介绍 Spring 中获取 Bean 的三种方式
  • 如何防止苹果MacOS进入休眠状态
  • 【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
  • 报错 - ‘jax.core‘ has no attribute ‘NamedShape‘
  • C语言 | Leetcode C语言题解之第546题移除盒子
  • 利用 Avalonia UI 构建 Blazor 混合应用程序
  • sql分区
  • 计算机体系结构之多级缓存、缓存miss及缓存hit(二)