不知不覺(jué)已經(jīng)出來(lái)工作一年,經(jīng)過(guò)一年的工作,使我學(xué)了不少東西,從而使我認(rèn)識(shí)到以前很多不足之處,也想把自己的程序調(diào)試經(jīng)驗(yàn)跟大家分享下。
首先是軟件的編寫環(huán)境,選擇一個(gè)編譯平臺(tái)對(duì)于編寫代碼效率是至關(guān)重要的,在實(shí)際開發(fā)中,基本上使用Source Insight這個(gè)軟件上編寫和根改程序代碼,本人現(xiàn)在使用的的是Source Insight3.5,這個(gè)軟件功能非常強(qiáng)大,可以幫你快速定位代碼、查看代碼變量使用及各位置調(diào)用情況等信息。顏色管理也非常出色,根據(jù)顏色可以判斷各個(gè)信息,比如變量是否定義、是局部變量還是全局變量等,可以說(shuō)只要你使用過(guò)了就決不會(huì)再想在KEIL環(huán)境下編寫代碼了,當(dāng)然程序很小有點(diǎn)感覺(jué)不出來(lái),而對(duì)于程序量較大,且充分使用程序模塊化,就是頭文件的使用,定位程序的速度可以達(dá)到想到哪里就定位到哪里。熟悉后基本是使用各個(gè)快捷鍵進(jìn)行操作,到那時(shí)KEIL就是當(dāng)作一個(gè)編譯器使用了。
KEIL建工程還是很有講究的,假如代碼比較大時(shí),而工程全部又放在同一個(gè)文件里,那這個(gè)文件里的東西就像雜貨間,找一個(gè)東西都難。如下建立一個(gè)工程簡(jiǎn)單keil工程,這樣建的工程,在keil設(shè)置相關(guān)的頭文件調(diào)用路徑,清單與工程存放文件等設(shè)置后,整個(gè)工程的程序代碼就跟keil工程文件獨(dú)立了,這樣就對(duì)代碼的移植及備份帶來(lái)很大的方便,當(dāng)然還有分得更細(xì)的工程了。這樣一來(lái)Source Insight工程里添加文件,SVN版本管理代碼就方便了。
變量及函數(shù)的定義在一個(gè)工程里命名習(xí)慣是非常重要的,做到看到函數(shù)或變量名就可以知道變量和函數(shù)的意義及作用。我一般命令根據(jù)函數(shù)功能相關(guān)的關(guān)鍵字進(jìn)行命名,而關(guān)鍵字與關(guān)鍵字之間用大小寫區(qū)分,我英語(yǔ)也很差,但語(yǔ)法可以不懂,但專業(yè)英語(yǔ)的單詞還是要會(huì)使用的。而變量定義能用結(jié)構(gòu)體的盡量使用,比如時(shí)間就可以構(gòu)建一個(gè)時(shí)間結(jié)構(gòu)體變量,里面包含年、月、日、時(shí)、分、秒、星期,這樣定義了一個(gè)時(shí)間就非常容易操作而且直觀。
程序的調(diào)試是寫程序最重要的環(huán)節(jié),好的調(diào)試方法可以快速完成程序調(diào)試。以前調(diào)試就是要在板上設(shè)置一盞燈,不然程序跑到哪里出了問(wèn)題都不知道,所以以前沒(méi)燈都不知道怎么樣去調(diào)試,但即使有燈調(diào)試,這樣效率也是很低的而且實(shí)際中也不太現(xiàn)實(shí)。使用串口打印信息來(lái)調(diào)試程序,可以完全跟TUBRO C 2.0下的printf函數(shù)格式進(jìn)行信息打印,如使用%d,%s、%f、%c打印各類型變量值,而這個(gè)功能函數(shù)就是debug.c和debug.h模塊文件,在這里預(yù)編譯發(fā)揮著重要的作用,可以根據(jù)自己配置的定義去控制打印的信息,當(dāng)程序調(diào)試結(jié)束后就關(guān)閉打印信息,這樣編譯器就不會(huì)編譯調(diào)試信息,這有就不用一個(gè)一個(gè)把調(diào)試代碼刪掉了,當(dāng)要更改程序時(shí),可以重新打開編譯信息,這就充分使用了C語(yǔ)言里的預(yù)編譯和DUBUG的使用,這就是為什么程序里存在調(diào)試版和釋放版,而調(diào)試版程序運(yùn)行時(shí),往往在串口可以看到相關(guān)的信息。斷言(assert (條件))也是檢測(cè)程序里關(guān)鍵參數(shù)一個(gè)重要調(diào)試方式,但條件不成立時(shí)打印出錯(cuò)所在的文件下的第幾行和錯(cuò)誤條件信息。串口調(diào)試環(huán)境構(gòu)建當(dāng)使能調(diào)試時(shí)要開銷一部分資源,不過(guò)現(xiàn)在單片機(jī)基本上有外擴(kuò)RAM,從而使串口調(diào)試在51單片機(jī)上調(diào)試成為可能。
附:本人調(diào)試keil51時(shí)遇到打印char 類型出現(xiàn)了一些問(wèn)題,比如char a=0X01,用printf(“a=%c\n”,a),串口會(huì)打印出a=0100, 用printf(“a=%d\n”,a),串口會(huì)打印出a=512,而keilARM里沒(méi)出現(xiàn),應(yīng)該是51keil標(biāo)準(zhǔn)庫(kù)的問(wèn)題。
程序的屏蔽,以前最常用的是 “ // ”和”/**/”來(lái)注釋掉程序,//是屏蔽掉一行的代碼,當(dāng)要屏蔽一段代碼時(shí)就會(huì)使用/**/來(lái)屏蔽,但往往一些注釋也用/**/來(lái)注釋,如果在屏蔽段代碼中剛好用/**/的注釋,那是問(wèn)題就出現(xiàn)了,以前就會(huì)把代碼段里/**/該成//注釋,F(xiàn)在就我們可以使用#if <條件> 一段代碼 #endif來(lái)屏蔽一段代碼,當(dāng)條件為真時(shí)編譯器編譯代碼,如為0則不編譯代碼,這樣就容易多了。
前后臺(tái)系統(tǒng),寫程序中處理單個(gè)任務(wù)在難的功能只算是一個(gè)功能,代碼多容易寫,當(dāng)任務(wù)多個(gè)給且任務(wù)看似實(shí)時(shí)的,如數(shù)碼管顯示,按鍵操作、流水燈、點(diǎn)陣顯示燈這樣的任務(wù)放在一起的時(shí)候,就存在時(shí)間調(diào)配問(wèn)題。這些我們按鍵按下時(shí)要馬上反應(yīng)、數(shù)碼顯示、點(diǎn)陣顯示、流水燈都是要實(shí)時(shí)處理的,比如按鍵按下不能及時(shí)反應(yīng),要麻處理按鍵時(shí)顯示停在某個(gè)狀態(tài),而這些現(xiàn)象在實(shí)際中是完全可以同時(shí)出現(xiàn)的,而你是看不的上面的現(xiàn)象,而處理這樣的事件往往是*前后臺(tái)系統(tǒng)運(yùn)行起來(lái)的,而前后臺(tái)系統(tǒng)就是看定時(shí)器來(lái)構(gòu)建這個(gè)程序的軟中斷一樣,比如單片機(jī)里的中斷就是一個(gè)機(jī)器周期去查詢中斷的狀態(tài)位,如符合中斷,程序就會(huì)放下當(dāng)前代碼去執(zhí)行中斷代碼,但按鍵、數(shù)碼顯示、點(diǎn)陣這些對(duì)人來(lái)說(shuō)是時(shí)間很短的,但對(duì)于單片機(jī)來(lái)說(shuō)是很長(zhǎng)的,有了這樣的思維后我們就可以構(gòu)建一個(gè)由我們自己定的模擬軟件中斷查詢周期,這個(gè)周期就是*定時(shí)器來(lái)設(shè)置中斷間隔時(shí)間,而這個(gè)在定時(shí)器里處理的事件最好是占用時(shí)間短,比如計(jì)數(shù)、少數(shù)個(gè)賦值、狀態(tài)判斷及標(biāo)記,然后后臺(tái)(main()函數(shù)里的代碼)就根據(jù)前臺(tái)(TimerTnterrupt()函數(shù)里的代碼)返回的標(biāo)記狀態(tài)進(jìn)行處理相應(yīng)事件。這就有點(diǎn)像操作系統(tǒng)的系統(tǒng)節(jié)拍,簡(jiǎn)稱為系統(tǒng)的心臟。