EH78系列單片機(jī)的編程技巧
筆者在某智能水表開發(fā)中使用了EM78P447芯片,對EM78系列芯片有了較深認(rèn)識,在實(shí)踐中總結(jié)了一些開發(fā)此類芯片應(yīng)注意的問題,同時(shí)給出了應(yīng)用中的編程技巧。
市面上常見的介紹EM78系列的參考書中,都給出了一些應(yīng)用實(shí)例,但這些實(shí)例一般程序代碼量較小,功能單一。雖然這些實(shí)例對于新手確實(shí)起到了很好的作用,但一個(gè)產(chǎn)品可能功能很復(fù)雜,程序可能達(dá)到幾千行,這就會出現(xiàn)一些短程序中沒有遇見的問題。以筆者的開發(fā)為例,程序總共5千多行,有效的匯編語句代碼有3千多行。由于義隆沒有提供C的編譯環(huán)境,只能以匯編進(jìn)行編碼,而匯編的結(jié)構(gòu)、條理性與C語言比較不是很清晰,再加上EM78單片機(jī)結(jié)構(gòu)的獨(dú)特性,所以當(dāng)程序代碼量較大的時(shí)候總會出現(xiàn)一些新的問題。下面將實(shí)踐中遇到的問題及其解決方法總結(jié)一下,以供參考。
1 RAM數(shù)據(jù)的讀取方法
EM78系列的RAM既可以認(rèn)為是普通單片機(jī)中的RAM,也可以認(rèn)為是寄存器(通用和專用寄存器)。以EM78P447為例,RAM共148×8位,其結(jié)構(gòu)如圖1所示。
其中地址為20H一3EH,共有124(31×4)個(gè),分布在4個(gè)RAM“體”(Bank)上。4個(gè)體分別標(biāo)記為“BankO(體O)”、“Bankl(體1)”、“Bank2(體2)”、“Bank3(體3)”。當(dāng)程序中用到的變量不多或者數(shù)據(jù)量不是很大時(shí),這種RAM結(jié)構(gòu)對程序不會有什么影響,即程序變量能夠分配在一個(gè)Bank中;但是當(dāng)變量較多時(shí),操作起來將會有些麻煩,同時(shí)有可能因?yàn)槌绦蛑蠦ank選擇不當(dāng)導(dǎo)致程序出錯(cuò)。筆者覺得當(dāng)數(shù)據(jù)量較大時(shí),只要是對數(shù)據(jù)操作,就要先進(jìn)行Bank的選擇。特別是對子程序而言,一進(jìn)入子程序就要進(jìn)行Bank的選擇,從而控制所操作數(shù)據(jù)的范圍,時(shí)刻要清楚自己操作的數(shù)據(jù)在哪個(gè)Bank內(nèi)。通過改變“體選碼”,即RSR寄存器的最高2位,來選擇所要訪問的數(shù)據(jù)Bank。下面給出一個(gè)程序來說明。
BS RSR,7 :到Bank2
MOV A,0X2F
AND A,@OB00111111
MOV OX2E,A
CALL LCD _LEAR ;調(diào)用顯示屏清零程序
LCD CLEAR:
BC RSR,7 ;到Bank0
BC RSR,6
MOVA,@OB00000000
MOV LCd address,A
……
如上面程序所示,在調(diào)用LCD_ CLEAR之前訪問了Bank2數(shù)據(jù)區(qū),接著調(diào)用LCD-CLEAR子程序。此時(shí)在子程序內(nèi),若沒有注意數(shù)據(jù)的Bank問題,即沒有設(shè)置選擇BankO,則原本要對BankO的數(shù)據(jù)操作則會發(fā)生在Bank2的相應(yīng)數(shù)據(jù)地址上,從而程序發(fā)生錯(cuò)誤。所以進(jìn)入子程序后,馬上選擇要使用數(shù)據(jù)的Bank,從而防止發(fā)生誤操作EM78系列單片機(jī)的開發(fā)語言為匯編語言,所以當(dāng)編寫匯編程序時(shí),一定要養(yǎng)成一個(gè)良好的編程習(xí)慣,這非常有利于程序的開發(fā)和維護(hù)。筆者建議程序中對變量按如下操作。
①定義變量表。在程序開始的地方定義好變量表,為每一個(gè)變量取名,分配地址空間。
②相關(guān)變量最好定義在同一Bank內(nèi),這樣當(dāng)對這些相關(guān)變量操作時(shí)就可以免去選擇Bank的麻煩。
③以變量名進(jìn)行操作。不要對變量的地址直接操作,最好以變量名進(jìn)行操作,這樣當(dāng)變量需要改變名字或者需要更改分配地址時(shí),直接更改變量表即可,而不用更改具體的程序。這點(diǎn)對于較大的程序非常有利,不但可以增加程序的可讀性,更重要的是提高程序的編寫便利性和維護(hù)性。
以上幾點(diǎn)對于編寫較高質(zhì)量的代碼都非常重要,應(yīng)在具體實(shí)踐中仔細(xì)體會。
2 程序跨頁跳轉(zhuǎn)和跨頁調(diào)用技巧
首先需要介紹一下EM 78系列單片機(jī)的程序存儲器ROM結(jié)構(gòu)。EM78系列的程序存儲器ROM容量為4K×13位,采用Page(“頁”)分配原則,就是將4K的程序空間分為4頁,每個(gè)頁容量為1K。其結(jié)構(gòu)如圖2所示,其中Page0(000H~3FFH)、Pagel(400H~7FFH)、Page2(800H~BFFH)、Page3(COOH~FFFH)。指令系統(tǒng)中的兩條長距離跳轉(zhuǎn)指令JMP和CALL,所攜帶的地址碼僅僅有l(wèi)O位,210=lK地址空間,即只能在1K的空間內(nèi)跳轉(zhuǎn)。當(dāng)使用JMP指令時(shí),裝入目標(biāo)地址到PC程序指針的低10位;使用CALL指令時(shí),裝入目標(biāo)地址至PC程序指針的低10位,且PC+l壓棧,調(diào)用同1K頁面內(nèi)的任何程序。PC程序指針(寄存器R2)和堆棧的位數(shù)是12位,即尋址空間分別為4K,一個(gè)程序頁面為lK。頁面選擇通過設(shè)定狀態(tài)寄存器R3的Bit6(PS1)、Bit5(PSO)來完成。
在EM447中,當(dāng)需要跳轉(zhuǎn)或調(diào)用不同頁面的子程序時(shí),則需在調(diào)用前修改R3的PSl、PS0,這樣當(dāng)執(zhí)行IMP指令或CALL指令時(shí)會將狀態(tài)寄存器R3的PSl、PS0載入PC的A11、A10,所以PC程序指針可以在4K范圍的地址空間內(nèi)自由跳轉(zhuǎn)。
當(dāng)編寫的程序代碼量較大(超過1K)時(shí),程序跨頁跳轉(zhuǎn)和跨頁調(diào)用是避免不了的。在使用JMP指令時(shí),一定要知道將要跳到哪個(gè)Page;使用CALL指令時(shí),一定要知道要調(diào)用的子程序位于哪個(gè)Page中。這樣在使用JMP指令和CALL指令之前必須要設(shè)置PSl和PS0位來選擇將要跳轉(zhuǎn)或調(diào)用程序的存儲空間。例程如下:
BS STATUS,PSl ;到Page3
BS STATUS,PS0
CALL INIT CLEAR ;調(diào)用初始數(shù)據(jù)清零程序
CALL SYS INIT ;調(diào)用系統(tǒng)初始化程序
BC STATUS,PSI ;到Pagel
JMP SYS_BEGIN ;跳轉(zhuǎn)到系統(tǒng)啟動程序
例程中首先設(shè)置PS相應(yīng)位來選擇Page3,然后調(diào)用INIT_CLEAR和SYS_INIT,之后選擇Pagel,跳到Pagel中的SYS BEGIN主程序中。對于較大的程序,這種調(diào)用和跳轉(zhuǎn)是經(jīng)常出現(xiàn)的,所以要求編寫程序前必須熟悉程序地址空間的分配。
[!--empirenews.page--]
3 ROM模塊化編程原則
因?yàn)榱x隆提供的調(diào)試環(huán)境只支持匯編語言,而用匯編語言編寫的程序,結(jié)構(gòu)條理性劣于用C語言編寫的程序,所以編寫程序時(shí)應(yīng)盡可能的將子程序功能模塊化,即以完成某個(gè)功能來編寫子程序,這樣結(jié)構(gòu)清晰、調(diào)用方便。
筆者在編寫程序時(shí),針對EM78系列單片機(jī)ROM的Page結(jié)構(gòu),將子程序按區(qū)分功能原則分別存放到不同的Page內(nèi),如圖3所示為筆者項(xiàng)目中程序的存儲空間分配。
圖3中,PageO存放的主要是比較常用的子程序,如系統(tǒng)初始化程序、鍵盤掃描、液晶顯示等;Pagel存放的是一些數(shù)據(jù)處理程序,如不同Bank的數(shù)據(jù)拷貝,十六進(jìn)制轉(zhuǎn)為二進(jìn)制壓縮BCD碼等程序;Page2存放的加密算法程序,這是筆者項(xiàng)目開發(fā)中最重要的部分,所以單獨(dú)的放在一個(gè)Page內(nèi);Page3主要是對IC存儲器24LC02的一些讀寫操作子程序。這樣將功能相近的子程序放在一個(gè)Page內(nèi),從而根據(jù)單片機(jī)的結(jié)構(gòu)特點(diǎn)結(jié)合項(xiàng)目開發(fā)的實(shí)際來劃分程序存儲空間。在這樣調(diào)試時(shí),很容易發(fā)現(xiàn)問題出現(xiàn)在哪個(gè)區(qū)域,使得程序結(jié)構(gòu)清晰明了,調(diào)用方便,易于調(diào)試和維護(hù)。
4 采用分區(qū)指令冗余技術(shù)提高軟件抗干擾性
為了確保程序穩(wěn)定可靠運(yùn)行,有時(shí)必須采用軟硬件抗干擾設(shè)計(jì)。在某些場臺,大量的干擾源雖然不會造成單片機(jī)硬件系統(tǒng)的破壞,卻常常會破壞數(shù)字信號的時(shí)序,更改單片機(jī)寄存器內(nèi)容,導(dǎo)致程序的“跑飛”或進(jìn)入死循環(huán)。因此在提高硬件可靠性的基礎(chǔ)上,還需要在程序設(shè)計(jì)中采取軟件抗干擾,從而提高軟件的可靠性,減少軟件錯(cuò)誤的發(fā)生或者在發(fā)生錯(cuò)誤的情況下仍能使系
統(tǒng)恢復(fù)正常運(yùn)行。
針對EM78系列單片機(jī),筆者采用了分區(qū)指令冗余技術(shù)來防止程序的跑飛。即對程序中沒有使用的程序空間用“NOP_NOP_JMP”指令將其填滿。當(dāng)程序跑飛到單指令的“NOF”上時(shí),不會發(fā)生將操作數(shù)當(dāng)作指令來執(zhí)行的錯(cuò)誤,同時(shí)后面增加“JMP”指令使程序跳轉(zhuǎn)到程序跑飛處理程序上。圖4給出圖例。
圖4中,針對EM78系列單片機(jī)ROM的結(jié)構(gòu)特點(diǎn),分別在4個(gè)頁里存放一個(gè)單獨(dú)的跑飛處理程序Error(),程序的功能可以是“踢狗”(外置“狗”)。這樣做的原因如下:如果只編寫一個(gè)跑飛處理程序,假設(shè)放在PageO里,如果程序在Page2跑飛后,它不會跳到PageO的跑飛處理程序,反而會跳到Page2中,這樣程序仍然處于一種跑飛的狀態(tài)。所以在每個(gè)Page里添加Error()程序,這樣無論程序在哪個(gè)Page里跑飛,都會跳到Error()處理程序中。筆者實(shí)際中采用了這種方法取得了很好的效果。
5 其它常見問題分析
在使用EM78系列芯片進(jìn)行開發(fā)時(shí),除了上面要注意的幾點(diǎn),還會遇見一些其它小問題。下面就提出這些問題及解決方法,希望讀者編程時(shí)有所注意。
(1)切記堆棧的深度
匯編語言編程中經(jīng)常調(diào)用子程序,子程序的使用可以大大減少程序的書寫量,提高程序的使用效率。但在對EM78系列芯片進(jìn)行開發(fā)時(shí),調(diào)用子程序應(yīng)切記堆棧的深度。EM78系列單片機(jī)采用的是5級深度的硬件堆棧,它既不占用程序空間也不占用數(shù)據(jù)空間,是獨(dú)立的暫存空間,不需要進(jìn)棧和出棧的堆棧操作專用指令。堆棧的使用是環(huán)行的,若已有5個(gè)返回地址被存入堆棧后,若再次調(diào)用子程序,則第6個(gè)返回地址將被存入堆棧的第一層中(該層原有的內(nèi)容將被覆蓋),所以設(shè)計(jì)應(yīng)用程序時(shí),子程序的嵌套調(diào)用層數(shù)不能超過5層,若嵌套調(diào)用超過5層,則會發(fā)生程序跑飛。
(2)長時(shí)間的軟件延時(shí)方法
EM 78系列芯片內(nèi)部帶有定時(shí)器,但對于較長時(shí)間的延時(shí)(如幾十s)則不太適用。筆者在開發(fā)中要使用20s的延時(shí),編寫了一段軟件延時(shí)程序,采用3層嵌套程序,源代碼如下,程序可以直接移植運(yùn)行。
;…主循環(huán)………
LOOP0: MOV A,@18H
MOV DATAl,A
LOOF1: MOV A,@07fH
MOV DATA2,A
LOOP2: MOV A,@07IfH
MOV DATA3,A
LOOp3: JMP CHECK ;跳到應(yīng)用程序
CHE(1K BACK:DJZ DATA3 ;應(yīng)用程序退出
JMP LOOP3
DJZ DATA2
JMP LOOP2
DJZ DATAl
IMP LOOP1
;20s后執(zhí)行OTHER程序
IMP OTHER
(3)查表程序中防止程序跑飛的技巧
在單片機(jī)開發(fā)應(yīng)用中,經(jīng)常要用到查表程序來實(shí)現(xiàn)代碼轉(zhuǎn)換,例如8段LED的譯碼顯示。EM78系列芯片的指令系統(tǒng)中,有查表所需的專用指令TBL和RETL。查表過程是,先通過把被顯數(shù)字(即索引值)作為在數(shù)據(jù)表中的偏移量存入A,通過子程序傳遞參數(shù),子程序?qū)?shù)和當(dāng)前PC相加,則PC跳到偏移位置,然后經(jīng)由RETL將所列數(shù)據(jù)裝入A,然后退出子程序。假設(shè)所列數(shù)據(jù)表中只有1O項(xiàng),則傳遞到子程序的參數(shù)最大為9。但如果程序跑飛,則有可能傳入大于9的參數(shù),這樣此數(shù)加上PC指針則跳出數(shù)據(jù)表的范圍,程序出錯(cuò)。筆者在自己的程序中加上如下措施,從而有效的解決了這個(gè)問題。即進(jìn)入子程序后,首先判斷傳人參數(shù)是否大于9,即偏移量是否正確,不正確則跳到錯(cuò)誤處理程序ERROR(),正確則繼續(xù)執(zhí)行。這樣可確保顯示的數(shù)據(jù)都是正確的。
;……數(shù)據(jù)譯碼表……
DATA_TPANS_JBL:
AND A,@OXOF;判斷顯示的偏移數(shù)據(jù)是否超過09
MOV Disp_limit,a
BC STATUS,C
SUB A,@OxO9
IBS STATUS,C
JMP ERROR ;若顯示偏移數(shù)據(jù)出錯(cuò)跳到出錯(cuò)
;處理程序
……
……
TBL
RETL 0BI 10101 11 ;
“O”段碼AB′ABDEF,“0XD7”
RETL 0800000110 ;“1”段碼:“Bc” ,“0X06”
……
……
RETL 0810110111 ;“9”段碼’′ABCDFG′,"0XB7"以上是筆者在產(chǎn)品開發(fā)中的一些心得,文中所列舉的程序均經(jīng)ELAN WICE。E編譯通過,讀者可直接引用。