新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 慎用51單片機中的RET指令

慎用51單片機中的RET指令

作者: 時間:2016-11-20 來源:網絡 收藏
題目:已知有四個按鍵依次連接單片機中的P3口的0到3的IO口,有四個LED燈連接P1的0到3 IO口,寫一程序,滿足以下條件:當按下按一個按鍵,對應的LED會發(fā)亮,比如

按下P3.0的按鍵,連接P1.0的LED就發(fā)亮。y

本文引用地址:http://m.butianyuan.cn/article/201611/318611.htm

以下是我同學編寫的程序:

org 0000h
mov P1,#0ffh
loop:
jnb P3.0,led1;*
jnb P3.1,led2;*
jnb P3.2,led3;*
jnb P3.3,led4;*
ljmp loop
led1:
clr P1.0
ret
led2:
clr P1.1
ret
led3:
clr P1.2
ret
led4:
clr P1.3
ret
end

程序的意圖是,制造一個死循環(huán),不斷檢查按鍵是否按下,如果按下,就令對應的燈亮。程序經過測試,能夠滿足題目的要求。

但是,問題出現(xiàn)在上面帶*號的那一部分代碼,程序意圖是想要當P3的某個位為0的時候,就調用LED燈的子程序,執(zhí)行CLR P1.0語句,再返回到原來程序調用子程序的地方繼續(xù)執(zhí)行代碼。

我對的子程序的理解是:在一個地方啟動一段代碼,當這段代碼運行完畢之后,就返回到原來的地方繼續(xù)運行剩下的代碼。

那么CPU單片機是如何返回原來的地址的呢?

首先,當程序執(zhí)行到A處進入子程序時,將A的下一個條指令(即PC+2所指的地方)壓入棧中,即將棧指針SP+1,PCL進棧,SP再加1,PCH進棧。

然后,把PC的值改為子程序代碼的入口。

子程序執(zhí)行完畢之后,從棧中彈出原來的PC值,賦值給當前的PC寄存器。


最后,程序返回到原來調用子程序的地方的下一條指令繼續(xù)運行。

(詳細步驟請查看RET和ACALL,LCALL指令)

上面的代碼很明顯想調用一個子程序,但是51單片機中,只有ACALL和LCALL指令會在跳轉前講PC+2值壓棧,其他跳轉指令都不會。

代碼中使用了JNB作為跳轉指令,所以并沒有壓棧,但是當跳轉之后遇到RET,還是一如既往地彈棧,這樣,只有出,沒有進,會導致堆棧不平衡。

但為什么這個程序依然有效呢?

這個因為SP初始指針指向了一個空白的單元(全是0),所以,當遇到RET后,把PC寄存器給初始化,程序由頭開始重新執(zhí)行,陰差陽錯地滿足的題目的要求。

所以RET指令必須和ACALL和LCALL配套使用,才能組成為真正意義上的子程序



關鍵詞: 51單片機RET指

評論


技術專區(qū)

關閉