当前位置:网站首页>嵌入式软件架构设计-消息交互
嵌入式软件架构设计-消息交互
2022-07-05 13:36:00 【虚幻私塾】
优质资源分享
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
Python量化交易实战 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
1、前言
在熟悉任务调度、程序分层和模块化编程关于软件架构、分层和模块设计后,除了函数调用设计中出现的情况外,还会遇到同层模块之前如何进行消息交互,通常是应用层之间。
比如一个设备通过架构设计包含人机交互应用层模块(一般会调用按键和显示屏等功能驱动模块)和通信应用层模块(一般调用串口、CAN和网络ESP8266等功能驱动模块),两个同层之间的模块如果需要互传数据,一般都是调用各自头文件提供的接口(模块对外提供的接口尽量不要使用全局变量,防止其他模块擅自修改),这样就造成了耦合。
2、解决思路
上述情况,也可以采用回调函数的实现方式进行模块解耦,但是需要引入新的内容,即公共模块Commoon层(包含第三方功能库)。
公共模块主要有各模块都需要使用的类型定义、结构体定义、通用函数或常用宏定义等(通常属于基础类的功能,不会受功能需求和不同平台的影响)。
基于公共模块,为了解决各模块之前的数据交互,可以通过公共模块实现基础类的功能达到各应用层模块解耦的目的。
参考消息队列的方式,可以实现一个生产者/消费者的功能模块(这种可以称作观察者模式,即存在观察者和被观察者),即某一模块更新数据后,其他模块可以第一时间得到通知更新(采用回调函数的方式实现)
看图:
Callback 是一个指针数组变量,每个数组成员都是函数指针类型的变量,通过函数 Notify_Attach 拿到了应用层代码函数 OnSaveParam(…) 和OnUpdateParam(…)的函数地址,之后人机交互模块调用了 Notify_EventNotify,从而调用 Callback ,调用方式和直接调用 OnFunction(…) 存在些许差异,因为是数组,所有需要 [ ] 取函数地址,为了保证系统运行安全,调用前要确保 Callback[i] 不为 NULL,否则会引起程序异常。
从上述看,也许有人感觉这样处理反而复杂了,直接调用不香吗?(上述人机交互模块属于被观察者,参数和其他模块属于观察者)
有以下几个好处:
- 避免各模块相互调用,可完成解耦
- 即使 观察者 模块其中一个被移除,也不用修改 被观察者 或者 其他观察者 代码,保证系统稳定
- 新增一个 观察者 模块,也不需要修改 被观察者 代码,保证系统稳定
当然这种方式也有缺点:
- 如果回调函数过多,或者某一个 观察者 的回调函数执行时间很长,肯定会影响到其他观察者 模块的通知时间,甚至影响 被观察者 模块的正常运行
- 如果 观察者 和 被观察者 之间有循环依赖,就会导致他们循环调用,导致系统死机
避免方式:
- 回调函数中一定要保证执行的时间短,不能有执行时间长的功能,甚至延时(一般回调中处理数据更新等执行时间短的即可,数据更新后的需要花时间处理的可以在主循环执行)
- 观察者回调函数中尽量避免执行其他观察者的回调函数,防止循环调用
3、示例代码
事件通知模块头文件
copy
#ifndef \_NOTIFY\_H\_
#define \_NOTIFY\_H\_
#include
/**
* @brief 应用模块ID枚举定义
*
*/
typedef enum
{
NOTIFY_ID_HMI = 0, // 人机交互模块
NOTIFY_ID_SYS_PARAM, // 参数管理模块
NOTIFY_ID_TOTAL
} NotifyId_e;
/**
* @brief 事件类型枚举定义
*
*/
typedef enum
{
NOTIFY_EVENT_PARAM_UPDATE, // 参数更新事件, 对应结构体 PrramUpdateInfo\_t
NOTIFY_EVENT_TOTAL
} NotifyEvent_e;
typedef struct
{
uint16\_t addr;
uint32\_t param;
}PrramUpdateInfo_t;
typedef int (*EventNotifyCB)(NotifyId\_e id, NotifyEvent\_e eEvent, const void *pData, uint32\_t length);
extern void Notify\_Init(void);
extern int Notify\_Attach(NotifyId\_e id, NotifyEvent\_e eEvent, EventNotifyCB pfnCallback);
extern int Notify\_Detach(NotifyId\_e id, NotifyEvent\_e eEvent);
extern int Notify\_EventNotify(NotifyId\_e id, NotifyEvent\_e eEvent, const void *pData, uint32\_t length);
#endif /* \_NOTIFY\_H\_ */折叠
事件通知模块源文件:
copy
#include "notify.h"
#include
static EventNotifyCB sg_pfnCallback[NOTIFY_ID_TOTAL][NOTIFY_EVENT_TOTAL];
/**
* @brief 事件初始化
*
*/
void Notify\_Init(void)
{
memset(sg_pfnCallback, 0, sizeof(sg_pfnCallback));
}
/**
* @brief 添加事件监听通知
*
* @param[in] id 应用模块ID
* @param[in] eEvent 事件
* @param[in] pfnCallback 回调函数
* @return 0,成功; -1,失败
*/
int Notify\_Attach(NotifyId_e id, NotifyEvent_e eEvent, EventNotifyCB pfnCallback)
{
if (id >= 0 && id < NOTIFY_ID_TOTAL && eEvent < NOTIFY_EVENT_TOTAL)
{
sg_pfnCallback[id][eEvent] = pfnCallback;
return 0;
}
return -1;
}
/**
* @brief 删除事件监听通知
*
* @param[in] id 应用模块ID
* @param[in] eEvent 事件
* @return 0,成功; -1,失败
*/
int Notify\_Detach(NotifyId_e id, NotifyEvent_e eEvent)
{
if (id >= 0 && id < NOTIFY_ID_TOTAL && eEvent < NOTIFY_EVENT_TOTAL)
{
sg_pfnCallback[id][eEvent] = 0;
return 0;
}
return -1;
}
/**
* @brief 事件通知
*
* @param[in] id 应用模块ID
* @param[in] eEvent 事件类型
* @param[in] pData 消息内容
* @param[in] length 消息长度
* @return 0,成功; -1,失败
*/
int Notify\_EventNotify(NotifyId_e id, NotifyEvent_e eEvent, const void *pData, uint32_t length)
{
int i;
if (eEvent < NOTIFY_EVENT_TOTAL)
{
for (i = 0; i < NOTIFY_ID_TOTAL; i++)
{
if (sg_pfnCallback[i][eEvent] != 0)
{
sg_pfnCallback[i][eEvent](id, eEvent, pData, length);
}
}
return 0;
}
return -1;
}折叠
参数应用层模块:
copy
#include "notify.h"
static int Param\_OnNotifyProc(NotifyId\_e id, NotifyEvent\_e eEvent, const void *pData, uint32\_t length);
void Param\_Init(void)
{
Notify\_Attach(NOTIFY_ID_SYS_PARAM, NOTIFY_EVENT_PARAM_UPDATE, Param_OnNotifyProc);
}
// 事件回调处理
int Param\_OnNotifyProc(NotifyId\_e id, NotifyEvent\_e eEvent, const void *pData, uint32\_t length)
{
switch (eEvent)
{
case NOTIFY_EVENT_PARAM_UPDATE:
{
PrramUpdateInfo_t *pInfo = (PrramUpdateInfo_t *)pData;
SaveParam(pInfo->addr, pInfo->param);// 保存参数
}
break;
default:
break;
}
return 0;
}
人机交互应用层模块
copy
#include "notify.h"
void Hmi\_Init(void)
{
}
// 需要保存参数
int Hmi\_SaveProc(void)
{
ParamUpdateInfo_t info;
info.addr = 5;
info.param = 20;
Notify\_EventNotify(NOTIFY_ID_HMI, NOTIFY_EVENT_HMI_UPDATE, &info, sizeof(ParamUpdateInfo_t));
}
边栏推荐
- MMSeg——Mutli-view时序数据检查与可视化
- The development of speech recognition app with uni app is simple and fast.
- Can and can FD
- 不知道这4种缓存模式,敢说懂缓存吗?
- Integer ==比较会自动拆箱 该变量不能赋值为空
- go 指针
- When using Tencent cloud for the first time, you can only use webshell connection instead of SSH connection.
- Although the volume and price fall, why are the structural deposits of commercial banks favored by listed companies?
- Prefix, infix, suffix expression "recommended collection"
- Nantong online communication group
猜你喜欢
Solve the problem of invalid uni app configuration page and tabbar
Don't know these four caching modes, dare you say you understand caching?
Fragmented knowledge management tool memos
[server data recovery] a case of RAID5 data recovery stored in a brand of server
FPGA 学习笔记:Vivado 2019.1 添加 IP MicroBlaze
今年上半年,通信行业发生了哪些事?
Although the volume and price fall, why are the structural deposits of commercial banks favored by listed companies?
南理工在线交流群
[notes of in-depth study paper]uctransnet: rethink the jumping connection in u-net from the perspective of transformer channel
Binder communication process and servicemanager creation process
随机推荐
A detailed explanation of ASCII code, Unicode and UTF-8
Flutter 3.0更新后如何应用到小程序开发中
go 字符串操作
53. Maximum subarray sum: give you an integer array num, please find a continuous subarray with the maximum sum (the subarray contains at least one element) and return its maximum sum.
leetcode 10. Regular expression matching regular expression matching (difficult)
“百度杯”CTF比赛 九月场,Web:SQL
Datapipeline was selected into the 2022 digital intelligence atlas and database development report of China Academy of communications and communications
Godson 2nd generation burn PMON and reload system
多人合作项目查看每个人写了多少行代码
How to choose note taking software? Comparison and evaluation of notion, flowus and WOLAI
[深度学习论文笔记]使用多模态MR成像分割脑肿瘤的HNF-Netv2
Operational research 68 | the latest impact factors in 2022 were officially released. Changes in journals in the field of rapid care
Asemi rectifier bridge hd06 parameters, hd06 pictures, hd06 applications
SAE international strategic investment geometry partner
Intranet penetration tool NetApp
go 数组与切片
关于 Notion-Like 工具的反思和畅想
Difference between avc1 and H264
mysql econnreset_Nodejs 套接字报错处理 Error: read ECONNRESET
Multi person cooperation project to see how many lines of code each person has written