《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); } }
|