MCU订阅-发布模式

STM32裸机架构-定时器任务+消息事件【订阅发布模式】 stm32裸机编程, 定时器任务+消息事件,模块化编程 阅读详情
AI摘要

本文详细介绍了uMCN模块中实现发布 - 订阅机制的核心数据结构。包括消息中心、订阅者节点、消息中心链表等结构体,以及辅助宏与常量、发布数据、订阅主题、数据复制等函数。通过这些结构和函数,uMCN实现了高效的发布 - 订阅系统,保证了数据一致性。

在**uMCN(Micro Communication Node)**模块中,多个数据结构协同工作,实现发布-订阅机制。下面是uMCN中各个核心数据结构的详细功能解释。

1. McnHub 结构体:消息中心

功能:McnHub 是 uMCN 中的核心结构体,代表一个具体的消息主题(Topic)。它负责管理数据的发布和订阅,以及维护订阅者节点的链表。

struct mcn_hub {
    const char* obj_name;         // 主题名称,用于唯一标识
    const uint32_t obj_size;      // 主题数据的大小
    void* pdata;                  // 指向存储发布的数据的指针
    McnNode_t link_head;          // 订阅者链表的头节点
    McnNode_t link_tail;          // 订阅者链表的尾节点
    uint32_t link_num;            // 当前订阅者数量
    uint8_t published;            // 标志该主题是否已发布数据
    uint8_t suspend;              // 标志该主题是否暂停发布
    rt_event_t event;             // 用于事件通知的RTOS事件
    int (*echo)(void* parameter); // 打印主题内容的回调函数
    float freq;                   // 发布频率估算值
    uint16_t freq_est_window[MCN_FREQ_EST_WINDOW_LEN]; // 发布频率估算窗口
    uint16_t window_index;        // 当前频率窗口索引
};
详细解释:
  • obj_name:表示主题的名字,通过它标识不同的主题。订阅者通过该名称来订阅主题。
  • obj_size:保存主题数据的大小,定义了该主题发布的数据类型和所需的存储空间。例如,如果发布的数据是 float 类型,obj_size 将是 sizeof(float)。
  • pdata:这是一个指向实际存储发布数据的指针。通过这个指针,发布的数据会存储在该内存区域中,并且当新的数据发布时,旧数据会被覆盖。
  • link_head 和 link_tail:这是一个链表结构,存储了所有订阅该主题的订阅者节点(McnNode)。通过这两个指针,uMCN 可以高效地管理订阅者。
  • link_num:表示当前订阅该主题的订阅者数量。
  • published:标志主题是否已经发布过数据。如果为 1,表示主题已经有数据发布过。
  • suspend:标志主题是否被暂停发布。设置为 1 时,主题将不会接收新的发布数据。
  • event:在实时操作系统(RTOS)中用于订阅者等待事件通知,表示主题的发布事件。
  • freq:保存发布频率的估算值。
  • freq_est_window 和 window_index:用于估算发布频率的滑动窗口,记录最近几次的发布时间间隔。

2. McnNode 结构体:订阅者节点

功能:McnNode 代表一个订阅者,它存储与某个主题的订阅信息。每个订阅者节点都会挂在 McnHub 的订阅者链表上。

struct mcn_node {
    McnHub_t hub;             // 指向订阅的消息中心(主题)
    volatile uint8_t renewal; // 标志订阅者是否收到了新的数据
    void (*pub_cb)(void* parameter); // 发布数据时的回调函数
    McnNode_t next;           // 链表中的下一个订阅者节点
};
详细解释:
  • hub:指向当前订阅的主题(McnHub),即该订阅者关注的消息中心。
  • renewal:这是一个标志位,表示该订阅者是否接收到了新的数据。当 mcn_publish() 函数发布数据时,所有订阅者的 renewal 标志都会被设置为 1。
  • pub_cb:发布数据时调用的回调函数。当主题发布新的数据时,系统会遍历订阅者链表,调用每个订阅者的回调函数以通知它们数据更新。
  • next:指向下一个订阅者节点,实现订阅者链表。

3. McnList 结构体:消息中心链表

功能:McnList 用于维护系统中所有的 McnHub,即消息中心的链表。每个消息中心(主题)都会作为一个节点保存在该链表中。

struct mcn_list {
    McnHub_t hub;    // 指向当前链表节点的消息中心(主题)
    McnList_t next;  // 指向下一个消息中心
};
详细解释:
  • hub:指向链表中的一个 McnHub,即一个具体的主题。
  • next:指向下一个链表节点,实现所有主题的管理。通过这个链表,uMCN可以访问系统中的所有已定义的消息中心。

4. 辅助宏与常量

  • MCN_DECLARE 和 MCN_DEFINE:

    • MCN_DECLARE:用于在代码的其他部分声明一个消息主题。
    • MCN_DEFINE:用于定义一个消息主题,并为其分配内存。

    例如:

MCN_DEFINE(temp_sensor, sizeof(float));  // 定义一个浮点类型的主题

5. mcn_publish() 函数:发布数据

功能:数据发布由 mcn_publish() 函数完成。它将数据复制到消息中心,并遍历订阅者链表,更新每个订阅者的更新标志并调用回调函数。

fmt_err_t mcn_publish(McnHub_t hub, const void* data) {
    ...
    memcpy(hub->pdata, data, hub->obj_size);  // 将数据复制到已分配的内存
    ...
    // 遍历所有订阅者并更新其 renewal 标志
    McnNode_t node = hub->link_head;
    while (node != NULL) {
        node->renewal = 1;  // 标志订阅者接收到新数据
        if (node->pub_cb != NULL) {
            node->pub_cb(hub->pdata);  // 调用订阅者的回调函数
        }
        node = node->next;
    }
    ...
}

6. mcn_subscribe() 函数:订阅主题

订阅者通过 mcn_subscribe() 函数订阅消息(将订阅者节点挂在消息中心的订阅者链表中),并注册一个回调函数用于处理数据更新。

McnNode_t mcn_subscribe(McnHub_t hub, void (*pub_cb)(void* parameter)) {
    ...
    node->pub_cb = pub_cb;  // 注册订阅者的回调函数
    ...
    hub->link_num++;
    return node;
}

7. mcn_copy() 函数:数据复制

功能:订阅者可以通过 mcn_copy() 从消息中心复制最新的数据到订阅者的缓冲区中。这是确保订阅者能获取最新数据的关键步骤。

fmt_err_t mcn_copy(McnHub_t hub, McnNode_t node_t, void* buffer) {
    memcpy(buffer, hub->pdata, hub->obj_size);  // 将数据复制到订阅者的缓冲区
    return FMT_EOK;
}

8. 主题的声明与定义 

#define MCN_DECLARE(_name) extern McnHub __mcn_##_name
#define MCN_DEFINE(_name, _size) \
    McnHub __mcn_##_name = {     \
        .obj_name = #_name,      \
        .obj_size = _size,       \
        .pdata = NULL,           \
        .link_head = NULL,       \
        .link_tail = NULL,       \
        .link_num = 0,           \
        .published = 0,          \
        .suspend = 0,            \
        .freq = 0.0f             \
    }

总结

  • McnHub 是 uMCN 的核心结构,负责管理主题的发布和订阅。
  • McnNode 代表订阅者,管理订阅的主题和数据更新的回调函数。
  • McnList 用于维护所有消息中心的链表。
  • uMCN通过这些结构实现了一个高效的发布-订阅系统,保证了发布者和订阅者之间的松耦合和数据的一致性。


Zephyr zbus 内核消息总线:嵌入式多线程发布订阅通信实战 当嵌入式系统从单链路演化为多模块协作时,传统的消息队列往往面临归属不清、通知困难与耦合加重等挑战。Zephyr 提供的 zbus 是一种内核级内存消息总线,通过 Channel 通道、Subscriber 订阅者和 Listener 监听者,将数据生产与消费彻底解耦,实现发布/订阅模式下的轻量级通信。它以定长消息槽位保存最新数据,配合 pub/notify/read/write 等操作,兼顾确定性与实时性,适用于传感器聚合、协议网关、多线程状态同步等场景。合理划分通道粒度、善用事件广播并遵循静态订阅优先原则 阅读详情

相关推荐

zcm通讯在嵌入式软件中的使用及移植

ZCM不仅是一个技术框架,更是面向未来技术架构的思考与实践。无论是复杂的机器人控制、微妙的Web应用集成,还是嵌入式世界的深度探索,ZCM都提供了强大而灵活的解决方案。它的出现降低了通讯复杂性的门槛,让开发者能够更专注于业务逻辑本身。通过ZCM,我们可以共同探索更多可能性,推动技术的不断进步和发展。

loveliu928的博客 2465

FMT源码 - module

Param 参数模块提供了定义、读取、写入和存储参数的功能。这些参数可以存储在各种存储设备上,例如SD卡或闪存。如果没有参数文件存在,则将使用默认的参数值。uMCN 是 类似于 PX4里面的。在系统启动阶段,参数从。

蒲公英的诗与远方 444

Publishlib:嵌入式轻量级发布-订阅状态通告框架

在嵌入式系统开发中,状态可视化与模块解耦是调试与人机交互的核心挑战。发布-订阅(Pub/Sub)模式作为一种松耦合通信范式,通过事件驱动机制实现逻辑分离,显著提升系统可维护性与可扩展性。Publishlib 正是面向资源受限MCU(如Cortex-M0+/M3)设计的轻量级实现,不依赖RTOS或动态内存,以静态环形缓冲区和时间戳驱动状态机保障确定性行为。其技术价值体现在低至1.2KB Flash、48B RAM的极致精简,支持GPIO/PWM/WS2812多类型LED驱动,并天然适配STM32 HAL与Fr

weixin_36369848的博客 178

消息订阅(想法)

在mqtt中, 可以通过订阅主题, 来接收服务器的消息通知. 那是不是我们在单片机中也可以模拟一个呢?我们可以用这个来获取我们感兴趣的事件.这里是以按键消息来做为订阅主题, 为了偷懒, 我没有使用链表, 使用链表会更加灵活, 并且如果是按键有一个消息主题就可以了, 没必要整这么多.sub()这个不定参函数, 可以让订阅消息更灵活, 可以一次订阅多个消息(最近开发的mqtt就可以一个主题将服务器所有主题订阅)这里应该再次优化, 将sub()函数抽出来, 变成一个公共函数, 其他消息类型也可以订阅.

自学嵌入式 501

MCU中使用观察者模式

为了解决嵌入式系统中常见的 模块解耦、事件驱动、低功耗响应 等核心问题。

Car12 74

3D识别建模 — 基于ReconstructMe和EAGLE EYES SCANNER的实现

3D实体识别建模,作为3D打印反向工程的一个重要环节,今天就让我们利用ReconstructMe和EAGLE EYES SCANNER来了解一下。 第一步、软件和硬件准备就绪 ReconstructMe下载并安装 http://reconstructme.net/?wpdmdl=160 EAGLE EYES SCANNER直接将相应USB插入电脑接口即OK,之后在    中点击搜索“设备管理...

qq_40013290的博客 881

立创·梁山派开发板-21年电赛F题-送药小车数据的发布与订阅

使用发布-订阅模式获取数据的好处在于,系统中的任务或模块之间解耦合,发布者和订阅者之间不直接依赖于彼此的存在,从而提高了系统的可扩展性和灵活性。此外,发布-订阅模式还能够支持多对多的通信,允许多个订阅者同时接收相同的数据或事件,实现了信息的分发和共享。灵活性:发布-订阅机制支持多对多的通信模式,一个发布者可以有多个订阅者,一个订阅者也可以订阅多个发布者的事件或消息。主题(Topic):主题是数据或事件的分类或标识符,发布者根据主题将数据发送到相应的通道,而订阅者根据主题来选择订阅的数据源。

m0_73059981的博客 146

LVI-SAM适配KITTI数据集避坑指南:IMU频率与数据同步问题解析

本文深入解析了将LVI-SAM框架适配KITTI数据集时,在IMU频率与多传感器数据同步方面遇到的核心挑战与解决方案。针对KITTI数据集中sync与extract两种数据包的差异,文章提供了从数据选择、参数调优到时间戳诊断与修复的完整避坑指南,帮助开发者实现稳定高效的SLAM系统部署。

7z8x2c4v6b9的博客 248

发布-订阅模式

发布-订阅模式 学习知识要善于思考,思考,再思考。 —— 爱因斯 在众多设计模式中,可能最常见、最有名的就是发布 - 订阅模式了,本篇我们一起来学习这个模式。 发布 - 订阅模式 (Publish-Subscribe Pattern, pub-sub)又叫观察者模式(Observer Pattern),它定义了一种一对多的关系,让多个订阅者对象同时监听某一个发布者,或者叫主题对象,这个主题对象的状态发生变化时就会通知所有订阅自己的订阅者对象,使得它们能够自动更新自己。 当然有人提出发布 - 订阅模式和观察

uperficialyu的博客 7837

C# typeof() 和 GetType()区别

总得来说他们都是为了获取某个实例具体引用的数据类型System.Type。 1、GetType()方法继承自Object,所以C#中任何对象都具有GetType()方法,x.GetType(),其中x为变量名,由x实例返回得到一个类型 2、typeof(x)中的x,必须是具体的类名、类型名称等,不可以是变量名称,返回一个类型 3、System.Type.GetType(),有两个重载方法 比如有这样一个变量i: Int32 i = new Int32(); 使用GetType(),i...

Peter的博客 1955

Eureka自我保护机制

Eureka自我保护机制 默认情况下,当eureka server在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒),但是,如果短时间内丢失大量的实例心跳,便会触发eureka server的自我保护机制,比如在开发测试时,需要频繁地重启微服务实例,但是我们很少会把eureka server一起重启(因为在开发过程中不会修改eureka注册中心),当一分钟内收到的心跳数大量减少时,会触发该保护机制。可以在eureka管理界面看到Renews threshold和Renews(last

Soul_Ming的博客 543

嵌入式C语言设计模式四:发布-订阅模式

写到这里,我们来回顾一下这篇文章讲了什么。

zhuguanlin121的博客 253

AI产品经理面试宝典第9天:关于AI产品经理的挑战与转型怎么回答

AI技术重构产品逻辑,AI产品经理需直面三大核心命题:用户定位差异、技术融合边界、商业价值转化。本文从千道真题中提炼出面试高频考点,剖析AI产品经理如何突破传统思维定式,在B端需求与C端体验间构建价值桥梁,用数据驱动产品创新,破解技术落地的隐性壁垒。掌握这三重跃迁法则,助你在AI浪潮中脱颖而出。

打造全国最全的AI Agent开发知识领域的博客 175

Android 车机 Car模式原理

这个系统为汽车特定要求、功能和技术提供了支持,通过在原先的Android系统架构上增加与车相关的模块来实现,这些模块包括Car App(包括OEM和第三方开发的App)、Car API(提供给汽车App特有的接口)、Car Service(系统中与车相关的服务)等‌。IVehicle服务是Android Automotive在硬件抽象层的一个核心native服务,用于处理和车辆相关的功能,并为系统提供获取车身信息以及设置相关状态的接口‌。系统自动编译sdk,编译时引用即可,系统运行时,已经加载了这些类库;

Android技术之家 664

差分式升压逆变器MATLAB仿真模型设计——实现110V/50Hz输出电压与THD<5%

差分式升压逆变器MATLAB仿真设计 摘要 本文提出一种基于差分式升压逆变器(DBI)的MATLAB仿真设计方案,实现80V直流输入转换为110V/50Hz交流输出。该方案采用单级升压逆变拓扑结构,相比传统两级方案具有更高的功率密度和效率。通过建立数学模型,设计SPWM调制策略和电压闭环PI控制,并在MATLAB/Simulink中构建完整仿真模型。仿真结果表明,系统输出电压THD<5%,满足设计要求。文章详细阐述了主电路参数计算、控制策略实现和仿真验证过程,为实际工程应用提供了理论依据和技术参考。

huanghm88的专栏 122

【51单片机仿真】基于51单片机设计的多功能电子时钟日历(实时时钟闹钟秒表温度检测)系统__资料编号5

该项目是基于单片机的多功能电子时钟系统,集成了时间显示、闹钟设置、秒表功能以及温度显示等功能。主要硬件包括1602液晶显示屏、DS1302时钟芯片、DS18B20温度传感器和蜂鸣器。系统通过按键进行时间和闹钟的设置,并实时显示当前时间和温度。

嵌入式阿齐Archie 2万+

X-TRACK实战指南:深度解析开源GPS码表框架的三大核心模块

X-TRACK是一款支持离线地图和轨迹记录的开源GPS自行车码表,采用模块化设计架构,为开发者提供了丰富的二次开发接口。本文将从实战角度出发,深度解析X-TRACK的三大核心模块:数据处理中心、页面管理系统和硬件抽象层,帮助你快速掌握项目架构并实现功能扩展。 ## SEO关键词策略 **核心关键词**:GPS码表开发、离线地图实现、嵌入式系统架构 **长尾关键词**:AT32 MCU开发实

gitblog_00208的博客 414

[AHK]获取通达信软件上的股票代码

PC上的股票交易软件的自动止损、自动下单等功能比较弱,不如期货交易软件。 自力更生,程序员都是自己打造工具。 根据IPO模型(Input 输入,Process处理,Output输出),为了方便自动化首先要获取当前交易软件上浏览的股票代码。 截图再OCR显然太麻烦,通过Winspy工具查看下交易软件自带功能的消息号(33780),大家记住这个号码! 下面在用AutoHotkey作为变成语...

liuyukuan的专栏 1万+

Licode媒体处理深度解析:OneToManyTranscoder与VideoMixer实现原理

Licode是一个基于WebRTC和云技术的开源通信平台,专注于提供高效的实时音视频通信解决方案。在Licode的核心架构中,媒体处理模块扮演着至关重要的角色,其中**OneToManyTranscoder**和**VideoMixer**是两个关键组件,负责实现高效的媒体流转发和混合功能。本文将深入解析这两个核心模块的实现原理和工作机制,帮助开发者更好地理解Licode的媒体处理架构。 ##

gitblog_00236的博客 809

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【山大会议】创建 WebRTC Peer

本文介绍了如何创建 WebRTC Peer,包含它的结构定义,以及一些必要的方法。

weixin_45922876的博客 336

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

AI智能棋盘集成ESP8266推送MQTT远程通知

基于ESP8266与MQTT的智能棋盘实现远程状态同步,通过传感器感知落子、主控处理、Wi-Fi低延迟推送,支持AI分析与多端订阅,具备高可靠性与扩展性。

weixin_29859471的博客 473

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

CoCube和Micro-ROS简单案例演示

遇到问题,非常普遍,多多查阅github的issus或者micro-ros社区。很多时候,看架构图,不能就看个热闹,需要将每个部分的细节都理解清楚。令人吃惊的文档,日期220818,后续可能会不太一样哦!支持多种通信模式,有线方式比无线稳定。暑期学校中实践案例的直播演示的PPT部分。文档是如下这种情况,慌不慌?这一点,能做到的学员已经很少了。下位机订阅灯,发布IMU。...

zhangrelay的专栏 1272

ROS2系列教程:MicroROS接入(原理+仿真)

本文详解ROS2 MicroROS接入原理与仿真实践,解决嵌入式设备与上位机通信的通用性难题。通过MicroROS架构(Client+Agent+传输层),实现MCU作为ROS2节点无缝接入系统。基于Docker仿真环境,演示Host模式下在PC模拟MCU运行rclc代码,配合micro-ROS Agent完成串口通信,完整跑通话题发布/订阅流程,为后续真机开发及ROS2-Control应用奠定基础。

CJLU_WSJ的博客 253

MCU/DSP 与 ROS2 如何通信?XRCE-DDS 实现 rostopic 与嵌入式 Msg 无缝映射(附架构图)

一文打通:MCU/DSP 与 ROS2 如何通信?XRCE-DDS 实现 rostopic 与嵌入式 Msg 无缝映射(附架构图)

weixin_39939185的博客 567

如何用事件驱动框架告别裸机轮询地狱?一个轻量框架搞定单片机状态机开发

当你的嵌入式项目还在用 `while(1)` 里层层 if-else 硬啃按键、串口和定时器时,**EventOS Nano** 这个**事件驱动框架**已经为 STM32 等 MCU 平台准备好了更优雅的解法。它把程序组织成"事件来了才响应"的模式,占用资源低到惊人,下面带你完整认识它。 ## 为什么嵌入式MCU需要事件驱动框架:三种开发痛点对比 传统前后台程序长这样:`while(1)`

gitblog_00783的博客 155

【架构心法】砸碎“轮询”的绞肉机!彻底抛弃盲等思维,在混沌物理中建立“事件驱动”的绝对因果律

很多技术人在面对复杂的跨端协同项目时,总觉得要在所有的层级写满控制代码,才觉得踏实。他们用极其密集的轮询,试图将失控的物理世界强行捏合在软件的节拍里。但这是一种错觉。真正的架构之美,在于**“无为而治”**。我们抛弃了轮询,是对物理世界自身演进规律的最大尊重。我们建立事件驱动,是用最低的算力成本,换取了对突发灾难最快、最本能的物理响应。当你能克制住写下while(1)的冲动,学会用异步的事件流去重新编织从底层传感器到前端 UI 的物理羁绊时;

Max_uuc的博客 205
上一篇: 计算入射光强度和吸收系数
下一篇: BC28 AT指令
Let's Chat Coding
博客等级 码龄3年 1020粉丝 92原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值