模块化编程在51单片机中的应用
2022-05-15杨传燕张俊莲史媛
杨传燕 张俊莲 史媛
摘要:为了提高51单片机程序的可读性与可移植性,缩短程序开发设计时间,本文详细介绍了模块化编程的优势与具体操作步骤,并举例。
随着对单片机学习的深入,程序设计越来越复杂,要实现的功能也越来越多,此时采用传统编程方式,将所有的函数都放在main.c里,则一个文件内会有很多的代码,不利于代码的组织和管理,影响编程者的思路,造成程序的可读性变差。同时在很多的应用中,有很多功能的重复,如果每次都重新编写程序,会造成大量的时间浪费,提高程序的可移植性也刻不容缓。在单片机的实际应用开发中,一个程序由很多个模块组成,这些模块的编写任务将会被分配到不同的人。实现在整个设计过程中的分工合作,减少开发时间。
一、模块化编程的优势
模块化编程则能很好的解决以上问题,模块化编程是把各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数的声明,其它.c文件想使用其中的代码时,只需要#include "xxxx.h"文件,然后在程序中进行调用即可。使用模块化编程后,我们只需要关心这个模块实现了什么样的功能,如何调用,至于模块内部是如何组织的则无需过多关注,此时更多的是追求接口的单一性,把不需要的细节尽可能的对外部屏蔽起来。使用模块化编程可极大的提高代码的可阅读性、可维护性、可移植性等。
二、模块化编程设计步骤
在模块化编程中,往往会有多个C文件,每个C文件的作用不相同,在C文件中,由于需要对外提供接口,因此还必须有一些函数或变量提供给外部其它文件进行调用。因此,对于每一个模块都有相应的.c文件和.h文件,为了阅读调试方便,原则上.c和.h文件同名。比如,对延时函数进行模块化编程时,我们则可以将其命名为Delay.c和Delay.h。
1、创建头文件
以上创建的.h文件则是头文件,它里面存放的是可被外部调用的函数、变量的声明,不包括任务实质性的函数代码。我们可以把这个头文件理解成一份说明书,说明的内容是模块对外提供的接口函数或者接口变量,以及一些很重要的宏定义与结构体信息,离了这些信息,很可能无法正常使用接口函数或者接口变量。以刚建立的Delay.h为例进行阐述头文件的内容及作用。
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
这个几条条件编译(ifndef和endif)和宏定义(define)是为了防止重复包含。假如有两个不同源文件需要调用Delay(unsigned int xms)这个函数,他们分别都通过#include “Delay.h”把这个头文件包含了进去。在第一个源文件进行编译时候,由于没有定义过__DELAY_H__,因此#ifndef __DELAY_H__条件成立,于是用宏定义定义#define__DELAY_H__定义一个__DELAY_H__,并将下面的声明包含进去。在第二个文件编译时候,由于第一个文件包含时候,已经将__DELAY_H__定义过了。因此#ifndef __DELAY_H__不成立,整个头文件内容就没有被包含。假设没有这样的条件编译语句,那么两个文件都包含了void Delay(unsigned int xms);就会引起重复包含的错误。因此,在.h文件中,为了防止出现错误都进行了防重复包含。
2、模块功能编程
以上讲了头文件的作用及定义方法,对于c文件,则是对函数、变量的定义,实现模块的功能。比如Delay.c函数程序如下:
void Delay(unsigned int xms)
{
unsigned char i, j;
for(i=0;i<xms;i++)
for(j=0;j<120;j++);
}
此段程序和原來的main.c里的延时函数一样,只不过单独独立出来放要给文件里,实现程序的模块化。
3、模块调用
要实现模块的调用,则需要先将模块的头文件添加进来,比如在主程序中,如果想要调用延时函数,则需要通过#include “Delay.h”将头文件包含进来。
三、模块化编程举例
通过以上步骤,我们完成了模块化编程的基本步骤,我们将以流水灯为例,对程序进行模块化,图1是我们常规的编程方法,将延时函数和主函数写在同一个C文件里,如果函数功能复杂的话,程序的可读性不好。图3是将延时函数独立成一个模块,图2在主函数里进行调用,使程序简洁明了,提高程序的可读性。如果在其它工程里需要用到延时函数时,只需要将延时函数的.c文件和.h文件加载到对应的工程里即可,提高了程序的可移植性。同时对于复杂的工程的开发,则可以按模块进行分工,然后再进行调用整合,缩短程序开发设计过程。