ARM32开发--FreeRTOS-事件组

系列文章目录

知不足而奋进 望远山而前行


目录

系列文章目录

文章目录

前言

目标

内容

概念

事件标志位

开发流程

功能介绍

创建事件组

触发事件

等待事件触发

同步

清理事件

案例

总结


前言

在嵌入式系统开发中,任务之间的同步和通信是至关重要的。FreeRTOS作为一款开源的实时操作系统,提供了多种机制来实现任务间的有效协调。其中,事件组(Event Group)机制是一种强大的工具,允许任务等待和检测多个事件的状态,并在事件发生时进行及时的通知。通过使用事件组,开发人员可以实现复杂的任务调度和协同工作,提高系统的效率和可靠性。

本文将深入探讨FreeRTOS中事件组的基本概念、功能特性以及具体的使用方法。我们将详细介绍如何创建和管理事件组,以及如何利用事件组进行任务间的同步和通信。通过实际案例和代码示例,读者将能够全面理解如何在实际项目中应用事件组,从而更好地优化和管理嵌入式系统中的任务流程。


目标

  1. 理解什么是事件组
  2. 理解事件组标志位
  3. 掌握事件组开发流程

内容

概念

在FreeRTOS中,事件组(Event Group)是一种用于任务间同步和通信的机制。事件组允许任务等待和检测多个事件的状态,并在事件发生时进行通知。

事件组由一组标志位(或事件位)组成,每个标志位代表一个特定的事件。任务可以等待某些标志位被置位或清除,也可以设置或清除标志位。

以下是事件组的一些关键概念:

  1. 事件组句柄(Event Group Handle):

事件组句柄是用于标识和操作事件组的变量。它可以在创建事件组时由FreeRTOS分配,也可以通过函数返回。

  1. 标志位(Event Bit):

标志位是事件组中的单个位,它表示一个特定的事件。每个标志位可以被置位或清除,以表示事件发生或未发生。

标志位通常用二进制位来表示,如第0位、第1位等。可以使用位操作函数进行置位和清除操作。

  1. 等待事件(Waiting Events):

任务可以通过等待事件组中的一个或多个标志位来暂停执行,直到这些标志位满足特定的条件。

等待事件可以通过函数如xEventGroupWaitBits()、xEventGroupSync()等实现。

  1. 通知事件(Signaling Events):

任务可以通过设置或清除事件组中的标志位来通知其他任务事件的发生。

通知事件可以通过函数如xEventGroupSetBits()、xEventGroupClearBits()等实现。

通过使用事件组,任务可以进行有效的同步和通信,实现复杂的任务调度和协调。任务可以等待多个事件同时发生,也可以通过设置或清除标志位来触发其他任务的执行。

请注意,事件组是FreeRTOS中的一个特性,具体的使用方法和函数可能因不同的FreeRTOS版本而略有差异。建议参考相关的FreeRTOS文档和参考资料以获取更详细和准确的信息。

事件标志位

  1. 事件标志为一个32位的数字。也就是采用uint32_t来记录事件状态。
  2. 32位的状态分为高8位和低24位。
  3. 高8位位系统级事件和状态,由操作系统自行管理,无需开发人员关系。
  4. 低24位表示24种事件,每1个bit位表示一种事件,由开发人员控制这些事件位。
  5. 低24位中,每一位的取值是0或者1,0表示当前位对应的事件没有触发,1表示当前位的事件触发了。

开发流程

  1. 创建事件组
  2. 开启一个任务,用来等待事件触发
  3. 开启一个任务,用来改变事件触发

事件组标志位像一个订阅中心一样,一方可以订阅事件的触发,一方可以改变事件的状态。

功能介绍

功能

描述

xEventGroupCreate

创建事件组

xEventGroupSetBits

将事件状态改为触发

xEventGroupWaitBits

等待事件触发

创建事件组
EventGroupHandle_t xEventGroupCreate();

返回值为事件组的句柄。

触发事件

将事件状态改为触发

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
                                const EventBits_t uxBitsToSet )

参数说明:

  1. EventGroupHandle_t xEventGroup:事件组的句柄。
  2. const EventBits_t uxBitsToSet:事件标志位。

返回值:

当前触发的事件有哪些。

等待事件触发
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
                                 const EventBits_t uxBitsToWaitFor,
                                 const BaseType_t xClearOnExit,
                                 const BaseType_t xWaitForAllBits,
                                 TickType_t xTicksToWait )

参数说明:

  1. EventGroupHandle_t xEventGroup:事件组的句柄。
  2. const EventBits_t uxBitsToWaitFor:等待事件组的哪个标志位。可以是多个标志位。例如:
    1. 一个标志位(索引为1):0x02
    2. 两个标志位(索引为1和3):0x0A(0x08 + 0x02)
  1. const BaseType_t xClearOnExit:等待事件触发后,是否清除这个事件,如果清除,其他的订阅者将不会收到,不清除,就会收到。
    1. pdTRUE表示清除
    2. pdFALSE表示不清除。
  1. const BaseType_t xWaitForAllBits:指定是否等待所有的标志位都被设置。
    1. pdTRUE 表示等待所有标志位都被设置。(都为1)
    2. pdFALSE 表示只要有任何一个标志位被设置就可以继续执行任务。(任意一个为1)
  1. TickType_t xTicksToWait:等待标志位被设置的超时时间,以 FreeRTOS 的 Tick 单位表示。
    1. 可以使用 pdMS_TO_TICKS 宏将毫秒转换为 Tick 值。
    2. 如果设置为 portMAX_DELAY,则表示无限等待,直到标志位被设置。

返回值表示已设置的标志位。

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

参数说明:

  1. EventGroupHandle_t xEventGroup:事件组句柄
  2. const EventBits_t uxBitsToSet:要设置的标志位
  3. const EventBits_t uxBitsToWaitFor:要等待的事件标志位
  4. TickType_t xTicksToWait:等待的超时时间

清理事件

案例

开启三个任务,等待事件发生。通过按键触发事件发生。观察效果。

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"

#include "event_groups.h"
#include "Usart0.h"

#define	EVENT_BIT(N)		(1 << N)
#define EVENT_BIT_0			EVENT_BIT(0)
#define EVENT_BIT_1			EVENT_BIT(1)
#define EVENT_BIT_2			EVENT_BIT(2)
#define EVENT_BIT_3			EVENT_BIT(3)
#define EVENT_BIT_4			EVENT_BIT(4)
#define EVENT_BIT_5			EVENT_BIT(5)
#define EVENT_BIT_6			EVENT_BIT(6)
#define EVENT_BIT_7			EVENT_BIT(7)
#define EVENT_BIT_8			EVENT_BIT(8)
#define EVENT_BIT_9			EVENT_BIT(9)
#define EVENT_BIT_10		EVENT_BIT(10)
#define EVENT_BIT_11		EVENT_BIT(11)
#define EVENT_BIT_12		EVENT_BIT(12)
#define EVENT_BIT_13		EVENT_BIT(13)
#define EVENT_BIT_14		EVENT_BIT(14)
#define EVENT_BIT_15		EVENT_BIT(15)
#define EVENT_BIT_16		EVENT_BIT(16)
#define EVENT_BIT_17		EVENT_BIT(17)
#define EVENT_BIT_18		EVENT_BIT(18)
#define EVENT_BIT_19		EVENT_BIT(19)
#define EVENT_BIT_20		EVENT_BIT(20)
#define EVENT_BIT_21		EVENT_BIT(21)
#define EVENT_BIT_22		EVENT_BIT(22)
#define EVENT_BIT_23		EVENT_BIT(23)


TaskHandle_t            task_handler;
TaskHandle_t            task_key_handler;
TaskHandle_t            task1_handler;
TaskHandle_t            task2_handler;
TaskHandle_t            task3_handler;
EventGroupHandle_t			event_group;


void task1(void *pvParameters) {
    EventBits_t bits;
    while(1) {
        bits = xEventGroupWaitBits(event_group, EVENT_BIT_0, pdTRUE, pdFALSE, portMAX_DELAY);
        printf("task1: %d\r\n", bits);
        vTaskDelay(1000);
    }
    vTaskDelete(NULL);
}

void task2(void *pvParameters) {
    EventBits_t bits;
    while(1) {
        bits = xEventGroupWaitBits(event_group, EVENT_BIT_0, pdTRUE, pdTRUE, portMAX_DELAY);
        printf("task2: %d\r\n", bits);
        vTaskDelay(2000);
    }
    vTaskDelete(NULL);
}

void task3(void *pvParameters) {
    EventBits_t bits = 0;
    while(1) {
        bits = xEventGroupWaitBits(event_group, EVENT_BIT_0, pdTRUE, pdTRUE, portMAX_DELAY);
        printf("task3: %d\r\n", bits);
        vTaskDelay(3000);
    }
    vTaskDelete(NULL);
}

void task_key(void *pvParameters) {
    FlagStatus pre_state = RESET;
    while(1) {
        FlagStatus state = gpio_input_bit_get(GPIOA, GPIO_PIN_0);
        if(SET == state && pre_state == RESET) {
            // 当前高电平, 上一次为低电平,按下
            pre_state = state;

            printf("set bit \r\n");
            xEventGroupSetBits(event_group, EVENT_BIT_0);
        } else if(RESET == state && pre_state == SET) {
            // 当前高电平, 上一次为低电平,抬起
            pre_state = state;
        }
        vTaskDelay(20);
    }
}

void start_task(void *pvParameters) {
    GPIO_config();
    Usart0_init();

    event_group = xEventGroupCreate();
    if(event_group != NULL) {
        printf("group success\r\n");
    }

    taskENTER_CRITICAL();

    xTaskCreate(task_key, "task_key", 64, NULL, 0, &task_key_handler);
    xTaskCreate(task1, "task1", 64, NULL, 4, &task1_handler);
    xTaskCreate(task2, "task2", 64, NULL, 3, &task2_handler);
    xTaskCreate(task3, "task3", 64, NULL, 2, &task3_handler);
    vTaskDelete(task_handler);

    taskEXIT_CRITICAL();
}

void Usart0_recv(uint8_t *data, uint32_t len)
{
    // printf("recv: %s\n", data);
    xEventGroupSetBitsFromISR(event_group, EVENT_BIT_0, NULL);
 }

static void GPIO_config() {
    // 时钟初始化
    rcu_periph_clock_enable(RCU_GPIOA);
    // 配置GPIO模式
    gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN_0);
}

int main(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
    xTaskCreate(start_task, "start_task", 128, NULL, 0, &task_handler);
    vTaskStartScheduler();

    while(1) {}
}

总结

事件组作为FreeRTOS中的重要特性,为嵌入式系统开发带来了灵活而强大的任务协调机制。通过本文的学习,我们深入了解了事件组的核心概念,包括事件组句柄、标志位的设置和等待、以及任务间的同步与通信方式。我们学习了如何创建事件组、如何设置和等待特定的事件标志位,以及如何通过事件组实现任务的有效协作。

在实际应用中,事件组可以帮助开发人员实现高效的任务调度和资源管理,提升系统的可靠性和响应速度。通过合理利用事件组的功能,开发人员能够更好地优化系统性能,适应不同的应用场景需求,从而实现更为复杂和可靠的嵌入式软件设计。

通过持续学习和实践,我们可以进一步探索和应用事件组的高级特性,为嵌入式系统开发注入更多创新和效率。希望本文能为读者提供实用且深入的指导,帮助他们在实际项目中充分发挥事件组的优势,构建出更加稳健和高效的嵌入式应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/729537.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从新手小白到红酒大咖:解锁红酒品鉴的终极秘籍,升级之路全攻略

在五彩斑斓的饮品世界中&#xff0c;红酒以其深邃的色泽、丰富的口感和悠久的历史&#xff0c;吸引了无数人的目光。对于红酒的初学者来说&#xff0c;从小白到品鉴师的道路或许充满了未知与挑战&#xff0c;但只要掌握了正确的知识和方法&#xff0c;就能够轻松踏入这个美妙的…

测试的基础知识大全【测试概念、分类、模型、流程、测试用例书写、用例设计、Bug、基础功能测试实战】

测试基础笔记 Day01阶段⽬标⼀、测试介绍⼆、测试常⽤分类2.1 阶段划分单元测试集成测试系统测试验收测试 2.2 代码可⻅度划分⿊盒测试&#xff1a;主要针对功能&#xff08;阶段划分->系统测试&#xff09;灰盒测试&#xff1a;针对接⼝测试&#xff08;阶段划分->集成测…

海思NNIE精度对比详细操作指南

海思NNIE部署推理经常会遇到精度下降问题,但是又摸不着头脑究竟是什么原因,因此需要做精度分析来排查是不是算子问题或者是具体哪个算子问题。本文撰写详细操作说明文档,具体可以参考资料:海思NNIE之Mobilefacenet量化部署-腾讯云开发者社区-腾讯云 1.打开日志等级 不知道…

OpenAI 联合创始人 Ilya Sutskever 的新初创公司致力于“安全超级智能”

OpenAI 前首席科学家伊利亚-苏茨克沃尔&#xff08;Ilya Sutskever&#xff09;在今年 5 月离开了他共同创立的人工智能研究公司后&#xff0c;透露了他的下一个重要项目。 相关阅读&#xff1a;GPT-4o通过整合文本、音频和视觉实现人性化的AI交互&#xff0c;OpenAI推出了其新…

STM32 I2C总线锁死原因及解决方法

本文介绍STM32 I2C总线锁死原因及解决方法。 在使用STM32 I2C总线操作外设时&#xff0c;有时会遇到I2C总线锁死&#xff08;I2C总线为Busy状态&#xff09;的问题&#xff0c;即便复位MCU也无法解决&#xff0c;本文介绍其锁死的原因和解决方法&#xff0c;并给出相应的参考代…

融资融券有哪些优势和风险,融资融券利息怎么算,利率最低是?4.0

融资融券的优势 1. 提高资金利用率&#xff1a;获得额外的资金或股票交易&#xff0c;提高资金利用率&#xff0c;扩大投资规模。 2. 降低投资风险&#xff1a;通过融资融券买入多只股票分散风险&#xff0c;降低单一股票持仓风险。 3. 增加投资收益&#xff1a;提供更多的交…

CVPR2024|UniPAD:一种自动驾驶的统一的预训练范式

本文章仅用于学术分享 论文标题丨 UniPAD: A Universal Pre-training Paradigm for Autonomous Driving 论文地址丨 https://arxiv.org/abs/2310.08370 代码地址 | https://github.com/Nightmare-n/UniPAD 关注「AI前沿速递」公众号&#xff0c;获取更多前沿资讯 01总览 这…

Android下QVideoFrame转QImage不成功记录

1.由于QVideoFrame::image() const : unsupported pixel format Format_ABGR32 &#xff0c;在转换时需要做个特殊处理如下,增加了android手机下的特殊格式处理: if(frame.pixelFormat() QVideoFrame::Format_ABGR32) 此部分代码 QImage imageFromVideoFrame(QVideoFrame &…

uniapp 打包 H5 实现在 uniapp 打包 APP 的 webview 通信

一、前言 遇到 uniapp 打包的 APP 在 webview 内嵌入 uniapp 打包的 H5 页面的需求&#xff0c;并实现通信。本篇主要总结了如何实现并总结遇到的问题&#xff0c;希望可以帮助大家减少负担。 实现需求主要有三个地方需要处理&#xff1a; index.html 的打包配置导入 uni.we…

STM32 CAN总线通讯

使用STM32的CAN通讯&#xff0c;利用回环模式&#xff0c;按键控制发送CAN数据&#xff0c;中断接收CAN数据并通过串口助手打印出来。 7.2、配置引脚信息 由于每次新建工程都需要配置信息&#xff0c;比较麻烦&#xff0c;好在STM32CubeIDE提供了导入.ioc文件的功能&#xff…

eclipse中svn从分支合并到主干及冲突解决

1、将分支先commit&#xff0c;然后再update&#xff0c;然后再clean一下&#xff0c;将项目多余的target都清理掉。 2、将branches切换到trunk 3、工程上右键-》Team-》合并&#xff08;或Merge&#xff09; 4、默认选项&#xff0c;点击Next 5、有未提交的改动&#xff0c;…

Python轻松设置Excel单元格数字显示格式

Excel作为强大的数据处理与分析工具&#xff0c;不仅能够存储大量数据&#xff0c;还支持复杂的数据处理与可视化功能。而如何恰当地展示Excel表格中的数据是Excel文件制作的关键之一。这便涉及到Excel单元格数字格式的设置。数字格式不仅关乎数据的美学呈现&#xff0c;如货币…

钒能新材料综合回收利用,钒溶液净化富集工艺之离子交换法

钒电池储能产业作为典型的绿色低碳优势产业&#xff0c;是新型储能领域重要发展方向。钒电池储能具备大规模、长周期等优势&#xff0c;是储能领域的重要组成部分&#xff0c;将成为拓展电能利用、应对可再生能源随机波动、支撑可再生能源高占比电力系统的最佳技术途径之一。 …

【R语言】地理探测器模拟及分析(Geographical detector)

地理探测器模拟及分析 1. 写在前面2. R语言实现2.1 数据导入2.2 确定数据离散化的最优方法与最优分类2.3 分异及因子探测器&#xff08;factor detector&#xff09;2.4 生态探测器&#xff08;ecological detector&#xff09;2.5 交互因子探测器&#xff08;interaction dete…

处理机调度算法即cpu scheduling

i Arrival Time 到达时间Burst Time服务时间 response time开始时间-到达时间 FCFS 按照进程顺序 finsh 按照进程顺序 从0开始依次加上服务时间 周转时间即 finsh时间-到达时间&#xff08;注意不是开始时间&#xff09; waiting time等待时间开始时间-到达时间 带权周转时…

VsCode-PlatformIO 开发环境搭建

在VScode中搜索PlatformIO&#xff0c;然后点击install 安装即可 安装后重新打开vscode&#xff0c;会出现如下界面。

Photoshop揭秘:图像处理领域的领军软件

Photoshop 是一款由 Adobe 企业开发的图像处理软件&#xff0c;也被大家简称为 PS。在广告设计、摄影后期、数字绘画、网页设计等各个领域都得到了广泛的应用&#xff0c;是目前业界最受欢迎的图像处理软件之一。作为一款图像处理软件&#xff0c;Photoshop 为设计者提供了许多…

接到一家公司做团购活动类型的策划海报项目,使用AI给他们设计了相关的海报

在这个充满挑战和机遇的时代&#xff0c;我有幸接到一家公司的委托&#xff0c;为他们策划一场团购活动。这不仅是对我的专业能力的认可&#xff0c;也是对我创新思维的考验。 这家公司是一家知名的电子产品销售商&#xff0c;他们希望通过团购活动来提升产品的销售量和品牌的…

基于国产飞腾2000制作的paddleocr hubserving服务docker镜像文件

目录导航 paddleocr hubserving国产化飞腾、鲲鹏armv8 api服务镜像制作 一、编译paddle 二、准备Dockerfile文件 三、制作paddleocr hubserving服务镜像 四、paddleocr hubserving镜像导出和导入 paddleocr hubserving国产化飞腾、鲲鹏armv8 api服务镜像制作 一、编译padd…

爆火的AI姓名头像号篇篇10w+, 流量主赚麻了...

最近二师兄在刷公众号时&#xff0c;看到一个非常有趣的账号。简单又“暴li”。 几乎篇篇10w。点击去一看&#xff0c;内容也是非常极简&#xff0c;利用姓氏生成头像。一个字都不多。 几乎每篇文末都有广告&#xff0c;一篇10w按照800来算&#xff0c; 一个月大概 ~~一七得七、…