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