基於C語言的單片機、arm相關的工程開發時,C語言的模組化特點體現的非常明顯。試想一下:你的一個工程中需要用到AD採樣模組、液晶顯示模組、串口發送模組、DA控制模組等。你肯定不會選擇在一個.c檔案中進行,必須是分模組的,這樣才有利於團隊開發,提高效率。
那麼模組化設計遵循著怎樣的原則呢,應該怎麼寫.c,.h檔案呢。
1. .c和.h檔案的區別
通常意義上的說法,.c是源檔案,.h是標頭檔。通常為了創作者為了保護其代碼,而把.c檔案封裝起來,不公開,而將。.h檔案提供。此時.h相當於介面,供程式員調用。
但是實際上我們自己編寫.h,.c檔案時會發現.c與.h檔案裡面的內容其實並沒有什麼區別。在.c中寫的代碼同樣可以在.h檔案寫。
2.工程中使用.c,.h檔案
總的來說,.h檔案有兩種使用方法。
方法一:
正是由於1中藍色部分的描述的原因。我們會發現好多工程中某個模組只有.h檔案,而沒有.c檔案
以的DSP開發【瑞泰提供的常式為例】其工程中ICETEK-VC5509-EDU.h檔案中包含了對12864液晶屏的寄存器地址定義,相關操作函數定義。並沒有寫相關的.c檔案。然後在lcd.c檔案中調用ICETEK-VC5509-EDU.h。這樣的做法是可行的,為什麼可行,上面1中已經講得很清楚。
但是我們再來思考一個問題。如果這個工程中我又添加了一個ad.c。在ad.c中我們需要用到液晶顯示,那麼我們得調用ICETEK-VC5509-EDU.h 。如果我們這麼做了,工程編譯連結會通過嗎?
肯定不會,會報define duplicated //重複定義的錯誤,為什麼呢? include "ICETEK-VC5509-EDU.h"相當於把這句話替換成ICETEK-VC5509-EDU.h中的內容,而ICETEK-VC5509-EDU.h中對液晶的寄存器都進行了定義,初始化,函數都已經定義了。你在兩個檔案中引用ICETEK-VC5509-EDU.h,肯定會報重複定義的錯誤。
這種方法適用於單模組,或者某個模組不會被多個.c檔案調用
方法二:在.c檔案中進行變數,數組,函數的定義,在.h檔案中進行變數,數組,函數的聲明。
C語言支援的是一處定義,多處聲明【這裡所講的聲明指的是狹義上的聲明,引用聲明,即不會進行記憶體配置】
現在將上述的ICETEK-VC5509-EDU.h分成.c和.h檔案
首先在.h檔案中開頭寫上
#ifndef __ICETEK-VC5509-EDU_H
#define __ICETEK-VC5509-EDU_H //防止重複定義,名字與.c相同
#endif
然後就要進行進一步的操作
(1)宏定義,宏定義是遇到此變數即替換
所以放在.h檔案中
如:
// McBSP0 ------------------------------------------------------
#define SPCR0 (*(unsigned int *)0x018c0008)
#define PCR0 (*(unsigned int *)0x018c0024)
#define SPCR01 (*(unsigned int *)0x01900008)
#define SPCR02 (*(unsigned int *)0x0)
(2)函數,函數的定義和聲明比較清晰
.h檔案進行聲明
void InitInterrupt(void); // 初始化中斷
void InitCTR(); // 初始化ICETEK-CTR
void CloseCTR(); // 關閉ICETEK-CTR上各裝置
.c檔案進行定義
void CloseCTR()
{
CTRGR=0;
CTRLR=0; CTRLR=0x40;
CTRLR=0x0c0;
LCDCMD(LCDCMDTURNOFF);
dbClearKey=CTRCLKEY;
LBDS=0;
}
這樣就可以實現多個.c檔案加.h標頭檔,而不會導致重複定義的問題。
(3)數組等變數
變數的聲明和定義在單個檔案時好像都不怎麼區分的。
變數的聲明:指明變數名,變數類型。
變數的定義:指名變數名,變數類型,分配記憶體空間。
eg int a; //定義
extern int a; //聲明
如果進行了賦值,則肯定是定義
extern int a=0; //定義
所以在.h檔案中:
extern unsigned char ledbuf[8],ledx[8];
extern unsigned char dbClearKey;
extern unsigned char ledkey[10][8];
extern unsigned int music[nMusicNumber][2];
//變數聲明
.c檔案:
unsigned int pwm[8]={ 0x86,0x87,0x83,0x8b,0x89,0x8d,0x8c,0x8e };
//變數必須要定義
unsigned char dbClearKey; //必須要定義
unsigned char ledbuf[8];
unsigned char ledx[8];
【
在這地方還是有個疑問的,在.h檔案中如果不加extern 編譯也是可以通過的,那麼unsigned char ledbuf[8]也能表示聲明。【.h檔案是先被載入進.c檔案,所以.h中unsigned char ledbuf[8]是最先執行的。為什麼表示的是聲明呢】