 嵌入式編(bian)程(cheng)規范及注意事項
							時間:2018-01-17      來源:未知
							嵌入式編(bian)程(cheng)規范及注意事項
							時間:2018-01-17      來源:未知 
							嵌(qian)(qian)(qian)入式(shi)(shi)系(xi)統(tong)已經在(zai)(zai)各行各業中(zhong)得到(dao)了廣泛(fan)的(de)(de)(de)應用(yong),隨(sui)著(zhu)人們的(de)(de)(de)生活(huo)向信息化,智(zhi)能化的(de)(de)(de)發展,嵌(qian)(qian)(qian)入式(shi)(shi)技術將徹(che)底融入到(dao)我們的(de)(de)(de)生活(huo),在(zai)(zai)我們的(de)(de)(de)生活(huo)當中(zhong)扮演越(yue)(yue)來(lai)(lai)越(yue)(yue)重(zhong)要(yao)的(de)(de)(de)角(jiao)色。對(dui)于嵌(qian)(qian)(qian)入式(shi)(shi)系(xi)統(tong)來(lai)(lai)講,嵌(qian)(qian)(qian)入式(shi)(shi)軟(ruan)件相(xiang)當于嵌(qian)(qian)(qian)入式(shi)(shi)系(xi)統(tong)的(de)(de)(de)靈(ling)魂,整(zheng)個嵌(qian)(qian)(qian)入式(shi)(shi)系(xi)統(tong)如(ru)何(he)工作,都是由嵌(qian)(qian)(qian)入式(shi)(shi)軟(ruan)件來(lai)(lai)控(kong)制(zhi)的(de)(de)(de)。如(ru)何(he)編寫高(gao)(gao)質量(liang),高(gao)(gao)效率的(de)(de)(de)嵌(qian)(qian)(qian)入式(shi)(shi)軟(ruan)件在(zai)(zai)實際項目(mu)開發過程中(zhong)變的(de)(de)(de)越(yue)(yue)來(lai)(lai)越(yue)(yue)重(zhong)要(yao)。本文針(zhen)對(dui)嵌(qian)(qian)(qian)入式(shi)(shi)軟(ruan)件的(de)(de)(de)特點,從嵌(qian)(qian)(qian)入式(shi)(shi)軟(ruan)件編程規(gui)范和注意(yi)事項2個方面來(lai)(lai)闡述(shu)如(ru)何(he)編寫高(gao)(gao)質量(liang)的(de)(de)(de)嵌(qian)(qian)(qian)入式(shi)(shi)軟(ruan)件。
一、 嵌入式編(bian)程規范(fan)
我(wo)們(men)在(zai)(zai)公司進行(xing)嵌入(ru)式(shi)項目開(kai)發的(de)(de)(de)(de)時候,并不是(shi)(shi)你(ni)一(yi)(yi)(yi)(yi)(yi)個(ge)人在(zai)(zai)單打獨斗,通常(chang)是(shi)(shi)一(yi)(yi)(yi)(yi)(yi)個(ge)團隊在(zai)(zai)一(yi)(yi)(yi)(yi)(yi)起(qi)(qi)戰(zhan)斗。很多(duo)人在(zai)(zai)一(yi)(yi)(yi)(yi)(yi)起(qi)(qi)共(gong)同完成一(yi)(yi)(yi)(yi)(yi)個(ge)嵌入(ru)式(shi)項目,通常(chang)是(shi)(shi)每個(ge)成員,每個(ge)小組(zu)完成整個(ge)項目中的(de)(de)(de)(de)一(yi)(yi)(yi)(yi)(yi)個(ge)或幾個(ge)模塊。我(wo)們(men)編(bian)寫的(de)(de)(de)(de)代碼(ma)首先是(shi)(shi)給人看(kan)的(de)(de)(de)(de),其(qi)次才是(shi)(shi)給機器執行(xing)的(de)(de)(de)(de),這就要求我(wo)們(men)團隊中的(de)(de)(de)(de)每個(ge)人在(zai)(zai)編(bian)寫軟件(jian)的(de)(de)(de)(de)時候,要遵循統(tong)一(yi)(yi)(yi)(yi)(yi)的(de)(de)(de)(de)編(bian)程規范(fan)和編(bian)碼(ma)風格(ge),提高(gao)代碼(ma)的(de)(de)(de)(de)可(ke)讀性(xing)和可(ke)維護性(xing),方便團隊成員之間的(de)(de)(de)(de)溝(gou)通和交流。在(zai)(zai)實際項目開(kai)發過(guo)程中,遵循統(tong)一(yi)(yi)(yi)(yi)(yi)的(de)(de)(de)(de)編(bian)程規范(fan)相當(dang)重要,同學(xue)們(men)一(yi)(yi)(yi)(yi)(yi)定要引起(qi)(qi)足(zu)夠(gou)的(de)(de)(de)(de)重視,下(xia)面我(wo)就從代碼(ma)排版,代碼(ma)注釋,標(biao)識符命名,代碼(ma)可(ke)讀性(xing)和函數設計幾個(ge)方面來(lai)講解比較通用的(de)(de)(de)(de)嵌入(ru)式(shi)軟件(jian)編(bian)程規范(fan)。
1. 代碼排版
1) 程序塊要采用縮進風(feng)格編寫(xie), 縮進的空格數為4個或(huo)一(yi)個TAB鍵(jian),設置TAB鍵(jian)為
4個空格.
例如:
int main(int argc, char *argv[])
{
int a=900; //縮進4個(ge)空格(ge)
}
2) 相對獨(du)立的程序塊之(zhi)間、變量說明之(zhi)后必須加空行(xing)
例如:
if (!valid_ni(ni))
{
... // program code
}
//相對(dui)獨立的程序塊之間加空行
repssn_ind = ssn_data[index].repssn_index;
repssn_ni = ssn_data[index].ni;
3) 較長的語(yu)句( >80字符)要分成多行書寫, 長表(biao)達式要在低優先級操作符處劃
分(fen)新行(xing)(xing),操(cao)作符放在新行(xing)(xing)之(zhi)首, 劃分(fen)出的(de)新行(xing)(xing)要進行(xing)(xing)適當的(de)縮(suo)進, 使(shi)排版整(zheng)齊(qi),
語句可讀。
例如:
perm_count_msg.head.len = NO7_TO_STAT_PERM_COUNT_LEN
+ STAT_SIZE_PER_FRAM * sizeof( _UL );
4) 不允許把多個短語句寫(xie)在一行(xing)中,即一行(xing)只寫(xie)一條語句。
例如:
rect.length = 0;
rect.width = 0;
5) if、 for、 do、 while、 case、 switch、 default等語句自(zi)占一行,且if、 for、do、
while等語句的執行(xing)語句部(bu)分無論多少都要加括號(hao){}。
例如:
if (pUserCR == NULL) //if語句單獨占一行
{ //執行語句只有1條也要加{}
return;
}
6) 程序塊的(de)分界符(如C/C++語言的(de)大括號‘ {’和‘ }’)應各獨占一行并且位
于同一列, 同時與引用它(ta)們的(de)(de)語句左對(dui)齊。 在(zai)函數體的(de)(de)開(kai)始、 類的(de)(de)定義、 結
構的定(ding)義、 枚舉的定(ding)義以及if、 for、 do、 while、 switch、 case語(yu)句(ju)中(zhong)的
程序都要采用(yong)如上的縮進方式(shi).
例如:
for (...)
{ //{}單獨占(zhan)一行,與for左對齊
... // program code
}
void example_fun(void)
{
... // program code
}
2. 代碼注釋(shi)
1) 注釋的原則是有助(zhu)于對程序的閱讀理解(jie),在該加(jia)的地(di)方(fang)都加(jia)了,注釋不宜太多也不
能太少, 注釋語言必(bi)須準確(que)、易懂(dong)、簡(jian)潔,防止注釋的二義性.
2) 說明(ming)性文(wen)件(如頭(tou)文(wen)件.h文(wen)件)頭(tou)部應進行注釋, 注釋必須列出:版(ban)權說明(ming)、版(ban)本
號、生成日期、作者、內容、功能、 修(xiu)改日志等, 頭文件(jian)的注(zhu)釋中還應有函數功能
簡要說明。
例如:
Copyright (C), 2004-2018, 華清遠見(jian)教(jiao)育科技集團.
File name: // 文件名
Author: Version: Date: // 作者、版本(ben)及(ji)完成日期(qi)
Description: // 用于詳(xiang)細說明(ming)此程序文件完成的主(zhu)要(yao)功(gong)能(neng),與其他模塊(kuai)
// 或函數的(de)(de)接口,輸出值、取值范圍、含(han)義及參(can)數間的(de)(de)控
// 制、順序(xu)、獨立或(huo)依賴等關系
Function List: // 主要函數(shu)列表,每條記錄應包括函數(shu)名及功(gong)能簡要說明
1. ....
History: // 修(xiu)(xiu)改歷(li)史記(ji)錄列表(biao),每條修(xiu)(xiu)改記(ji)錄應包括修(xiu)(xiu)改日期、修(xiu)(xiu)改
// 者及修(xiu)改內容簡述
1. Date:
Author:
Modification:
2. ...
3) 源文(wen)件頭部應進行注釋, 列出: 版權說明、 版本號、 生成日期、 作者、 模塊目的/功(gong)能、主要函數及其功(gong)能、 修改日志等(deng).
例如:
Copyright (C), 1988-2018, 華清遠見教育科(ke)技集團.
FileName: test.cpp
Author: Version : Date:
Description: // 模(mo)塊描述(shu)
Function List: // 主要(yao)函數及其功能
1. -------
History: // 歷史(shi)修改記錄
David 96/10/12 1.0 build this moudle
4) 函(han)數頭部應(ying)進行注(zhu)釋(shi),列出函(han)數的功能、輸入參(can)數、輸出參(can)數、返回值等。
例如:
Function: // 函數名稱
Description: // 函數功能(neng)、性能(neng)等的描述
Input: // 輸入(ru)參數說明,包括(kuo)每個參數的作用、取(qu)值說明及參數間關系(xi)。
Output: // 對輸出參數的(de)說明(ming)。
Return: // 函數返回值的說(shuo)明
Others: // 其(qi)它(ta)說明
5) 邊(bian)寫代碼(ma)邊(bian)注釋, 修改代碼(ma)同時修改相應的注釋, 以保(bao)證注釋與代碼(ma)的一(yi)致(zhi)
性。 不再有用的(de)注釋要刪(shan)除。
6) 注釋應與(yu)其(qi)描(miao)述的代碼(ma)相近, 對代碼(ma)的注釋應放在其(qi)上方或右方(對單(dan)條語句(ju)
的注釋)相鄰位(wei)置(zhi), 不可放在下面,如(ru)放于上(shang)方(fang)則需與其上(shang)面的代碼用空(kong)行隔開。
3. 標(biao)識符命名
1) 標識(shi)符的(de)命名(ming)要(yao)清晰、 明(ming)了, 有明(ming)確(que)含(han)義, 同(tong)時使用完(wan)整的(de)單詞(ci)或大(da)家基(ji)本(ben)
可(ke)以理解的縮(suo)寫,避(bi)免使人產生誤解.
2) 對于變量命(ming)名,禁止(zhi)取單個字符(如i、 j、 k...) ,建議除了要有具體含(han)義外,
還能表(biao)(biao)明(ming)其變量(liang)類型(xing)。建議(yi)在變量(liang)前面加前綴(zhui) g表(biao)(biao)示(shi)全局(ju)變量(liang),m表(biao)(biao)示(shi)形式參數.
例(li)如(ru): int gCount = 0;
3) 命名規范(fan)必(bi)須與所使用(yong)的(de)系統風格保(bao)持一(yi)致(zhi),并(bing)在同一(yi)項目中統一(yi),比如采用(yong)
UNIX的全小(xiao)寫加下(xia)劃線的風格(ge)或大小(xiao)寫混排(pai)的方式, 不要同時(shi)使用大小(xiao)寫與下(xia)
劃線混排的方式。
例如(ru): char total_score =0;
4) 函數名(ming)應準確描(miao)述函數的(de)功(gong)能,使用動賓詞(ci)組為執行某操作(zuo)的(de)函數命名(ming)。
例如:
int input_record( void )
unsigned char get_current_color( void )
5) 除非必要(yao),不要(yao)用(yong)數字或較(jiao)奇怪的字符來(lai)定義標識符
6) 用(yong)正確的(de)反義詞(ci)組(zu)命名(ming)具有互斥意義的(de)變量(liang)或相反動(dong)作的(de)函數等
4. 代碼可讀性(xing)
1) 注意(yi)運(yun)算符的優(you)先級,并用(yong)括號明確表達式(shi)的操作順序,避免使用(yong)默認優(you)先級
例如:不(bu)要(yao)這樣(yang)寫: word = high << 8 | low
而應該寫成如下這樣(yang): word = (high << 8) | low
2) 避免使(shi)用不易理解的數(shu)字, 用有(you)意(yi)義(yi)的標(biao)識來替代(dai)。 涉及物理狀態或者含有(you)物理意(yi)
義的常量,不(bu)應直接使用數字,必須(xu)用有意(yi)義的枚舉或宏來代替.
例如:
#define TRUNK_IDLE 0
#define TRUNK_BUSY 1
if (Trunk[index].trunk_state == TRUNK_IDLE)
{
Trunk[index].trunk_state = TRUNK_BUSY;
... // program code
}
3) 不要(yao)使(shi)用難懂的技巧性(xing)很高的語句,除非很有必要(yao)時.
例如: 不要使用類似這樣的(de)難懂的(de)語句 *stat_poi++ += 1; 應該分(fen)成(cheng)多個(ge)語句
書寫(xie),增強代碼可讀性.
二(er)、嵌入式編程中的注意事項
嵌入(ru)式軟(ruan)件開發和普(pu)通軟(ruan)件編(bian)程(cheng)(cheng)相比,有(you)一些自(zi)己的(de)特點,下(xia)面(mian)(mian)從嵌入(ru)式軟(ruan)件架構(gou),中(zhong)斷(duan)編(bian)程(cheng)(cheng),寄存器配置,浮點運算等幾個方面(mian)(mian)來講解嵌入(ru)式編(bian)程(cheng)(cheng)中(zhong)的(de)注意事(shi)項(xiang).
1. 嵌入式系統的軟件架構
一個大型(xing)的(de)嵌入式(shi)軟(ruan)件(jian)往往需要根據功能(neng)的(de)不(bu)同劃分成多個軟(ruan)件(jian)功能(neng)模塊。
1) 模塊即是一個.c文件(jian)(jian)和(he)一個.h文件(jian)(jian)的結合,頭文件(jian)(jian)(.h)中是對于(yu)該模塊接(jie)口的聲(sheng)明;
2) 某模(mo)塊提供給其它(ta)模(mo)塊調(diao)用的外部函數及數據需在.h中文件(jian)中冠以extern關鍵字
聲明;
3) 模塊內(nei)的函數(shu)和全局變量需在.c文(wen)件開頭(tou)冠以static關鍵字聲明(ming);
4) 永遠不要在(zai).h文件中定(ding)義(yi)變量!定(ding)義(yi)變量和聲明變量的區別在(zai)于定(ding)義(yi)會產生內(nei)存分
配的操作,是匯編階段的概念;而聲(sheng)明(ming)則只是告訴包含該(gai)聲(sheng)明(ming)的模塊在連(lian)接(jie)階段從(cong)
其它模塊尋(xun)找外部函數和變量
2. 中斷編程
中(zhong)斷(duan)(duan)是嵌入(ru)式系統中(zhong)重要的(de)(de)組(zu)成(cheng)部(bu)分(fen),但是在(zai)標(biao)準C中(zhong)不(bu)包(bao)含中(zhong)斷(duan)(duan)。 許多(duo)編譯(yi)開發商在(zai)標(biao)準C上增加了對中(zhong)斷(duan)(duan)的(de)(de)支(zhi)持,提供新的(de)(de)關(guan)鍵字用于(yu)標(biao)示中(zhong)斷(duan)(duan)服(fu)(fu)務程序(xu)(xu)(xu). 類似于(yu)__interrupt、#program interrupt等。當一(yi)個函數被(bei)定義(yi)為中(zhong)斷(duan)(duan)服(fu)(fu)務處理程序(xu)(xu)(xu)的(de)(de)時候,編譯(yi)器會自動為該函數增加中(zhong)斷(duan)(duan)服(fu)(fu)務程序(xu)(xu)(xu)所需要的(de)(de)中(zhong)斷(duan)(duan)現場入(ru)棧(zhan)和出棧(zhan)代(dai)碼(ma)。
中斷服務程(cheng)序需要(yao)滿(man)足如下要(yao)求:
1) 不能有返(fan)回值(zhi);
2) 不能向中斷服務處理程序傳遞(di)參數;
3) 中斷服務處理程序應該盡可(ke)能的短小精悍,不要包含耗時的代碼
3. 寄存器配置(zhi)
嵌入(ru)式軟(ruan)件是面向硬件底層的軟(ruan)件,我(wo)們(men)在(zai)對硬件進(jin)行編程(cheng)時(shi),通(tong)常(chang)是通(tong)過(guo)配置(zhi)(zhi)(zhi)硬件相關的寄(ji)(ji)(ji)存器(qi)來實現的。在(zai)配置(zhi)(zhi)(zhi)寄(ji)(ji)(ji)存器(qi)時(shi),通(tong)常(chang)我(wo)們(men)只需要(yao)配置(zhi)(zhi)(zhi)寄(ji)(ji)(ji)存器(qi)的1位或幾(ji)位,對于其他不(bu)(bu)需要(yao)配置(zhi)(zhi)(zhi)的位,我(wo)們(men)要(yao)保持不(bu)(bu)變,不(bu)(bu)要(yao)更(geng)改我(wo)們(men)不(bu)(bu)需要(yao)配置(zhi)(zhi)(zhi)的位。
例如:我們(men)希望配置(zhi)寄(ji)存器的(de) GPIOADAT 的(de)第(di) 1位(wei) 為 1
我們不(bu)能這樣寫成這樣:
GPIOADAT = 0x02; //將其他位設置為 0
而應該(gai)寫成(cheng)這樣(yang):
GPIOADAT |= 0x02; //保證其(qi)他位不變
4. 浮點運算
大多數低檔(dang)次(ci)的(de)(de)單(dan)片機都是不(bu)支持(chi)浮(fu)點運(yun)算(suan)(suan)的(de)(de),因(yin)(yin)此在實際使(shi)用(yong)過程中(zhong)也(ye)很少用(yong)到,因(yin)(yin)此為了降(jiang)低成本(ben),一(yi)般都去掉了浮(fu)點運(yun)算(suan)(suan)模塊,這就帶來了一(yi)個問(wen)題(ti)(ti),如(ru)果萬一(yi)要用(yong)到浮(fu)點運(yun)算(suan)(suan)怎(zen)么辦?我(wo)們(men)可以(yi)采用(yong)的(de)(de)是“定點”的(de)(de)方法來解決這個問(wen)題(ti)(ti),就是直接放大10的(de)(de)N次(ci)方倍進行(xing)整數的(de)(de)計算(suan)(suan),可以(yi)得出(chu)近似值,因(yin)(yin)此為了不(bu)增加不(bu)必要的(de)(de)麻(ma)煩,應該總是盡量避免使(shi)用(yong)浮(fu)點運(yun)算(suan)(suan),一(yi)般情況也(ye)是可以(yi)避免的(de)(de)。
5. volatile 關(guan)鍵字(zi)的使用
嵌(qian)入式開(kai)發過程(cheng)中(zhong),在定義(yi)硬件寄(ji)存(cun)器的(de)(de)(de)時候(hou),需要(yao)使用(yong)volatile關鍵字。 volatile提醒(xing)編譯器它后面所定義(yi)的(de)(de)(de)變(bian)量隨時都有(you)可(ke)能(neng)改變(bian),因此編譯后的(de)(de)(de)程(cheng)序(xu)每次需要(yao)存(cun)儲或讀取這個變(bian)量的(de)(de)(de)時候(hou),都會直接從變(bian)量地址中(zhong)讀取數(shu)據。 如果沒有(you)volatile關鍵字,則編譯器可(ke)能(neng)優化讀取和存(cun)儲,可(ke)能(neng)暫(zan)時使用(yong)寄(ji)存(cun)器中(zhong)的(de)(de)(de)值。
例如: #define GPIO_DATA (*(volatile unsigned int *)0x90002000)
以上(shang)就是我今天要(yao)給同(tong)學們(men)講解(jie)的(de)(de)嵌(qian)入式(shi)軟件編程規范和(he)注(zhu)(zhu)意(yi)事(shi)項,希望(wang)同(tong)學們(men)在實(shi)際的(de)(de)嵌(qian)入式(shi)項目開(kai)發過(guo)程中(zhong)嚴(yan)格遵循嵌(qian)入式(shi)軟件編程規范和(he)注(zhu)(zhu)意(yi)事(shi)項,開(kai)發出高質量,穩定(ding),可靠,維護性(xing)高的(de)(de)嵌(qian)入式(shi)軟件。

