通俗易懂講PIC單片機:從一竅不通到入門(mén)進(jìn)步
客觀(guān)運行的結果是 GP1管腳電平不停地一會(huì )高,一會(huì )低, 就輸出了方波信號.
本文引用地址:http://dyxdggzs.com/article/201803/376687.htm要計算方波的頻率,我們必須知道單片機每運行一條指令需要多少時(shí)間.這個(gè)時(shí)間的單位不以通常的秒 毫秒 或微秒作為單位, 而是以”機器周期” 為單位. 以后凡是我們討論單片機內部的時(shí)間問(wèn)題都要以機器周期作為時(shí)間單位. 至于一個(gè)機器周期究竟是多少微妙或毫秒, 取決于單片機的品牌和振蕩頻率頻率大小, 等一會(huì )我們再用公式計算我們PIC12CE512在4MHz震蕩頻率下的機器周期是多少個(gè)微妙。
我們先看看我們的程序中GP1腳的高電平低電平都是用了多少個(gè)機器周期.
PIC單片機所有指令都是單機器周期的指令,
例外的情況是goto 語(yǔ)句要用2個(gè)機器周期 還有一個(gè)call指令用的時(shí)間也不完全是一個(gè)機器周期(待后續)
其他品牌的某些單片機可不是這樣,一條指令往往要用幾個(gè)周期……
從bsf 到bcf有8個(gè)指令,都是單周期指令,所以GP1高電平時(shí)間長(cháng)度是8個(gè)機器周期
從bcf 到bsf有7條指令,其中6條是單周期指令 1條雙周期指令(goto). 所以GP1低電平時(shí)間長(cháng)度也是8個(gè)機器周期
這樣,我們輸出方波的周期長(cháng)度就是16 個(gè)機器周期.
Pic品牌的機器周期 = 4/振蕩頻率 (公式)
所以,在我們的例子當中 1個(gè)機器周期=4/4MHz= 1 uS
也就是說(shuō),我們的例子中,執行一條指令僅需要1微秒的時(shí)間.
這樣,我們輸出的方波周期就是16微秒, 頻率是 f =1/16 =0.0625 兆赫 =62.5 KHz
如果這個(gè)方波的頻率比較低,你再接一個(gè)揚聲器到GP1腳上你就可以聽(tīng)到聲音了
頻率降低到幾赫茲的時(shí)候, 接一個(gè)led燈, 就會(huì )不停的閃爍.
當然, 頻率太低你用的nop指令的數目會(huì )很多,程序雖簡(jiǎn)單但是臃腫, 這沒(méi)有關(guān)系,我們主要是在學(xué)習程序, 弄清楚道理是目的。
要想使得程序不臃腫我們有的是辦法,這就必須再學(xué)習新的指令.
如果此前我講的你基本都弄明白了,那你現在已經(jīng)抓住單片機入門(mén)的門(mén)把手了, 還需輕輕的推開(kāi).
當你坐在家里吃著(zhù)月餅,愜意地用電視遙控器選擇電視頻道,不停地用 +/- 鍵盤(pán)調節電視音量到合適的時(shí)候,你可曾想過(guò),此時(shí)嶗山也許正鉆在在溫度高達35攝氏度以上的樹(shù)叢里,忍耐蚊子螞蟻的叮咬,研究用什么樣的通信線(xiàn)更好地防止雨水侵蝕和動(dòng)物的啃咬。
也許你從沒(méi)有留意你按下的節目頻道、音量等這些 標有 + / - 符號的鍵盤(pán)是怎樣工作控制大小的。
下面我們學(xué)習兩個(gè)新指令 incf 和 decf ,它們都是對某一個(gè)寄存器進(jìn)行增1 或減1 操作,例句中假如我們要操作的寄存器是 09H
movlw 02H '常數2進(jìn)入W
movwf 09H '把w 內的數2 復制到09H 這個(gè)寄存器
'現在09H 寄存器內存儲的數是2
incf 09H '寄存器09H內存儲的數 增加1
'現在09H內存儲的數變成3
decf 09H '寄存器09H內存儲的數 減掉1
'現在09H內存儲的數變成2
movlw 0FFH '常數255進(jìn)入W
movwf 09H '把w 內的數255 復制到09H 這個(gè)寄存器
'現在09H 寄存器內存儲的數是255
incf 09H '寄存器09H內存儲的數 增加1
'現在09H內存儲的數變成0
decf 09H '寄存器09H內存儲的數 減掉1
'現在09H內存儲的數又變成255
如果你事先定義好了地址為09H 的這個(gè)寄存器里存儲的數字大小,代表電視機節目頻道的話(huà),你會(huì )很喜歡這兩個(gè)指令的。并且當節目頻道到達最大值255 或最小值0的時(shí)候無(wú)需擔心,寄存器在0時(shí)減1 會(huì )得255, 255狀態(tài)下增1 會(huì )得0
至于為什么會(huì )這樣,學(xué)過(guò)環(huán)形計數器的人不會(huì )感到奇怪的。你要是沒(méi)有學(xué)過(guò)計數器電路也不要緊,記住一個(gè)寄存器的最大存儲數值是255 = 0FFH 就可以了,加減法都會(huì )導致它“進(jìn)位”
當然控制音量時(shí)這個(gè)程序不能使用,因為它在0和255之間變化,音量忽大忽小怎們行。
為解決這個(gè)問(wèn)題, 我們必須再學(xué)習兩條指令 incfsz 和 decfsz
它們與上兩個(gè)功能基本相同,不同的是: 寄存器增1 或減1操作以后,該指令會(huì )自動(dòng)判定寄存器內的結果是否為零,如果不為零,繼續正常執行該指令后面的語(yǔ)句. 但如果結果為零的話(huà),則程序會(huì ) "跳一步" .繞過(guò)緊挨著(zhù)它下面的一條指令,繼續執行更下面的語(yǔ)句,舉例子說(shuō)明
假定我們操作的寄存器還是09H:
movlw 0FDH '常數253進(jìn)入W
movwf 09H '把w 內的數253 復制到09H 這個(gè)寄存器
'現在09H 寄存器內存儲的數是253
incfsz 09H '寄存器09H內存儲的數 增加1,結果變成254 結果不等于0,故程序繼續執行下一指令
nop '該句得到執行(因為上一句寄存器09H的計算結果不等于0)
incf 09H '寄存器09H內存儲的數 增加1,結果是255
incfsz 09H '寄存器09H內存儲的數 增加1,結果變成0
'因為結果等于0,故程序要跳過(guò)下面的一句(不運行下面的一句).
incf 09H '由于上一句的存在并結果為0,該句得不到執行,被忽略
incf 09H '程序跳入這一句繼續運行 寄存器09H內存儲的數 增加1
nop '因此現在 09H寄存器存儲的數是1
nop '繼續運行
.
.
.
.
.
思考題:設計一段程序代碼,當用戶(hù)連續按下音量減小鍵后,判定音量寄存器09H的存儲音量數值,
防止該寄存器的值從0 變成255,以免震驚到用戶(hù)。
.
.
.
.
SMALL_SOUND: nop '標號可以任意寫(xiě)的,此前用戶(hù)一旦按下音量減,就把程
' 序引導到這一句上來(lái)
decfsz 09H '寄存器09H內存儲的數 減1,如果結果為0 就跳一步
goto OK '如果上一句結果不為0,執行該句后,程序去了ok語(yǔ)句
movlw 01H '跳到這一步說(shuō)明寄存器結果是0
movwf 09 '強行把 09H內的數值寫(xiě)成1,仍然是小音量,這樣音量不會(huì )被因為 減小而變成255
OK: nop '繼續運行
.
.
思考題:利用decfsz 指令設計一段延時(shí)代碼,使得延時(shí)時(shí)間可以在10個(gè)機器周期到65535個(gè)機器周期之間,
可以通過(guò)程序任意控制
在這個(gè)例子中,設我們要控制的延時(shí)時(shí)間大約是24086個(gè)及其周期,用16進(jìn)制表是就是 5E16 H.
如果用到通用寄存器,請使用 0AH, 0BH
yanshi: movlw 5EH ' 常數5E進(jìn)W 標號是延時(shí)
movwf 0BH , '0B寄存器數為5EH
movlw 16H '常數16進(jìn)W
movwf 0AH '0A寄存器數為16H
jixu: decfsz 0AH '0A寄存器內的數減1,如果結果為0跳步
goto jixu '結果不為0,繼續
decfsz 0BH '0B寄存器內的數減1,如果結果為0跳步
goto jixu '結果不為0,繼續
nop '延時(shí)完畢
.
.
.
.
你現在可以只用這幾個(gè)簡(jiǎn)單句子完成任意時(shí)間的延時(shí)程序了。
下面介紹單片機匯編語(yǔ)言里的一個(gè)概念 “子程序”
下面我介紹 “子程序”
我先打個(gè)比方,如果你做一頓飯,要做湯,炒菜,燉魚(yú),汆丸子, 奧,忘了還有炒小螃蟹(大螃蟹現在都叫人吃的逮不著(zhù)了:))期間有一個(gè)動(dòng)作在我看來(lái)不斷的重復,這個(gè)動(dòng)作就是放鹽 放鹽的過(guò)程描述是這樣的:
放鹽: 用一把小勺子深入鹽罐
舀出氯化鈉適量 。
把小勺子里的氯化鈉
均勻灑在鍋里。
完畢
如果我們把做飯定義為主任務(wù) 那么放鹽這個(gè)動(dòng)作就叫做 子任務(wù)。
這樣定義的一個(gè)好處就是描述主任務(wù)的時(shí)候比較方便,當你用語(yǔ)言文字描述主任務(wù)的時(shí)候,無(wú)論哪一道菜,到了該加鹽的時(shí)候不必細說(shuō)用一把小勺子深入鹽罐...... 因為很多菜都有同樣的這個(gè)過(guò)程,所以,你用 “放鹽” 兩個(gè)字就可以了。但是在你使用 放鹽 這個(gè)詞之前或者之后,你應該解釋一下放鹽 這個(gè)詞的具體過(guò)程是什么。
我們單片機的程序也是一樣的,如果你設計一個(gè)電視機的自動(dòng)搜索頻道的程序,程序要求電視機每搜索成功一個(gè)頻道,它面板上的發(fā)光二極管就眨一次眼睛,也就說(shuō),先熄滅一段時(shí)間然后再點(diǎn)亮。這樣就會(huì )遇到很多這樣的眨眼動(dòng)作,為了簡(jiǎn)化主程序我們可以把眨眼這樣一個(gè)過(guò)程定義為一段子程序,以后每次遇到需要眨眼的時(shí)候就調用一次子程序就可以了。
子程序的定義是這樣的
Zhayan: bcf GPIO,GP1 '管腳GP1輸出低電平關(guān)閉LED燈 做為子程序標號是必須有的 標號
' 就是子程序的名字
nop
nop
nop
nop
nop
... .
bsf GPIO,GP1 '管腳GP1輸出高電平點(diǎn)亮LED燈
nop
nop
nop
nop
...
return '這個(gè)命令表示子程序的結束 是必需的 否則這個(gè)子程序沒(méi)有結束
這樣,子程序就定義完了 如果想在程序的某個(gè)位置需要led燈熄滅以下(眨眼一次),只需在那個(gè)程序位置調用一下子程序就可以了。
調用的方法是用 call 命令。
主程序:
.... '這些點(diǎn)點(diǎn)表示主程序里的語(yǔ)句
....
......
...... '這個(gè)位置搜所成功一個(gè)臺 需要“眨眼”一次
call Zhayan
...... '繼續搜索下一個(gè)臺的命令行
......
......
......
...... '這個(gè)位置搜所成功一個(gè)臺 需要“眨眼”一次
call Zhayan
...... '繼續搜索下一個(gè)臺的命令行
......
......
...... '這個(gè)位置搜所成功一個(gè)臺 需要“眨眼”一次
call Zhayan
...... '繼續搜索下一個(gè)臺的命令行
......
疑問(wèn)1 我在一個(gè)主程序里固然可以調用另一個(gè)子程序,而我在一個(gè)子程序里能不能調用另一個(gè)子程序?
答 可以的,這叫子程序嵌套,甚至還可以在另一個(gè)子程序中再繼續調用別的子程序。
疑問(wèn)2 嗯,那繼續往下調用下去,有限制么?
答 有,這叫允許嵌套的層數 每個(gè)品牌 型號的單片機允許的嵌套層數都是有規定的 例如pic16f74 允許8層
pic12e519 允許兩層 也就是說(shuō)pic12e519的主程序里可以調用子程序,子程序里??梢栽僬{用子程序,到此為止不要再往下調用 了,否則程序報錯或者超出你預計的結果。
疑問(wèn)3 在同一層程序空間里,例如在我的某個(gè)子程序之中,調用另一個(gè)子程序的次數有限制么?
回答 沒(méi)有限制,只要你的程序寄存器裝得下你的程序。
疑問(wèn)4 我聽(tīng)說(shuō)單片機在調用子程序以前,好像需要程序“堆?!痹L(fǎng)問(wèn)什么的,要進(jìn)行一些程序計數器的保存保護,以保證子程序返回來(lái)得時(shí)候,程序能夠正確回到原來(lái)位置和環(huán)境。是這樣的么?
答 pic單片機不用管這些問(wèn)題,它是硬件自動(dòng)完成這些堆棧的事情,我們的指令里不用關(guān)心這些。盡管如此,中檔pic單片機的例如 pic16等系列,它們的程序存儲器地址是分頁(yè)的,盡量調用本頁(yè)的子程序,如果子程序不在本頁(yè),而是在另一個(gè)頁(yè)面里存放,你還是要告訴單片機你的子程序所在的頁(yè)面數據的,具體操作指令可以查相關(guān)指令說(shuō)明。我們的pic12c519的程序存儲器,沒(méi)有分頁(yè),不用關(guān)心這事。
繼續講
我們學(xué)習到這里,就已經(jīng)初窺門(mén)庭了,下一步還有一個(gè)重要的關(guān)口-------中斷
單片機的中斷,概念并不難以理解。只是要真正理解運用編程處理一些實(shí)際中斷的例子,卻也不是很容易,甚至是單片機學(xué)習、入門(mén)的攔路虎。要想學(xué)會(huì )實(shí)際的中斷處理編程,也還需要清楚一些程序存儲器,程序結構,程序計數器,硬件堆棧,現場(chǎng)保護等這些個(gè)另雜碎概念。
因此,我們在學(xué)習中斷以前,以后和學(xué)習中斷過(guò)程中,都有必要介紹回顧復習一些有關(guān)上述關(guān)鍵詞的概念和知識,否則,盡管你學(xué)了中斷,用起來(lái)可還是不能得心應手,以至于茫然。
我還是用比喻的方法介紹一下中斷的概念:
你的主程序任務(wù)是做一桌可口的飯菜,期間可能要多次調用子程序“撒鹽”。
盡管子程序下邊還有更小的子任務(wù),比如“計算食鹽的量”等過(guò)程,盡管這些子過(guò)程很復雜,但他們的出場(chǎng)時(shí)間和順序是可以預料的,是可以預先安排的。也就說(shuō)你肯定知道在什么時(shí)候放鹽。
有一類(lèi)子程序,他的出場(chǎng)時(shí)間是不確定的,突然的,處理他們的時(shí)間刻不容緩,必須趕緊的。我們稱(chēng)這一類(lèi)子程序為 中斷子程序。 也就是我們所說(shuō)的 中斷
你正在做菜的過(guò)程中,隔壁鄰居小孩突然敲門(mén)說(shuō) 他的二大爺在他房間里摔倒了 請你幫忙把二大爺扶起來(lái)。這是急迫的,必須處理的事務(wù)。
你肯定關(guān)掉爐子一溜煙跑出去幫忙,等回來(lái)以后再點(diǎn)著(zhù)爐子繼續做菜。
這個(gè)事件的特點(diǎn)就是發(fā)生的時(shí)間你無(wú)法預先知道,而這個(gè)任務(wù)必須得停下當前工作去處理,并且是刻不容緩。
從開(kāi)始關(guān)爐子到回來(lái)點(diǎn)著(zhù)爐子的這段時(shí)間里以及你的救人行為,就叫做 “中斷子程序”。
在中斷子程序過(guò)程中,你關(guān)爐子的動(dòng)作,叫做“中斷現場(chǎng)保護” 點(diǎn)著(zhù)爐子叫做“中斷現場(chǎng)恢復”中間走出去扶起隔壁二大爺到回來(lái) 叫做“中斷任務(wù)處理”
小孩子敲門(mén)就叫做“中斷請求”
這就是中斷的基本概念。
在單片機里,中斷的例子也是很多的。我舉一個(gè)你手里的手機的例子,你的GSM手機正工作在賦閑,屏幕上也就顯示個(gè)時(shí)間日期中國電信什么的,表面看沒(méi)有什么。其實(shí)它內部的cpu高速運行忙碌地工作在諸如聯(lián)絡(luò )無(wú)線(xiàn)網(wǎng)絡(luò ),查詢(xún)是否有短消息發(fā)來(lái),計算當前信號強度,時(shí)間等任務(wù)中。
你突然按下數字鍵“8”,此時(shí)內部cpu必須停下它正在干的工作來(lái)應付你,也就是清屏,顯示你按下的數字8,然后再回到它原來(lái)的任務(wù)接著(zhù)運行。(當然,這個(gè)例子不一恰當,現在有操作系統Windows-ce windows-mobile的手機的工作機制遠沒(méi)有如此的簡(jiǎn)單)
下面我們要接觸和復習一些另雜碎,學(xué)習中斷必須要弄明白單片機這些另雜碎,所以你還得忍耐他們一陣子。
再說(shuō)這不是教材,只是想為入門(mén)學(xué)習指劃個(gè)門(mén)徑,我的帖子里面有很多細節錯誤,例如內存頁(yè)面問(wèn)題,519也是分頁(yè)的。
但為了入門(mén),我們還是不先不要理會(huì )這些,等入門(mén)以后,還有很多細節需要搞明白,那時(shí)候就容易啦。
這不,我也是現學(xué)現賣(mài),在想寫(xiě)個(gè)具體中斷代碼的例子的時(shí)候,才現行的查閱了pic12f519 的數據手冊,竟然沒(méi)有查到中斷方面的說(shuō)明,感情這款芯片沒(méi)有中斷的功能!不會(huì )是我英文水平低沒(méi)有看懂吧,又拿出來(lái)中文的,同樣的,程序存儲器里沒(méi)有中斷說(shuō)明,只有復位(復位也是單片機的概念) 。
總之,我們學(xué)習中斷代碼,這款芯片不適合我們啦。
怎么辦?只好換一款中檔的型號:PIC16C74. 那位說(shuō)從低端芯片一下子到中端芯片跨度太大啦吧,能適應嗎。我回答:肯定能!
高端芯片無(wú)非腿腳更多,片內資源也多,但是原理和方法,和低端的沒(méi)有區別。我們只要掌握了單片機的使用操作方法入門(mén),慢說(shuō)中檔,就是高端芯片pic18、24、99999 系列,那也是一樣。我們仍然可以鉆進(jìn)去,出得來(lái)。
其實(shí)啊,所謂高端的語(yǔ)句,學(xué)起來(lái)更簡(jiǎn)單和使用起來(lái)更方便。要實(shí)現同樣功能,如果限定僅使用低端35條,反而會(huì )比較羅索。
下面以 PIC16C74 這款芯片為例,仍然不出35條基本指令,寫(xiě)出一個(gè)完整的中斷代碼的例子,注意這個(gè)例子程序的總體結構。題目要求:
1、當一個(gè)鍵盤(pán)按動(dòng)一下后,中斷主程序,改變某管腳上的一只LED燈的狀態(tài),如果再次按動(dòng),再次改變。
2、主程序實(shí)際上和我們的中斷任務(wù)處理沒(méi)有關(guān)系,我們可以隨便寫(xiě)個(gè)任務(wù),例如主任務(wù)程序是計算:123 + 45 = ?
在這個(gè)例子里,計算123 + 45 = ?相當于我們在做菜,突然有人按動(dòng)按鍵,相當于小孩子敲門(mén)請求中斷,那么改變(點(diǎn)亮或者熄滅)某管腳上的一只LED燈的狀態(tài),就是我們刻不容緩的拯救行動(dòng)。
為了理解中斷代碼,我們先看看硬件設計,下面是這個(gè)例子的電路圖。(缺)
如圖:11、12 管腳接電源和地線(xiàn),13、14管腳接振蕩器, 管腳 1 是復位管腳,只要它是高電平,程序就運行,只要是低電平,程序就馬上停止,并回到程序特定的開(kāi)始位置,也叫做“復位”
我們真正用到的是 管腳40 名字叫做 RB7 接一個(gè)鍵盤(pán)??梢钥闯?,該腳平時(shí)為高電平,一旦有人按下鍵盤(pán),就會(huì )變成低電平,從而導致主程序發(fā)生中斷。它是作為輸入 I 使用。
管教27 控制一個(gè)發(fā)光二極管,輸出高電平點(diǎn)亮。 它是作為輸出管腳.
剩下的那些管腳,先不管,實(shí)際使用的時(shí)候懸空好了。
根據我們以前所學(xué),主程序和子程序已然明了。在以前的程序中,凡是涉及專(zhuān)用寄存器如 GPIO 或者通用寄存器如的時(shí)候,
我都是在程序注釋里說(shuō)明該符號如GPIO 、020H,是一個(gè)寄存器的地址。這里有一個(gè)差別,特殊寄存器都是用字符串表示,而通用寄存器使用它的地址數表示。這樣做主要是為了便于理解寄存器的本質(zhì)和使用。
事實(shí)上,通用寄存器也是可以用字符串來(lái)表示的,并且在實(shí)用的程序里往往是用字符串表示通用寄存器,而不是直接用它的地址,因為用字符串更能明確這個(gè)通用寄存的用途性質(zhì)。僅用地址數是允許的,但是通用寄存器一旦多起來(lái),連程序作者自己也搞不清楚哪一個(gè)是干什么用的了。
為了便于程序理解,閱讀,容易編寫(xiě)。允許程序作者給通用寄存器 例如020H 起用一個(gè)漂亮直接的字符串名字。 我們來(lái)學(xué)習一個(gè)嶄新的語(yǔ)句 EQU
我們看幾個(gè)例子:
BeijiaShu EQU 020H '定義字符串 BeijiaShu 的值是數字 020H
'此前或者此后的程序代碼中, 只要遇到 BeijiaShu 就可以用數字 020H取代
'盡管BeijiaShu也可以寫(xiě)在一行的最左頂格,但是別用冒號,它不是程序標號
有了上述的語(yǔ)句,下列語(yǔ)句
MOVLW 123H
MOVWF 020H
就完全可以寫(xiě)成
MOVLW 123H
MOVWF BeijiaShu
程序中下列兩組語(yǔ)句是等價(jià)的,相同的意義。這樣,所有的通用寄存器都可以有自己的名號可以使用了。
新語(yǔ)句中的 EQU 不屬于35條指令里面的,因為它在單片機運行的時(shí)候,不能被執行,也不會(huì )占用單片機里的程序存儲空間。
僅僅是為了方便我們人類(lèi)閱讀、編寫(xiě)源程序程序而起的代號,事實(shí)上,有了EQU指令,家用電腦在把我們編寫(xiě)的源程序“翻譯”成單片機能夠執行的機器碼的時(shí)候,還徒然增加了編譯的工作量,不利于提高編譯速度。
因此,它也不是十分必須的語(yǔ)句,你如果記憶力好,對每個(gè)通用寄存器的地址你自己設計成什么用途了,都能夠記住,完全可以不必多此一舉的使用什么符號常數。話(huà)又說(shuō)回來(lái),誰(shuí)有那么多多余的精力去記憶枯燥的地址數據呢。
象這樣不能被單片機執行,僅僅能幫助我們編寫(xiě)閱讀源程序方便、或者僅僅有助于輔助家用電腦編譯源程序而設立的指令,叫做單片機的“偽指令”
從理論上來(lái)說(shuō),幾乎所有偽指令都不是必須的,都是可有可無(wú)的,都能夠用我們的35條指令就可以完成任務(wù)的。只是,那樣的話(huà)我們的35條使用起來(lái)比較麻煩和不太方便甚至還需要增加額外的計算我們的程序所存在的地址等等工作量。
有了這些個(gè)偽指令,我們編寫(xiě)程序就會(huì )省卻許多的麻煩,例如:
此前的例子中用到了許多行 NOP空操作指令,假如某段代碼需要連續500行NOP語(yǔ)句,即便拷貝也是個(gè)大麻煩,
那么有一款或者兩款偽指令,只需要說(shuō)明你的行編輯重復次數以及行編輯重復的代碼是NOP 就足夠了,
編輯上看上去也就是幾行的樣子,實(shí)際家用電腦在編譯生成單片機的實(shí)際執行碼的時(shí)候,會(huì )自動(dòng)添加500行NOP指令,單片機里面的程序存儲空間,也是相應的增加等量500行代碼的空間,那是一點(diǎn)也不能節約出來(lái)的。
一句話(huà):偽指令和我們此前講的 單引號 ’ 后面的程序注釋類(lèi)似,共同點(diǎn)是都不被單片機執行,也不會(huì )占用單片機內部的程序存儲資源,都是幫助人們閱讀和編寫(xiě)的方便。不同點(diǎn)是:偽指令要干預家用電腦對源程序的編譯,而單引號則不會(huì )。
由此看,初學(xué)入門(mén)不宜在偽指令上徘徊,老手則是善于運用偽指令圖個(gè)編程快捷簡(jiǎn)便。
下面我們編寫(xiě)我們的中斷例子,并且作為文本文件來(lái)處理看待。匯編語(yǔ)言主程序文件的擴展名稱(chēng),是匯編系統已經(jīng)規定好了的,必須使用 *.ASM
例如:可以為: Shan_LED.ASM
用記事本新建一個(gè)文件,文件名稱(chēng)請使用例子 Shan_LED.ASM 文件內容如下
BeijiaShu EQU 020H '被加數
JiaShu EQU 021H '加數
HE1 EQU 022H '第一算式的和
HE2 EQU 023H '第二算式的和
盡管如此,初學(xué)者,有四個(gè)偽指令需要認識,一個(gè)是EQU 已經(jīng)認識過(guò)了。如果需要的 EQU 的行很多,例如我們的主程序中要用到 被加數、加數、計算結果的和 以及第一個(gè)算式的計算結果寄存 以及第二個(gè)算式的計算結果暫存:
那么,下一步,就是要核計整個(gè)程序的結構,如果從程序的用途屬性,程序存儲區域等角度來(lái)看,存儲來(lái)區分一個(gè)典型的程序結構例子要包含主程序,子程序,中斷子程序,和偽指令說(shuō)明程序。
以往教材,在教導程序結構的時(shí)候不是這么分類(lèi),而是大談特談什么循環(huán)結構,分支結構,遞歸結構,函數調用等等,先把學(xué)生搞暈再說(shuō),我認為那些屬于程序技巧,是用,是末,理應排在以后的技巧升級后去研究。按照上述分類(lèi)才是程序之本體,是入門(mén)的必然門(mén)徑。
有四個(gè)偽指令需要認識的,我們已經(jīng)學(xué)會(huì )一個(gè) EQU,另外3個(gè)隨著(zhù)我們講解這個(gè)中斷例子添加。再看看 ORG 偽指令
ORG 00H '這是個(gè)偽指令,強調以下的源程序代碼在存儲到單片機的時(shí)候,
'被存儲在單片機程序存儲器的 00H位置,也就是開(kāi)始的位置
NOP '這個(gè)才是真實(shí)的第一條可執行單片機指令,它被存儲在程序存儲器的 0000H位置
NOP '該指令沒(méi)有用ORG指令規定位置,只好按照默認的順序 被存儲在 0001H
GOTO MAIN '順序存儲位置 002H 無(wú)條件挑轉到標號 MAIN的地方。
'0003H這個(gè)地方?jīng)]有任何語(yǔ)句,是個(gè)空洞,不被執行
'空洞在家用電腦編譯器編譯的時(shí)候,實(shí)際上也會(huì )被給出一個(gè)特定的數據存儲到0003H
'這個(gè)特定數據是什么是無(wú)所謂的,不同廠(chǎng)家的編譯器會(huì )給不同的特定數
'特定數例如:NOP MOVLW等一般為可執行數據,以免萬(wàn)一單片機誤入空洞,也能工作,不出錯
ORG 04H
GOTO INTSRV '由于上鄰的ORG 04H的存在,該句會(huì )被存儲到程序空間 0004H , 無(wú)條件轉向標號 INTSRV
NOP '按照默認順序編譯存儲到 0005H
NOP '按照默認順序編譯存儲 直到遇到下一個(gè)ORG命令,才會(huì )打破順序
學(xué)會(huì )ORG命令以后,就可以把整個(gè)源程序安排到單片機的程序存儲器位置上,我們習慣叫做程序存儲器地址。PIC12F509的片內程序存儲器只有1024個(gè)單元行,地址從 0000H ---- 03FF H 而PIC16C74的片內程序存儲器有4096個(gè)單元行。
整個(gè)程序存儲器 有幾個(gè)位置(地址)需要特別介紹,那就是復位地址0000H 和 中斷入口地址 0004H。
0000H是 PIC單片機程序存儲器的第一行,通電后首先執行這一行的指令。等于是單片機工作的開(kāi)始位置。
通電后后也許需要單片機多次重新開(kāi)始工作,例如一臺電子稱(chēng)通電以后,可能需要稱(chēng)若干次物品的重量,那么,每換一次物品,單片機就需要重新回到 0000 H這個(gè)指令上來(lái),開(kāi)始新一輪的測量。只要單片機的指令,回到了 0000 H, 我們就成為單片機復位。
中斷入口地址是怎么回事情呢?
原來(lái)啊,我們的主程序和調用的子程序已經(jīng)很完美了,如果小孩子不敲門(mén),或者在本例子里 那個(gè)鍵盤(pán)永遠也不按下的話(huà),是不會(huì )發(fā)生中斷的,我們的程序也就不會(huì )跳出我們事先設計的主程序和子程序那些事情。
可是,一旦發(fā)生了按鍵事件,此時(shí)程序會(huì )暫時(shí)記住當前位置,轉而去進(jìn)行中斷服務(wù),去哪里服務(wù)呢?就是強行把程序指向 0004H 這個(gè)特殊地址,然后從0004 H開(kāi)始進(jìn)行中斷的服務(wù)處理,因此我們設計的中斷撒鹽 或者開(kāi)關(guān)LED燈的一些程序,就必須從0004H這個(gè)位置開(kāi)始。因此 0004H就叫做中斷入口 或者叫中斷入口地址。
不同型號的單片機中斷入口地址不一定都是 0004H, 就我們的例子PIC16C74是這樣的,并且就這一個(gè)入口,因此中斷程序較簡(jiǎn)單,而別的型號則不一定,需要查手冊,如 PIC18F452就有兩個(gè)中斷入口,地址0008 H 以及 0018H
評論