《51单片机轻松入门—基于STC15W4K系列》内容节选 |
2.5 模块化编程 2.5.1 头文件的编写 执行菜单File→New新建一个空白文件,然后保存,保存路径选择当前工程所在文件夹,为方便阅读程序,文件名尽量与对应的*.c文件名相同,后缀名为*.h,模块化编程通常是一个*.c文件对应一个*.h文件,头文件编写中首先要使用条件编译命令防止头文件重包含错误,例如: #ifndef __STDIO_H__ //__ 是2个下划线 #define __STDIO_H__ ……头文件代码块 #endif 一般格式是这样的: #ifndef <标识> #define <标识> ……头文件代码块 #endif <标识>在理论上来说可以是自由命名的,为便于理解程序,实际使用一般是用头文件名并且全部大写,前后各加2个下划线,并把文件名中的“.”变成一个下划线。 2.5.2 条件编译 一般情况下,源程序中所有的行都参加编译,但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”,条件编译功能也可用条件语句来实现,但条件编译可以节省程序存储器空间,需要注意的是条件编译命令行结尾没有分号。 第1种条件编译格式 #ifdef 标识符 语句段1; #else 语句段2 #endif 功能说明:如果标识符已被#define命令定义过,则编译语句段1; 否则编译语句段2。 示例: #define MASTER 1 ┅┅ #ifdef MASTER SPCTL=0xf0; #else SPCTL=0xe0; #endif 第2种条件编译格式 #ifndef 标识符 语句段1; #else 语句段2 #endif 功能说明:如果标识符未被#define命令定义过,则编译语句段1; 否则编译语句段2。 第3种条件编译格式 #if 常数表达式 语句段1; #else 语句段2; #endif 功能说明:若#if指令后的常数表达式为真(随便什么数字,只要不是0),则编译语句段1,否则编译语句段2。 例如: #define MAX 200 #if MAX>999 printf("compiled for bigger\n"); #else printf("compiled for small\n"); #endif 2.5.3 多文件程序(模块化编程) 我们第一章介绍的所有程序都很简单,只需要编写一个*.c文件,main()函数和普通函数都放在同一个*.c文件中,就是单文件程序,当程序量比较大时,我们应该对代码进行分类,不同类型的代码放到不同的*.c文件中,这就是多文件程序,也就是模块化编程的方式,采用模块化编程可以使整个工程脉络清晰,代码规划合理,有利于代码积累,重复利用,快速建立大型工程,在这里,我们把一个*.c或*.h文件就称为一个模块,模块化编程主要注意以下几点: ① 变量定义与初始化,函数体都放在 *.c文件中,类型定义、宏、端口定义、SFR声明、函数声明等都放在*.h文件中,若某个函数声明不放在.H文件中,则其它程序无法调用这个函数。 ② 一个*.c文件配套一个*.h文件,由于*.c文件中用到的宏定义等可能都是在*.h文件中,所以*.c文件中要使用 #include "*.h"将自己对应的头文件包含进来,假设a.c文件需要调b.c文件中的函数,a.c除了包含自己对应的头文件外还需要包含b.c对应的头文件。 ③ *.h中的所有内容都可以放在*.c中,但*.c中的变量定义初始化等不能放在*.h中。 ④ 整个工程只能有一个main()函数。 多文件程序能够实现的根本原理是C51将所有函数都认为是全局性的,而且是外部的, 可以被另一个文件中的任何一个函数调用,但是另一个文件调用该函数之前,则应在文件的开头(即所有函数外的最上端)声明被调函数,又因为声明的被调函数可能会很多,所以有了包含头文件的需要。 接下来看一个流水灯程序采用模块化编程例子。 例2.35 完整的多文件程序 //*************** A模块包含下面2个文件 ********************** // 文件a.h 声明定义 #include "STC15W4K.H" #define PORT P0 #define DelayTime 50000 void fun1(void); void fun2(void); // 文件a.c // 具体实现 #include "b.h" // 因为要用到"b.c"中delay(),所以必须有此命令 #include "a.h" // 因为要用到"a.h"中的符号PORT和DelayTime,所以必须有此命令 void fun1(void) // 流水灯(从左到右) { unsigned char i=0,temp=0x80; for(i=0;i<8;i++) { PORT=~temp; temp>>=1; delay(DelayTime); } } void fun2(void) // 流水灯(从右到左) { unsigned chari=0,temp=0x01; for(i=0;i<8;i++) { PORT=~temp; temp<<=1; delay(DelayTime); } } //*************** B模块包含下面2个文件 ********************** // 文件b.h // 声明定义 void delay(unsigned int time); // 文件b.c //具体实现 void delay(unsigned int time) { while(time--); } //*************** 主文件main.c ********************** #include "a.h" // 因为要用到"a.c"中fun1()、fun2(),所以必须有此命令 #include "b.h" // 因为要用到"b.c"中delay(),所以必须有此命令 void main() { while(1) { fun1(); delay(10000); fun2(); delay(10000); } }
|