1. 问题的提出
  2. 有什么更好的方案吗
  3. 结构体封装+指针传递
    1. .h文件
    2. .c文件
    3. 在其他模块中使用
  4. 通过函数提供读取和修改的接口
    1. .h文件
    2. .c文件
    3. 在其他模块中使用
  5. 联合起来
  6. 挖坑

嵌入式模块化设计中的数据共享优化方案

版权信息

本文章为博主原创文章。遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。


问题的提出

在嵌入式项目中,模块化每个功能有利于管理和理清开发思路,但是,当我们需要将模块联动起来的时候,需要一些必要的变量以实现两个模块之间的互相配合,最常见的方法是使用全局变量,但这样做使模块间耦合性[1]大大提高了。

有什么更好的方案吗

有的兄弟有的。只不过要牺牲一些效率(需要通过接口访问)。我们可以为共享变量建立一个专门的.c/.h文件,例如SharedData.c/.h
这个文件集中管理模块间的共享变量。这样做结构清晰,每个模块只依赖 SharedData.h,而不是彼此依赖\
同时我们通过两种方法使需要访问变量的模块成功读取或修改变量:

  • 结构体封装+指针传递
  • 通过函数提供读取和修改的接口

结构体封装+指针传递

👍

  • 共享变量较多时非常好用。
  • 隐藏全局变量,外部模块无法直接访问共享数据而是通过指针,安全性高。
  • 更好扩展。
  • 方便,无需为每个变量都写函数接口以提供修改与读取。
  • 访问速度快

.h文件

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef SHARED_DATA_H
#define SHARED_DATA_H

typedef struct {
int sensor_value;
int motor_speed;
} SharedData;

// 只提供获取指针的接口,而不是直接暴露变量
SharedData* get_shared_data(void);

#endif

.c文件

1
2
3
4
5
6
7
#include "shared_data.h"

static SharedData system_data = {0, 0}; // 只在本文件可见

SharedData* get_shared_data() {
return &system_data;
}

在其他模块中使用

1
2
3
4
5
6
#include "shared_data.h"

void moduleA_update() {
SharedData *data = get_shared_data();
data->sensor_value += 10;
}

不推荐将接收共享变量的指针的变量定义为全局变量。尽管这样会方便一些。指针可能被多个模块修改,导致指向无效地址(增加 bug 风险)。推荐在每个函数内部通过接口访问变量。如果一定要这样做,请一定避免空指针(记住初始化指针)

使用全局指针示例:

1
2
3
4
5
static SharedData *data;  // 仅限当前文件访问

void moduleA_init() {
data = get_shared_data();//避免空指针
}

通过函数提供读取和修改的接口

👍

  • 灵活访问变量。你可以严格控制对数据的访问,如只读、避免非法值写入等;同时也可以自定义访问方法,如按位读取。非常的好用。
  • 可扩展性强。

  • 代码冗长,调用花销稍大。
  • 变量太多时需要为每个变量都写接口,太麻烦。所以才要和上面的方法联合起来使用,只为必要的变量编写接口,其余通过第一种方法访问。

.h文件

1
2
3
4
5
6
7
8
9
10
11
#ifndef SHARED_DATA_H
#define SHARED_DATA_H

void setSensorValue(int value);
int getSensorValue();

void setMotorSpeed(int speed);
int getMotorSpeed();

#endif

.c文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "shared_data.h"

static int sensor_value = 0;
static int motor_speed = 0;

void setSensorValue(int value) {
if (value >= 0) { // 限制非法值
sensor_value = value;
}
}

int getSensorValue() {
return sensor_value;
}

void setMotorSpeed(int speed) {
if (speed >= 0) {
motor_speed = speed;
}
}

int getMotorSpeed() {
return motor_speed;
}

在其他模块中使用

1
2
3
4
5
#include "shared_data.h"

void moduleA_update() {
setSensorValue(getSensorValue() + 10);
}

联合起来

将两种方式联合起来使用——大部分变量,我们使用指针接口访问即可;如果有些变量需要一些个性化要求,我们为这些变量编写定制的接口就好。

挖坑

降低耦合性的方法还有使用单例模式,以及RTOS中的消息/事件机制。后续研究。


  1. 代码耦合性(Coupling)是指模块或组件之间的依赖程度。如果代码耦合性很高,模块之间会紧密依赖,导致代码难以维护、扩展和测试。 ↩︎