用C語言編寫的單片機流水燈程式的軟體和硬體,可以讓八個LED輪流點亮,每個燈點亮和熄滅時間均為1秒。是利用單片機I/O口控制外部裝置的簡單例子。當然,在你掌握了本程式後,完全可以充分發揮你的想象,改變一下程式内容和燈的接法(比如用光耦驅動繼電器來控制霓虹燈),做出各種變化非凡的大型燈光廣告牌。
一、硬體電路
因為電路用單片機控制,是以電路非常簡潔。其電路原理圖見下圖,印制闆圖如下圖所示。

電路的核心部分是AT89C2051單片機,前面提到它有Pl和P3兩組I/O口,我們這裡隻用到Pl口,共8個引腳。圖中Cl、R9組成典型的上電複位(即在加電時單片機複位)電路,XTAL、C2、C3與AT89C2051片内振蕩電路組成時鐘振蕩器。值得注意的是,C2、C3的容量不能與圖中數值偏差太大,否則可能引起不起振或振蕩不穩定。XTAL的頻率可以在4-20MHz之間,不過,頻率的變化會導緻程式運作速度的變化,這樣就需要調整延時子函數的參數。事實上,不調整參數亦可,隻是此時延遲時間不再是1秒,其延遲時間會随着XTAL頻率的降低而增加。
二、軟體部分
本程式包含兩個函數,一個是主函數,另一個是延時子函數。源程式如下(為了便于講解,我們為每行程式加上了編号):
程式各行作用如下:
00行:把AT89C2051的頭檔案“AT89x051.H”包含進來。
01行:聲明Delay()延時子函數,該函數有一個無符号整型參數k,同時函數前面的void表明函數不傳回函數值。
02行:延時子函數的開始,同時聲明兩個無符号整型變量i和j。
不過請注意,這裡沒有象上期的程式一樣,把表示函數開始的“{”單獨成行,而是把下一行寫在一起了。事實上,寫C程式的時候,可以把多行寫作一行,C編譯器隻要遇到分号就認為是一行語句的結束。
當然,我們不能因為C程式有這個特點,就随意把多行合作一行書寫,實際書寫C程式的時候,還是要養成良好的程式書寫習慣,按照約定俗成的原則來書寫。
03行:聲明for()循環。這個循環的初始條件是i=0,終止條件是i<k,循環計數是每循環一次,用手計數的變量i加1。是以,這個循環的循環次數就是k次。這樣,隻要改變k的值(即改變Delay()延時子函數的參數k的值),就可以很容易地控制循環次數,進而獲得不同的延時時間。
04行:聲明嵌套在03循環中的一個新的for()循環,這個循環與上一個循環相似,其循環次數是120次。本循環與上一個循環嵌套後,使得總的循環次數達120×k次。
05行:第一個分号,表示L條空語句,占用一個機器時間,以實作延時的目的。後面的兩個“}”中,第一個“}”是04行for()循環的結束标志,程式遇到它時,将自動傳回04行,使用于循環計數的變量j加1,同時判斷j是否小于120,如果否,則轉入05行;第二個是03行for()循環的結束标志,程式遇到它則會傳回03行。
06行:Delay()延時子函數的結束标志。
07行:聲明主函數main()。這裡的主函數不需要參數,也不傳回函數值。
08行:主函數的開始标志“{”。
與01行的Delay()延時子函數一樣,習慣上也會把下一行的語句與本行的花括号寫在一起。
09行:聲明一個無條件for()循環,“;;”以使單片機重複執行任務,使流水燈能不停地流動。
10行:大括号表示09行for()循環的開始,語句“Pl_0=0”是讓單片機Pl口的O号引腳(即Pl.0)輸出低電平,根據電路可知,此時LED1會被點亮。
11行:以參數值1000調用01行聲明的Delay()延時子函數,使程式運作到此處時,延時1000毫秒(即1秒)。
12-41行:與10、11行的作用相同。
簡而言之,10-41行的作用就是依次點亮LEDl-LED8這八個發光二極管。
42行:09行結束标志,程式運作到此處時,自動傳回09行,因為09行的for()循環是無條件循環,是以程式馬上會轉到10行繼續運作。
三、軟體仿
真首先按照前面的方法建立一個新的工程,并把上面的程式按照前面的方法輸入并存盤。然後按照下面的方法進行仿真調試。
1.把建立好的C程式加入工程
輕按兩下左邊工程視窗中的“Target1”,展開“Target1”夾,然後右擊“SourceGroupl”,選擇“增加檔案到組‘SourceGroup1’(AddFilestoSourceGroup1)”,并把剛才輸入的C程式加入到工程中。
2.連編目标程式
連編之前要設定目标的輸出屬性,否則連編出來的目标程式中不含有用于固化到單片機中的十六進制檔案。
設定目标輸出屬性的方法是:
先單擊工程視窗中的“Target1”以選中它,然後選擇“工程”菜單中的“目标‘Targetl’屬性(OptionsfortargetTargetl)”,系統彈出對話框,在對話框中選擇“輸出(Output)”頁籤,并選中“生成HEX檔案(CreateHEXFile)”選項(生成十六進制檔案),當然,如果你的單片機程式設計器不支援十六進制檔案的話,就要用轉換軟體把生成的十六進制檔案轉換成二進制了。
設定好目标屬性後,按“F7”開始連編目标程式。連編的結果資訊會在輸出視窗中顯示出來,若顯示“0錯誤(s),0警告(s)(0Error(s),0Warning(s))”表示連編成功,否則說明連編不成功。若連編不成功,在輸出視窗中會顯示錯誤所在行及錯誤原因,然後根據具體的錯誤進行修改,修改完成後,再次連編,直到連編成功。
3.仿真調試
連編好目标程式後就可以開始仿真調試了,其步驟是:
1)選擇“調試(Debug)”菜單中的“開始/停止調試(Start/StopDebugSession)”,進入仿真調試狀态。
2)選擇“外圍裝置(Peripherals)”菜單中的“I/OPorts“選項中的“Port1”,打開I/O口狀态模拟器。狀态模拟器中的“&raDIC;”表示相應的I/O口引腳狀态為“1”電平狀态。
如:圖中表示Pl口(Portl)的8個引腳全為“1”電平狀态。
3)按“Fll”進行單步跟蹤調試。每按一次“Fll”,程式會執行一步(即一條語句),若程式的執行影響了I/O口的狀态,在I/O口狀态模拟器上會有相應的顯示。因為每按Fll一次,程式隻執行一步,是以在調試循環程式時,可能會有很多的步數,如本例中每調試一次Delay()子函數中的兩個循環,其步數高達六萬步,是以要設法減少步數,本例中可先将Delay()子函數的參數值由1000改為1,等調試成功後再改回1000,這樣就可以大大減少循環步數。
4)再次選擇“調試(Debug)”菜單中的“開始/停止調試(Start/StopDebugSession)”,退出仿真調試狀态。
四、程式固化
當程式通過了仿真調試,就可以利用程式設計器把它固化到單片機,并插入做好的線路闆上,欣賞你的勞動成果了。