上一次我們(men) 的程序實在是沒什麽(me) 用,要燈亮還要重寫(xie) 一下片子,下麵我們(men) 要讓燈持續地閃爍,這就有一定的實用價(jia) 值了,比如能把它當成汽車上的一個(ge) 信號燈用了。怎樣才能讓燈持續地閃爍呢?實際上就是要燈亮一段時間,再滅一段時間,也就是說要P10持續地輸出高和低電平。怎樣實現這個(ge) 要求呢?請考慮用下麵的指令是否可行:
SETB P1.0
CLR P1.0 ……
這是不行的,有兩(liang) 個(ge) 問題,第一,計算機執行指令的時間很快,執行完SETB P1.0後,燈是滅了,但在極短時間(微秒級)後,計算機又執行了CLR P1.0指令,燈又亮了,所以根本分辨不出燈曾滅過。第二,在執行完CLR P10後,不會(hui) 再去執行SETB P1.0指令,所以以後再也沒有機會(hui) 讓滅了。
為(wei) 了解決(jue) 這兩(liang) 個(ge) 問題,我們(men) 能做如下設想,第一,在執行完SETB P1.0後,延時一段時間(幾秒或零點幾秒)再執行第二條指令,就能分辨出燈曾滅過了。第二在執行完第二條指令後,讓計算機再去執行第一條指令,持續地在原地兜圈,我們(men) 稱之為(wei) "循環",這樣就能完成任務了。
以下先給出程序(後麵括號中的數字是為(wei) 了便於(yu) 講解而寫(xie) 的,實際不用輸入):
;主程序:
LOOP: SETB P1.0 ;(1)熄滅燈
LCALL DELAY ;(2)延時一段時間
CLR P1.0 ;(3)點亮燈
LCALL DELAY ;(4)延時一段時間
AJMP LOOP ;(5)跳轉到第一句LOOP處
;以下子程序
DELAY: MOV R7,#250 ;(6)
D1: MOV R6,#250 ;(7)
D2: DJNZ R6,D2 ;(8)
DJNZ R7,D1 ;(9)
RET ;(10)
END ;(11)
本例keil工程文件點擊這裏下載 keil單片機,閃爍燈匯編程序
按上麵的設想分析一下前麵的五條指令。
第一條是讓燈滅,第二條應當是延時,第三條是讓燈亮,第四條和第二條一模一樣,也是延時,第五條應當是轉去執行第一條指令。第二和第四條實現的原理稍後談,先看第五條,AJMP是一條指令,意思是轉移,往什麽(me) 地方轉移呢?後麵跟的是LOOP,看一下,什麽(me) 地方還有LOOP,對了,在第一條指令的前麵有一個(ge) LOOP,所以很直觀地,我們(men) 能認識到,它要轉到第一條指令處。這個(ge) 第一條指令前麵的LOOP被稱之為(wei) 標號,它的用途就是給這一行起一個(ge) 名字,便於(yu) 使用。是否一定要給它起名叫LOOP呢?當然不是,起什麽(me) 名字,完全由編程序的人決(jue) 定,能稱它為(wei) A,X等等,當然,這個(ge) 時候,第五條指令AJMP後麵的名字也得跟著改了。
第二條和第四條指令的用途是延時,它是怎樣實現的呢?指令的形式是LCALL,這條指令稱為(wei) 調用子程序指令,看一下指令後麵跟的是什麽(me) ,DELAY,找一下DELAY,在第六條指令的前麵,顯然,這也是一個(ge) 標號。這條指令的作用是這樣的:當執行LCALL指令時,程序就轉到LCALL後麵的標號所標定的程序處執行,如果在執行指令的過程中遇到RET指令,則程序就返回到LCALL指令的下麵的一條指令繼續執行,從(cong) 第六行開始的指令中,能看到確實有RET指令。在執行第二條指令後,將轉去執行第6條指令,而在執行完6,7,8,9條指令後將遇到第10條令:RET,執行該條指令後,程序將回來執行第三條指令,即將P10清零,使燈亮,然後又是第四條指令,執行第四條指令就是轉去執行第6,7,8,9,10條指令,然後回來執行第5條指令,第5條指令就是讓程序回到第1條開始執行,如此周而複始,燈就在持續地亮、滅了。
在標號DELAY標誌的這一行到RET這一行中的所有程序,這是一段延時程序,大概延時零點幾秒,至於(yu) 具體(ti) 的時間,以後我們(men) 再學習(xi) 如何計算。 程序的最後一行是END,這不是一條指令,它隻是告訴我們(men) 程序到此結束,它被稱為(wei) "偽(wei) 指令"。
單片機內(nei) 部結構分析:為(wei) 了知道延時程序是如何工作的,我們(men) 必需首先了解延時程序中出現的一些符號,就從(cong) R1開始,R1被稱之為(wei) 工作寄存器。什麽(me) 是工作寄存器呢?讓我們(men) 從(cong) 現實生活中來找找答案。如果出一道數學題:123+567,讓你回答結果是多少,你會(hui) 馬上答出是690,再看下麵一道題:123+567+562,要讓你要上回答,就不這麽(me) 不難了吧?我們(men) 會(hui) 怎樣做呢?如果有張紙,就不難了,我們(men) 先算出123+567=690,把690寫(xie) 在紙上,然後再算690+562得到結果是1252。這其中1252是我們(men) 想要的結果,而690並非我們(men) 所要的結果,但是為(wei) 了得到最終結果,我們(men) 又不得不先算出690,並記下來,這其實是一個(ge) 中間結果,計算機中做運算和這個(ge) 類似,為(wei) 了要得到最終結果,一般要做很多步的中間結果,這些中間結果要有個(ge) 地方放才行,把它們(men) 放哪呢?放在前麵提到過的ROM中能嗎?顯然不行,因為(wei) 計算機要將結果寫(xie) 進去,而ROM是不能寫(xie) 的,所以在單片機中另有一個(ge) 區域稱為(wei) RAM區(RAM是隨機存取存儲(chu) 器的英文縮寫(xie) ),它能將數據寫(xie) 進去。 特別地,在MCS-51單片機中,將RAM中分出一塊區域,稱為(wei) 工作寄存器區,上麵程序用到的R6,R7就是在這個(ge) 區裏麵,這我們(men) 會(hui) 在第7課有詳細的介紹。其實如果我們(men) 用C語言來寫(xie) 程序的話用根本不用了解工作寄存器這個(ge) 概念了因為(wei) C編譯器會(hui) 自動處理.看上麵的程序如果用c來寫(xie) 就是
#include <at89x52.h>
void DELAY() //延時函數
{ unsigned char i,j;
for(i=0;i<250;i++)
{
for(j=0;j<200;j++);
}
}
void main() //程序從(cong) 這裏開始執行
{
while(1) //這句的作用就是反複的執行下麵這個(ge) {}中包含的4句
{
P1_0=1; //(1)熄滅燈
DELAY(); //(2)延時一段時間
P1_0=0; //(3)點亮燈
DELAY(); //(4)延時一段時間
}
}
在匯編例子中程序是從(cong) 第一條語句開始執行的,而c不同在c語言裏程序是從(cong) main() 這裏開始執行的,關(guan) 於(yu) (1)(2)(3)(4) 這幾句的解釋和上麵的匯編一樣,不再敖述。循環部分這裏是用了一個(ge) while(1) 語句下麵打了一個(ge) 大括號,這樣大括號中的這4條語句就會(hui) 按(1)->(2)->(3)->(4) ->(1)->(2)->(3)->(4) ->(1)->(2)->(3)->(4)……永遠不停的執行下去。這樣燈就會(hui) 持續的亮滅再亮再滅實現了閃爍效果,關(guan) 於(yu) 延時函數下節課再敘。