C/C++编程-分层模块化-数据交互

模块间的数据交互

  • 实习方式
  • 方式选择优缺点说明
    • 关于变量
    • 关于函数接口
  • 模块的堆叠
    • 1,模块之间的交互方式:数据交互、函数接口、全局变量。
      • 带系统的模块间交互方式:
      • 不带系统的模块间交互方式:
    • 2,模块堆叠需要遵守的一些规则和考虑

zchs_protocol
vince pipe grab

对于zchs_protocol协议模块和下面的三个运动部件模块之间的交互问题。


实习方式

  • 变量

无系统:跨模块的全局变量
有系统:信号量等

  • 函数接口

方式选择优缺点说明

关于变量

  • 无系统
    例如,在zchs_protocol中定义serial_send_state:0没有数据发送,1有数据发送。
    需要分别在三个运动部件模块中分别置位此标志变量,然后在zchs_protocol中实现发送函数(检测此标志,然后发送)。
    但是这这其中存在的问题是,如果vince模块已经将serial_send_state置1,有vince的数据要发送。那么又有pipe或者grab模块也要置位此位,要申请串口发送数据。那么zchs_protocol就不知道要发送谁的了。说白了,就是需要明确三个底层模块的发送顺序。
    发送顺序又有两种实现方式:变量和逻辑控制
    变量最简单的就是,每个运动模块都在自己模块内置位,清位serial_send_state。每次置位serial_send_state前,都检测是否为1,如果为1,则放弃此次发送,等待下一次轮询到自己模块有没有数据要发送。
  • 有系统
    利用信号量,实现上面逻辑业务逻辑

关于函数接口

在zchs_protocol中定义一个serial_send()接口函数,由三个运动部件调用。
但是一样面对,不知道vince调用此函数的时候,pipe和grab有没有调用。这样的问题。
同样需要标志变量或者逻辑控制,实现**“发送接口”**这个共享资源问题。
其实,裸机没有任务中断调度,已经通过逻辑控制解决了这个问题。即,不可能vince在通过zchs_protocol发送数据的时候,pipe和grab也有数据同时申请发送。
但是,由系统的时候,就需要依旧需要信号量去解决这个问题。
综上,对于变量,裸机和系统都适用。
对于接口函数,裸机适用,系统不适用。
所以,变量实现方式更占优势。
优势:适用普遍,有利移植

zchs_protocol

uint8_t s_state=0;

if(s_state==1)

{

serial_send();

s_state=0;

}

vince

if(v_sate==1)

{

if(s_state!=1)

{s_state=1;v_state=0;}

}

pipe

if(p_sate==1)

{

if(s_state!=1)

{s_state=1;p_state=0;}

}

grab

if(g_sate==1)

{

if(s_state!=1)

{s_state=1;g_state=0;}

}

zchs_protocol
poll()
{
	check_sub_send();
	switch(state)
	{
	ready:break;
	recive:break;
	send:break;
	idle:break;
	}
}

上面的描述虽然有些道理,但是经过一些日子的磨炼,现在又感觉有些肤浅。这是有了新的感悟。现描述如下:

模块的堆叠

我们经常在一些让人崇拜的官网上看到下面这样的软件图解:

APP
drive_a drive_b drive_c
三个下层托起一个上层
或者
APP_A APP_B APP_C
drive
一个下层驱动供三个上层调用

这是软件的整体划分,由下而上的堆叠,这个我自然很容易了解了,其作用也是一样很容易理解了。但是,若想切身的体会却是不容易。应该还是要去大公司工作,并且有着坚实的基础,才会有着切身的体会。
体会就是:即使上层领导根据项目需求,划分好模块了,那么又如何保证软件的书写、构造完美遵循这个堆叠结构呢?
这里面有大量的工作。我技术不够好、层次不够高,也是说不好的。但是却有着下一些切身体会。

1,模块之间的交互方式:数据交互、函数接口、全局变量。

这些实现方式,就像数学中的“加减乘除”是基本的要素,需要我们自己的搜寻、借鉴。有哪些方式实现、各个实现方式能达到的效果、其优缺点又是什么都要自己平时一一积累总结。就是模拟电路中,运放电路的基本电路”加法、减法、乘法、除法、积分、微分、vi、iv、低通、高通、带通、跟随、锁相环、、、”等一样。这都是你以后设计电路的基础电路,有了他们,就是数学中你学会了加减乘除,才能去用它们解决各种问题,他们是基础啊!这个基础知识不行,那还谈什么。也像画家手中的“笔、纸、赤、橙、黄、绿、金、蓝、紫墨水”,有了它们,你才能做画,是一样的道理。

然而市面上的教材,却少有提及这个的,教这个的。其实,我一直认为最好的教材,莫过于汇聚了各个高手的操作系统源码。所以,我把整理这些基础素材的来源,总是分为“带系统”和“不带系统”两种实现方式。

带系统的模块间交互方式:

其实网上都有。这里只是告诉大家把这些思想联系起来。
数据交互方式:队列、邮箱。
函数接口:注册(操作集的指针赋值)。
就是rt_thread和Linux中驱动架构中的操作集的函数接口赋值。
struct file_operation fops =
{
.open = xxx_open;
.close = xxx_close;
.read = xxx_read;
.write = xxx_write;
.probe = xxx_probe;
};
全局变量:信号量,互斥锁、事件。

不带系统的模块间交互方式:

函数接口:
在“model_a.c”的“model_a.h”中声明对外的
void a_open(void);
void a_close(void);
void a_read(void);

或者采用extern关键字修饰,在合适的地方声明。
者两种方式,前者对所有上层模块开放,并且include之后夹带其他通用对外开放信息。所以适合带有common属性。而extern则只需要在需要的上层文件中声明就可,并且不带有.h文件中的其他对外common属性。

对于全局变量和数据交互,也是一样考虑。

2,模块堆叠需要遵守的一些规则和考虑

  • 机制和策略(即“输入”和“输出”)
  • 认清模块在软件栈中的位置-
  • 向下依赖, 不要向上依赖
  • 避免同级依赖

你可能感兴趣的:(嵌入式,C/C++编程,实践工程,c语言,c++)