田邱林
(桂林理工大學(xué)高等職業(yè)技術(shù)學(xué)院,廣西 南寧 530001)
51單片機(jī)指令SJMP $不宜濫用
田邱林
(桂林理工大學(xué)高等職業(yè)技術(shù)學(xué)院,廣西 南寧 530001)
51單片機(jī)的指令SJMP $,是諸如HERE:SJMP HERE的簡(jiǎn)略表示,其目標(biāo)地址即為當(dāng)前地址,相當(dāng)于定義了一個(gè)沒(méi)有退出條件的循環(huán),即所謂“死循環(huán)”,因此,該指令不可濫用。
單片機(jī);微機(jī)控制;指令SJMP $
51單片機(jī)指令SJMP $,是諸如HERE:SJMP HERE的簡(jiǎn)略表示,其目標(biāo)地址即為當(dāng)前地址,相當(dāng)于定義了一個(gè)沒(méi)有退出條件的循環(huán),即所謂“死循環(huán)”。令人詫異的是,這樣一個(gè)麻煩制造者卻在一些51單片機(jī)教材中屢屢現(xiàn)身,從手頭的教材中隨機(jī)抽取幾本,統(tǒng)計(jì)程序示例中指令SJMP $(含AJMP $)出現(xiàn)的頻度,結(jié)果少則5、6處,多的超過(guò)10處,這尚未包括目標(biāo)地址為“$”的條件轉(zhuǎn)移指令。只有厘清指令 SJMP $的作用,才能詮釋使用它的意義。
51單片機(jī)的SJMP rel是一條無(wú)條件短轉(zhuǎn)移指令,偏移量rel是一個(gè)用補(bǔ)碼表示的8位帶符號(hào)數(shù),轉(zhuǎn)移范圍為相對(duì)指令當(dāng)前地址-128~+127的256個(gè)單元,所以也被稱(chēng)作相對(duì)轉(zhuǎn)移指令。當(dāng)rel取值為FEH時(shí),指令可表示為SJMP $,程序就地轉(zhuǎn)入無(wú)條件循環(huán),終止下行。
51單片機(jī)的AJMP addr11是一條無(wú)條件指定頁(yè)轉(zhuǎn)移指令,也被稱(chēng)為絕對(duì)轉(zhuǎn)移指令或短轉(zhuǎn)移指令,addr11提供同一個(gè)2KB頁(yè)范圍內(nèi)的轉(zhuǎn)移空間。當(dāng)addr11指向該指令當(dāng)前位置時(shí),亦可表示為 AJMP $,作用與指令 SJMP $相同,但不如 SJMP $的可讀性強(qiáng)。
相關(guān)教材給出了指令SJMP $的三個(gè)用途,即程序隔離、程序暫停和等中斷。
程序隔離的實(shí)質(zhì),是令程序在即將進(jìn)入非順序模塊前轉(zhuǎn)向,其實(shí)(包括SJMP rel在內(nèi)的)所有轉(zhuǎn)移指令都可以完成程序跳轉(zhuǎn),不必刻意使用SJMP $。
討論程序暫停的意義,不妨看一段引文對(duì)指令SJMP $的描述。
若偏移量rel取值為FEH,則目標(biāo)地址等于源地址,相當(dāng)于動(dòng)態(tài)暫停,程序“終止”在這條指令上。動(dòng)態(tài)暫停指令在調(diào)試程序時(shí)很有用。MCS-51沒(méi)有專(zhuān)用的停止指令,若要求動(dòng)態(tài)暫停可以用SJMP指令來(lái)實(shí)現(xiàn):
HERE:SJMP HERE;動(dòng)態(tài)停機(jī)(80H,FEH)
盡管描述有些混亂,仔細(xì)梳理仍可見(jiàn)端倪。
首先,“MCS-51沒(méi)有專(zhuān)用的停止指令”,堪稱(chēng)一語(yǔ)中的,因?yàn)樵O(shè)計(jì)者壓根沒(méi)打算停機(jī)。自創(chuàng)一條停止指令SJMP $,無(wú)端耗費(fèi)有限的機(jī)器時(shí)間資源,顯然有悖設(shè)計(jì)初衷。
其次,指令SJMP $在終止程序下行后仍允許中斷響應(yīng),這就是“動(dòng)態(tài)暫?!钡挠蓙?lái)。
再者,若無(wú)中斷可響應(yīng),程序被迫“終止”(在 SJMP $上),故而注釋為“動(dòng)態(tài)停機(jī)”,以示有別于“動(dòng)態(tài)暫?!?。對(duì)于這種運(yùn)行狀態(tài),一般PC機(jī)用戶(hù)更習(xí)慣直呼為死機(jī)。
至于“動(dòng)態(tài)暫停指令在調(diào)試程序時(shí)很有用”,則屬于套用PC機(jī)的概念,意指借指令JMP $(罕用,常用WAIT和DEBUG專(zhuān)用指令 HLT)將待調(diào)程序分段調(diào)試。須知,替換 PC機(jī) RAM中的指令易如反掌,單片機(jī) EPROM中的程序卻不允許隨機(jī)刪改。對(duì)于單片機(jī),可自程序分段處跳轉(zhuǎn)至鍵盤(pán)模塊,經(jīng)鍵盤(pán)饋入調(diào)試引導(dǎo)信息,完成調(diào)試后,調(diào)試引導(dǎo)模塊或作為手動(dòng)模塊保留,需要時(shí)經(jīng)由鍵盤(pán)激活。
下面一段引文描述了借指令SJMP $等中斷的過(guò)程。
這是一條死循環(huán)令,如果系統(tǒng)的中斷是開(kāi)放的,那么SJMP $指令實(shí)際上是在等待中斷,當(dāng)有中斷申請(qǐng)后,CPU轉(zhuǎn)至執(zhí)行中斷服務(wù)程序。中斷返回時(shí),仍然返回到這條死循環(huán)指令,繼續(xù)等待中斷,而不是返回到該指令的下一條指令。這是因?yàn)閳?zhí)行SJMP $后,PC仍指向這條指令,中斷的斷點(diǎn)就是這條指令的首字節(jié)地址。
所謂等中斷也套用了PC機(jī)的概念。PC機(jī)可提供多達(dá)256個(gè)32位的中斷矢量,還能擴(kuò)充中斷鏈等硬件予以支持,除去系統(tǒng)占用和保留的之外,可供用戶(hù)靈活使用的依然十分豐富,因此,PC機(jī)的許多功能的確是建立在(包括軟調(diào)用)中斷基礎(chǔ)之上的。相比之下,單片機(jī)區(qū)區(qū)幾個(gè)16位的中斷矢量,即便全部“中斷是開(kāi)放的”也僅能應(yīng)對(duì)少數(shù)緊急事件,主程序仍要承擔(dān)大量常規(guī)操作。設(shè)計(jì)中斷方式的本意,是在滿(mǎn)足實(shí)時(shí)性要求的前提下,使計(jì)算機(jī)仍有充裕時(shí)間處理各種事務(wù),因此,空耗機(jī)器時(shí)間等候中斷實(shí)屬不當(dāng)應(yīng)用。換個(gè)角度來(lái)看,等中斷實(shí)際上改變了中斷的運(yùn)行方式,稍有不慎可能事與愿違。
上述三個(gè)用途缺少中斷配合均意味著死機(jī),所以可歸結(jié)為等中斷,而等中斷終歸不當(dāng)應(yīng)用。
本節(jié)通過(guò)幾個(gè)例子來(lái)考察指令SJMP $的作為。例1.
FW:LCALL DELAY;令電機(jī)正向轉(zhuǎn)動(dòng)300次DELAY子程序的時(shí)間
DJNZ TIME,FW
MOV TIME,#300
SETB IN1
CLR IN2
FAN:LCALL DELAY;令電機(jī)反向轉(zhuǎn)動(dòng)300次DELAY子程序的時(shí)間
DJNZ TIME,FAN
STOP:CLR IN1;令電機(jī)停轉(zhuǎn)
CLR IN2
AJMP $
本例令電機(jī)正反轉(zhuǎn)一次后停轉(zhuǎn)。眾所周知,電機(jī)是反復(fù)運(yùn)轉(zhuǎn)的設(shè)備,本例需要利用中斷服務(wù)程序修改堆棧中的斷點(diǎn),重新指向電機(jī)驅(qū)動(dòng)程序,才能再次啟動(dòng)電機(jī)。本例試圖演繹指令A(yù)JMP $的暫停功能卻落入陷阱,與其借由中斷逃脫束縛,不如直接用中斷方式控制電機(jī)更快捷更可靠。
例2.
LOOP:JNB FO,$;等待計(jì)數(shù)5000時(shí)產(chǎn)生中斷
SETB P1.0;繞線(xiàn)機(jī)停止工作
本例用戶(hù)標(biāo)志 F0未置位時(shí),指令 JNB F0,$執(zhí)行結(jié)果與SJMP $相似。例中注釋表明F0由計(jì)數(shù)器中斷置位,意在強(qiáng)調(diào)等中斷,但之后的指令 SETB P1.0可以被任意中斷,致使部分線(xiàn)包匝數(shù)失準(zhǔn),除非關(guān)閉其余中斷。P1.0和F0都是位名稱(chēng),操作雷同,若P1.0由中斷直接置位,且設(shè)該計(jì)數(shù)器中斷為唯一高優(yōu)先級(jí),則能保證線(xiàn)包匝數(shù)準(zhǔn)確,亦不必等待和限制其他中斷。
例3.
LOOP:JNB TF1,LOOP;查詢(xún)等待
CLR TF1;TF1清零
CPL P1.0;P1.0取反
MOV TH1,#OEOH;重新裝入時(shí)間常數(shù)初值
MOV TL1,#18H
AJMP LOOP;繼續(xù)生成波形本例的LOOP:JNB TF1,LOOP也可以表示為JNB TF1,$,與例2的區(qū)別在于TF1可由硬件直接置/復(fù)位。置位TF1必須啟動(dòng)定時(shí)器T1,但JNB TF1,$是雙周期指令,T1中斷約有半數(shù)機(jī)會(huì)搶先使 TF1硬復(fù)位,導(dǎo)致波形畸變,所以又必須關(guān)閉T1中斷。鑒于例中TF1采用軟復(fù)位,可認(rèn)為T(mén)1中斷已被關(guān)閉,即便如此,仍不能阻止其他中斷干擾定時(shí)器T1重置,波形畸變依舊難免。如果再關(guān)閉其他中斷,則所有中斷均被關(guān)閉,這樣一來(lái),單片機(jī)僅相當(dāng)于一只固定頻率振蕩器。循環(huán)體本質(zhì)屬于子程序,因自動(dòng)就地重復(fù)可免調(diào)用,本例循環(huán)體添一條返回指令即可供T1中斷調(diào)用,若再采用高優(yōu)先級(jí),不但不會(huì)延誤重置,還可取消 TF1軟復(fù)位,也不影響在低優(yōu)先級(jí)下應(yīng)用其他中斷。
例4.
B.查詢(xún)方式
對(duì)于采用查詢(xún)方式時(shí),則需要把EOC與8031一條I/O口線(xiàn)相連。本例中用P1.7邊EOC,因此,8031通過(guò)對(duì)P1.7的狀態(tài)進(jìn)行不斷的查詢(xún),來(lái)判斷 A/D轉(zhuǎn)換是否結(jié)束。實(shí)現(xiàn)中斷方式的具體程序如下:
MAIN:MOV R1,#50H;置轉(zhuǎn)換結(jié)果存放數(shù)據(jù)區(qū)首址
MOV DPTR,#7FF8H;DPTR指向ADC0809的通道IN0地址
MOV R7,#08H;置轉(zhuǎn)換通道數(shù)
LOOP:MOVX @DPTR,A;啟動(dòng)A/D轉(zhuǎn)換
WAIT:MOV A,P1;未轉(zhuǎn)換完,繼續(xù)查詢(xún)
JNB ACC.7,WAIT
MOVX A,@DPTR;讀取轉(zhuǎn)換結(jié)果
MOV @R1,A;轉(zhuǎn)換結(jié)果存入結(jié)果數(shù)據(jù)區(qū)
INC DPTR;指向下一個(gè)通道
INC R1;修改結(jié)果數(shù)據(jù)區(qū)指針
DJNZ R7,LOOP;8路模擬信號(hào)是否都已轉(zhuǎn)換完成?
SJMP $
本例是一段 8通道模擬信號(hào)采樣程序,在順利完成第一次8通道循環(huán)后,遇到SJMP $,難以 “不斷的查詢(xún)”,由于程序未按中斷方式編寫(xiě),也不能“實(shí)現(xiàn)中斷”取值,沒(méi)有后續(xù)檢測(cè)則控制無(wú)以為據(jù)。可行的做法是利用定時(shí)器建立周期指針,為“實(shí)現(xiàn)中斷”測(cè)控方式提供節(jié)律。本例采用集中測(cè)(控),即使采用中斷也難免“不斷的查詢(xún)”,如果采用分散測(cè)控并令測(cè)控節(jié)律略大于A/D轉(zhuǎn)換周期,使A/D轉(zhuǎn)換與測(cè)控程序平行運(yùn)行,實(shí)現(xiàn)中斷內(nèi)無(wú)條件取值,不但節(jié)省查詢(xún)等待時(shí)間,還可使測(cè)控時(shí)標(biāo)更精確。
引述以上4例皆因其典型,絕非其他使用SJMP $及其近義指令的程序就沒(méi)有問(wèn)題,至少,耗在一個(gè)點(diǎn)上等待實(shí)際上已造成程序阻塞,許多功能被屏蔽是既成事實(shí)。
下面是一個(gè)概略的程序參考框架。
… ;初始化模塊MOV PTER,#00H;啟動(dòng)自行待機(jī)
KEY: … ;鍵盤(pán)解碼模塊
JNB F0,SEQU ;運(yùn)行/調(diào)試選擇
TEST: … ;鍵盤(pán)二次解碼
MOV PTER,A ;保存散轉(zhuǎn)指針
DISP1: ACALL DISP ;調(diào)用顯示模塊MOV A,PTER ;提取散轉(zhuǎn)指針
RL A
SELECT: JMP @A+DPTR ;選擇運(yùn)行模式
SJMP KEY ;目標(biāo)地址很近AJMP SEQU ;目標(biāo)地址較近AJMP SELE1…
LJMP SEELN ;目標(biāo)地址較遠(yuǎn)… ;被隔離區(qū)
SEQU: SETB EA ;主模塊開(kāi)中斷CLR F0 ;關(guān)閉手動(dòng)調(diào)試…
ACALL DISP ;進(jìn)行人機(jī)對(duì)話(huà)AJMP KEY
TABLE: … ;數(shù)據(jù)表隔離區(qū)
SELE1: CLR EA ;暫停輸出模塊SETB F0 ;激活手動(dòng)調(diào)試AJMP KEY ;保持人機(jī)對(duì)話(huà)… ;被隔離區(qū)
… ;其他功能模塊
SEELN: … ;模塊N
LJMP KEY
… ;被隔離區(qū)
DISP: … ;顯示模塊
RET
… ;被隔離區(qū)
TIMER0: … ;定時(shí)中斷0
RETI
… ;被隔離區(qū)
… ;其他中斷
INTT1: … ;外部中斷1
RETI
… ;被隔離區(qū)
從例舉的程序框架可以看出,賦予指令SJMP $的三種功能,其實(shí)都是誤解。
其一,程序中能自然產(chǎn)生許多被隔離區(qū),根據(jù)需要靈活分配即可。
其二,所謂暫??煞殖绦驎和:蛦纹瑱C(jī)暫停兩層含義。程序暫停因無(wú)嚴(yán)格定義而無(wú)從討論,但并不妨礙質(zhì)疑其意義何在及爾后如何喚醒。單片機(jī)僅需臨時(shí)關(guān)閉其控制(信號(hào)輸出)功能,其中也包括阻止具有輸出功能的中斷服務(wù)程序,此時(shí)外在表現(xiàn)即為暫停,并不需要關(guān)閉其監(jiān)視(信號(hào)輸入)功能,也就是說(shuō),程序無(wú)需暫停。
單片機(jī)不能完全避免(有別于暫停的)待機(jī),程序框架例舉了一種解決方案。系統(tǒng)啟動(dòng)后處于無(wú)中斷待機(jī)狀態(tài),可隨時(shí)借助鍵盤(pán)修改散轉(zhuǎn)指針PTER,選擇程序各項(xiàng)功能。選擇運(yùn)行主模塊時(shí)開(kāi)中斷,隨即取消調(diào)試/手動(dòng)功能,當(dāng)然機(jī)器時(shí)間充裕時(shí)不取消也無(wú)妨,但始終保留人機(jī)對(duì)話(huà)功能,以便于狀態(tài)轉(zhuǎn)換。如果確實(shí)需要待機(jī),通過(guò)選擇可選模塊 SELE1關(guān)閉中斷的同時(shí)激活調(diào)試/手動(dòng)功能,將待機(jī)視為啟用調(diào)試/手動(dòng)功能的前奏,要比單純待機(jī)更安全。
其三,中斷是一種滿(mǎn)足響應(yīng)條件即可隨機(jī)插入子程序的運(yùn)行方式,空等專(zhuān)侯就枉費(fèi)了。
通過(guò)檢討可知,指令SJMP $的表現(xiàn)乏善可陳,亦無(wú)獨(dú)到專(zhuān)長(zhǎng),故類(lèi)似指令切勿濫用。
[1]王用倫.微機(jī)控制技術(shù)[M].重慶:重慶大學(xué)出版社,2004.
[2]李全利.單片機(jī)原理及應(yīng)用技術(shù)[M].北京:高等教育出版社,2001.
[3]張曄.王玉民.單片機(jī)應(yīng)用技術(shù)[M].北京:高等教育出版社,2006.
[4]王效華.單片機(jī)原理及應(yīng)用[M].北京:北京交通大學(xué)出版社,2007.
TP368.1
A
1008-1151(2011)04-0046-02
2011-01-12
田邱林(1952-),男,河北完縣人,桂林理工大學(xué)高等職業(yè)技術(shù)學(xué)院(南寧校區(qū))高級(jí)工程師,副教授,研究方向?yàn)橛?jì)算機(jī)組成原理、單片機(jī)、計(jì)算機(jī)控制技術(shù)等。