一. 分层思想与模块化编程
-
分层是基于代码的特性,例如对于一般的嵌入式系统来说,代码的最底层是与硬件相关的,这一层需要根据MCU数据手册以及板载外设编写硬件驱动程序,这一层称为硬件驱动层;而代码的最顶层是应用层,这一层是用来实现具体任务的;而应用层和硬件驱动层之间则可以根据实际合理分层,如下图,则是将其分为了一层,包括FreeRTOS内核以及一些特定功能模块,并且层级内部也可以根据实际情况进行分层。
-
分层时严格规定:只有高层级可以调用其下一层级,但不能跨层级调用,层级内部分层也需遵守这一点;同一层级内的各个模块相互独立,不存在相互调用。这样一来,大大提高了系统的重用率,例如原本的嵌入式系统仅仅更换了芯片,我们就可以只把与主控板相关的硬件驱动层代码进行修改,就可以完成移植。
-
模块化编程就相当于把特定的功能封装成一个黑盒,只留出输入接口以及输出接口,而这个黑盒的具体实现则交由特定的人;而其余需要使用这个模块的人,只需根据约定好的输入输出接口去编写自己负责的部分,当“黑盒”完成后,就可直接将其用于测试自己负责的部分,大大提升了合作效率。
二. 如何进行模块化编程
- 对于c语言来说,模块的接口其实就是一堆函数的集合,输入即为函数的参数、输出即为函数的返回值,所以我们只要确定了函数参数及返回值就能确定一个接口。因此可以使用函数指针来体现模块化编程的优势。
i. 例如calculation模块实现两个数的加减乘除功能,上层的GetValue模块需要去调用这个模块,此时GetValue模块就可以定义如下数据结构,而calculation模块则定义并实现下列这四个函数
/*GetValue模块可以定义如下数据结构*/
typedef struct
{
float (*add)(float,float);
float (*reduce)(float,float);
float (*multiply)(float,float);
float (*divide)(float,float);
}calculate_module_t; /*计算处理模块*/
/*calculation模块则实现这四个函数*/
float Add(float a,float b);
float Reduce(float a,float b);
float Multiply(float a,float b);
float Divide(float a,float b);
ii. 当calculation模块完成时,GetValue模块只需将函数指针指向实际的功能函数,就可以直接测试GetValue模块是否正常了
calculate_module_t calculate_module;
calculate_module.add = Add;
calculate_module.reduce = Reduce;
calculate_module.multiply = Multiply;
calculate_module.divide = Divide;
- 注意,只有模块的接口函数才可以在其头文件定义,被模块调用者使用;而下一层级模块的头文件、只在本模块使用的函数的声明和只在本模块使用的数据变量的声明及宏定义,不能出现在模块的头文件中。
以上是我对模块化编程的一点理解,不足之处请在评论区指出。