《51單片機(jī)輕松入門—基于STC15W4K系列》內(nèi)容節(jié)選 |
2.5 模塊化編程 2.5.1 頭文件的編寫 執(zhí)行菜單File→New新建一個(gè)空白文件,然后保存,保存路徑選擇當(dāng)前工程所在文件夾,為方便閱讀程序,文件名盡量與對應(yīng)的*.c文件名相同,后綴名為*.h,模塊化編程通常是一個(gè)*.c文件對應(yīng)一個(gè)*.h文件,頭文件編寫中首先要使用條件編譯命令防止頭文件重包含錯(cuò)誤,例如: #ifndef __STDIO_H__ //__ 是2個(gè)下劃線 #define __STDIO_H__ ……頭文件代碼塊 #endif 一般格式是這樣的: #ifndef <標(biāo)識> #define <標(biāo)識> ……頭文件代碼塊 #endif <標(biāo)識>在理論上來說可以是自由命名的,為便于理解程序,實(shí)際使用一般是用頭文件名并且全部大寫,前后各加2個(gè)下劃線,并把文件名中的“.”變成一個(gè)下劃線。 2.5.2 條件編譯 一般情況下,源程序中所有的行都參加編譯,但是有時(shí)希望對其中一部分內(nèi)容只在滿足一定條件才進(jìn)行編譯,也就是對一部分內(nèi)容指定編譯的條件,這就是“條件編譯”,條件編譯功能也可用條件語句來實(shí)現(xiàn),但條件編譯可以節(jié)省程序存儲(chǔ)器空間,需要注意的是條件編譯命令行結(jié)尾沒有分號。 第1種條件編譯格式 #ifdef 標(biāo)識符 語句段1; #else 語句段2 #endif 功能說明:如果標(biāo)識符已被#define命令定義過,則編譯語句段1; 否則編譯語句段2。 示例: #define MASTER 1 ┅┅ #ifdef MASTER SPCTL=0xf0; #else SPCTL=0xe0; #endif 第2種條件編譯格式 #ifndef 標(biāo)識符 語句段1; #else 語句段2 #endif 功能說明:如果標(biāo)識符未被#define命令定義過,則編譯語句段1; 否則編譯語句段2。 第3種條件編譯格式 #if 常數(shù)表達(dá)式 語句段1; #else 語句段2; #endif 功能說明:若#if指令后的常數(shù)表達(dá)式為真(隨便什么數(shù)字,只要不是0),則編譯語句段1,否則編譯語句段2。 例如: #define MAX 200 #if MAX>999 printf("compiled for bigger\n"); #else printf("compiled for small\n"); #endif 2.5.3 多文件程序(模塊化編程) 我們第一章介紹的所有程序都很簡單,只需要編寫一個(gè)*.c文件,main()函數(shù)和普通函數(shù)都放在同一個(gè)*.c文件中,就是單文件程序,當(dāng)程序量比較大時(shí),我們應(yīng)該對代碼進(jìn)行分類,不同類型的代碼放到不同的*.c文件中,這就是多文件程序,也就是模塊化編程的方式,采用模塊化編程可以使整個(gè)工程脈絡(luò)清晰,代碼規(guī)劃合理,有利于代碼積累,重復(fù)利用,快速建立大型工程,在這里,我們把一個(gè)*.c或*.h文件就稱為一個(gè)模塊,模塊化編程主要注意以下幾點(diǎn): ① 變量定義與初始化,函數(shù)體都放在 *.c文件中,類型定義、宏、端口定義、SFR聲明、函數(shù)聲明等都放在*.h文件中,若某個(gè)函數(shù)聲明不放在.H文件中,則其它程序無法調(diào)用這個(gè)函數(shù)。 ② 一個(gè)*.c文件配套一個(gè)*.h文件,由于*.c文件中用到的宏定義等可能都是在*.h文件中,所以*.c文件中要使用 #include "*.h"將自己對應(yīng)的頭文件包含進(jìn)來,假設(shè)a.c文件需要調(diào)b.c文件中的函數(shù),a.c除了包含自己對應(yīng)的頭文件外還需要包含b.c對應(yīng)的頭文件。 ③ *.h中的所有內(nèi)容都可以放在*.c中,但*.c中的變量定義初始化等不能放在*.h中。 ④ 整個(gè)工程只能有一個(gè)main()函數(shù)。 多文件程序能夠?qū)崿F(xiàn)的根本原理是C51將所有函數(shù)都認(rèn)為是全局性的,而且是外部的, 可以被另一個(gè)文件中的任何一個(gè)函數(shù)調(diào)用,但是另一個(gè)文件調(diào)用該函數(shù)之前,則應(yīng)在文件的開頭(即所有函數(shù)外的最上端)聲明被調(diào)函數(shù),又因?yàn)槁暶鞯谋徽{(diào)函數(shù)可能會(huì)很多,所以有了包含頭文件的需要。 接下來看一個(gè)流水燈程序采用模塊化編程例子。 例2.35 完整的多文件程序 //*************** A模塊包含下面2個(gè)文件 ********************** // 文件a.h 聲明定義 #include "STC15W4K.H" #define PORT P0 #define DelayTime 50000 void fun1(void); void fun2(void); // 文件a.c // 具體實(shí)現(xiàn) #include "b.h" // 因?yàn)橐玫?quot;b.c"中delay(),所以必須有此命令 #include "a.h" // 因?yàn)橐玫?quot;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個(gè)文件 ********************** // 文件b.h // 聲明定義 void delay(unsigned int time); // 文件b.c //具體實(shí)現(xiàn) void delay(unsigned int time) { while(time--); } //*************** 主文件main.c ********************** #include "a.h" // 因?yàn)橐玫?quot;a.c"中fun1()、fun2(),所以必須有此命令 #include "b.h" // 因?yàn)橐玫?quot;b.c"中delay(),所以必須有此命令 void main() { while(1) { fun1(); delay(10000); fun2(); delay(10000); } }
|