ARM32开发--FreeRTOS-事件组

news2024/11/26 3:43:18

系列文章目录

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


目录

系列文章目录

文章目录

前言

目标

内容

概念

事件标志位

开发流程

功能介绍

创建事件组

触发事件

等待事件触发

同步

清理事件

案例

总结


前言

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

性价比高的洗地机推荐,测评员精选四款热门洗地机分享

家庭清洁新升级&#xff0c;家用洗地机可以让家里打扫变得轻松高效。面对众多品牌和型号&#xff0c;朋友们常犯难&#xff1a;到底应该怎么选家用洗地机&#xff1f;别急&#xff0c;我这回的普及知识可不含糊&#xff0c;亲测超十款热门洗地机&#xff0c;从中精挑细选了四款…

从0开始C++(三):构造函数与析构函数详解

目录 构造函数 构造函数的基本使用 构造函数也支持函数重载 构造函数也支持函数参数默认值 构造初始化列表 拷贝构造函数 浅拷贝和深拷贝 析构函数 总结 练习一下ヽ(&#xffe3;▽&#xffe3;)&#xff89; 构造函数 构造函数的基本使用 构造函数是一种特殊的成…

二叉树的这五种遍历方法你们都会了吗?

说在前面 &#x1f388;二叉树大家应该都很熟了吧&#xff0c;那二叉树的这五种遍历方式你们都会了吗&#xff1f; 以这一二叉树为例子&#xff0c;我们来看看不同遍历方式返回的结果都是怎样的。 前序遍历 前序遍历的顺序是&#xff1a;首先访问根节点&#xff0c;然后递归地…

Power BI 连接数据源/获取数据(Excel表、文件夹、数据库、网页等)

一、Power BI 支持的数据源类型 Power BI支持广泛的数据源类型&#xff0c;包括文件、数据库、云服务和其他来源。 文件&#xff1a;Excel、文本/CSV、XML、JSON、文件夹、PDF等。数据库&#xff1a;SQL Server, Oracle, IBM DB2, MySQL, PostgreSQL等。云服务&#xff1a;Azur…

怎么学习PMP才是最正确的?

每个人的学习方式各不相同&#xff0c;不能一概而论说某种学习方式就是错误的。学习方式并没有绝对的对错之分&#xff0c;只能说是否适合自己&#xff0c;是否能够达到预期的学习效果。并不是别人的学习方式就一定适合自己&#xff0c;也不是不适合自己的学习方式就一定是错误…

简单好用的远程软件推荐? 内网端口映射工具快解析

最近有一些小伙伴求推荐一款简单好用的远程软件&#xff0c;经过多方对比试用&#xff0c;还是推荐快解析。通过快解析内网端口映射&#xff0c;可以让主机电脑自带远程桌面连接直接提供跨网访问控制&#xff0c;外网访问端无需再安装客户端软件&#xff01; 1.目标服务器本地…

【QCustomPlot实战系列】QCPGraph堆叠图

将一个QCPGraph叠加到另一个QCPGraph上显示&#xff0c;就得到了折线堆叠图 static QCPScatterStyle GetScatterStyle(const QColor& color) {QPen pen(color, 2);return QCPScatterStyle(QCPScatterStyle::ssCircle,pen,Qt::white, 5); }static QCPGraph* AddGraph(QCus…

ADI Trinamic TMC2300 完美用于相机镜头的马达驱动芯片方案

TMC2300-LA是一款用于高达 1.2A RMS 的两相步进电机的低压驱动芯片&#xff0c;低电压的步进电机驱动器是用于电池供电的、空间和待机功率临界驱动器应用。它的静音驱动技术StealthChop™能够为便携式&#xff0c;家庭和办公应用程序的非窃听运动控制&#xff0c;确保安静&…

树莓派4B学习笔记11:PC端网线SSH连接树莓派_网线连接请求超时问题解决

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1&#xff1a; 今日学习使用网线连接树莓派&#xff0c;网线可以提供更…

优思学院|质量管理中如何应用5W1H或5W2H方法?

5W1H或者5W2H其实是一种"工作方式"&#xff0c;它不是"思考方法"&#xff0c;这种工作方式是通过回答“什么&#xff08;What&#xff09;&#xff1f;为什么&#xff08;Why&#xff09;&#xff1f;谁&#xff08;Who&#xff09;&#xff1f;何时&#…

Flutter【组件】富文本组件

简介 flutter 富文本组件。 github地址&#xff1a; https://github.com/ThinkerJack/jac_uikit 使用方式 运行 flutter pub add jac_uikit组件文档 使用方式&#xff1a; HighlightedTextWidget.builder(text: "全部文案包含高亮文案测试用",highlights: [Hig…

Rust高性能日志库tklog0.0.8—支持mod设置参数

tklog是rust高性能结构化日志库&#xff0c;支持同步日志&#xff0c;异步日志&#xff0c;支持自定义日志的输出格式&#xff0c;支持按时间&#xff0c;按文件大小分割日志文件&#xff0c;支持日志文件压缩备份&#xff0c;支持官方日志库标准API&#xff0c;支持mod独立参数…

控制台瞬间干净!Vue 删除生产环境烦人的console.log打印,看完这个你就会了!

1.安装插件 需要安装babel-plugin-transform-remove-console插件 yarn add babel-plugin-transform-remove-console //或者 npm install babel-plugin-transform-remove-console2.配置babel.config.js // 所有生产环境&#xff0c;或者也可以配置测试环境 const prodPlugin …

文心一言 VS 讯飞星火 VS chatgpt (285)-- 算法导论21.2 4题

四、请给出图 21-3 所示操作序列的一个运行时间的渐近紧确界&#xff0c;假定使用链表表示和加权合并启发式策略。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 图 21-3 没有直接给出&#xff0c;但通常这种操作序列可能与某种数据结构&#xff08;如并查集或…

计算机网络:网络层 - 虚拟专用网 VPN 网络地址转换 NAT

计算机网络&#xff1a;网络层 - 虚拟专用网 VPN & 网络地址转换 NAT 专用地址与全球地址虚拟专用网 VPN隧道技术 网络地址转换 NAT网络地址与端口号转换 NAPT 专用地址与全球地址 考虑到 IP 地址的紧缺&#xff0c;以及某些主机只需要和本机构内部的其他主机进行通信&…

【经验分享】Ubuntu 24.04 安装搜狗输入法(亲测有效)

【经验分享】Ubuntu 24.04 安装搜狗输入法&#xff08;亲测有效&#xff09; 先用如下Ubuntu22.04的安装方法进行安装 Ubuntu 22.04安装搜狗输入法 发现存在闪屏问题&#xff0c;那解决闪屏问题不就好了&#xff0c;解决方法如下&#xff1a; Ubuntu 23.10 搜狗拼音输入法闪屏…

OceanMind海睿思参与编写的《数据智能白皮书(2024年)》正式发布!

近日&#xff0c;由中国通信标准化协会大数据技术标准推进委员会&#xff08;CCSA TC601&#xff09;牵头和组织&#xff0c;中新赛克海睿思作为TC601-WG16人工智能数据工作组合作伙伴参与编写的《数据智能白皮书&#xff08;2024年&#xff09;》正式发布。 中新赛克的卢云川、…

WebStorm 配置 PlantUML

1. 安装 PlantUML 插件 在 WebStorm 插件市场搜索 PlantUML Integration 并安装&#xff0c;重启 WebStorm 使插件生效。 2. 安装 Graphviz PlantUML 需要 Graphviz 来生成图形。使用 Homebrew 安装 Graphviz&#xff1a; 打开终端&#xff08;Terminal&#xff09;。确保你…

MySQL——索引(概述和结构介绍)

一、索引概述 1、索引(index&#xff09;是帮助 MySQL 高效获取数据的数据结构(是一种有序的数据结构)。 2、在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构。这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0c;这样就可以在这些…

什么是联盟营销?独立站如何通过联盟营销提高转化率?

什么是联盟营销&#xff1f;独立站如何通过联盟营销提高转化率&#xff1f; 流量紧缺是跨境电商独立站永恒不变的难题&#xff0c;对于独立站卖家来说&#xff0c;广告投放、KOL引流等推广方式都能带来流量&#xff0c;但在广告流量越来越贵的今天&#xff0c;对于跨境电商独立…