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