天天看點

OTP(OneTimeProgrammable)開發之彙編技巧

我開發的是義隆單片機,是以以義隆的彙編舉例。

1.定義IO口

原來的方式: IO_Buz == 1

給IO置1,則需要寫成

BS    P5.IO_Buz
           

更改方式: IO_Buz == P5.1

BS    IO_Buz
           

這樣做的好處是,可避免程式更改帶來的相容問題,隻要改檔案定義部分就好,而且書寫量變小。

2.定義常用的狀态标志位

一般功能寄存器定義裡都有類似如下的定義:

R3		==	0X03:rpage 0
STATUS	==	0X03:rpage 0
           

我們可以在下面加一些自己要的定義:

;{				
		;//因為這裡定義了每一位,是以才不用指定寄存器
	    C	  	==  STATUS.0	;
	    DC	 	==  STATUS.1
	    Z	  	==  STATUS.2
	    P	  	==  STATUS.3 ;Power-down bit.
	    T	  	==  STATUS.4 ;
	    
	    IOCS  	==  STATUS.6 ; I/O REGISTER PEGER CONTER BIT
	    RST		==  STATUS.7 ;
;}
           

不要小看了這個定義,原來可能寫的是

bs  STATUS.2
           

現在寫的是

bs  Z
           

不但書寫量變小,而且不容易出錯,一下明白他的意思。

3.代碼壓縮文法技巧

3.1 調用之後馬上傳回

call 	F_XXX
Ret
           

可改為:

jmp	 F_XXX
           

好處是節省一個 ret 棧少壓一層。壞處是破壞程式完整性,仿真的時候不友善跟蹤。非最後開發需要幾行ROM,不建議這樣做。

3.2 多次對位比較跳轉到相同的位址

Jbc 	B_XX1
Jmp		mainloop
Jbc		B_XX2
Jmp		mainloop
           

可改為:

jbs		B_XX1
Jbc		B_XX2
Jmp		mainloop
           

每兩次比較跳轉可節省一個 跳轉。

4.中斷現場儲存

1.中斷儲存的原則是會破壞什麼才保護什麼,這裡的技巧在于,你的中斷程式不一定破壞了R4間接尋址寄存器,是以可以選擇性儲存。

mov 	V_A_Save,a
swap	V_A_Save
           

中斷儲存一定要用這個。

不可隻用

mov		R,a
           

因為出中斷還原的時候:

swapa	V_SF_Save
mov 	SF,a
swapa	V_A_Save
           

是先還原的狀态寄存器,如果用 mov a,R 則會改變Z标。

5.改善相容性

義隆IDE開發還支援條件編譯,僞指令,這個利用好能大大增加相容性。

5.1條件編譯

條件編譯用法:

if(條件)
/*代碼塊*/
endif
           

舉例:

我常用的的OTP晶片是153S和372N,在使用IIC的時候,總是有端口設定上相容性問題,每次都要琢磨改。終于在發現條件編譯後才解放。

在開始的位置,先說明使用的OTP平台,需要改IO方向的SDA在哪個端口。

OTP_153S == 0;
OTP_372N == 1;
Port_SDA == P6
           

下面實際應用實作。

;;------------------153S---------------------------
;;;P5口SDA
;	;153S P5口沒有上拉功能,不能用作SDA
;;;P6口SDA
if (OTP_153S == 1)
F_SDA_NotPullUpOutZero:	;
	ior	iocd
	or	a,@(mIO_SDA)
	iow	IOCd		;
	ior	ioc6
	and	a,@(0XFF^(mIO_SDA))
	iow	ioc6
	bc	IO_SDA		;這一句不能省,會影響EEPROM操作,造成當機
	ret

F_SDA_PullUpInMode:
	ior	ioc6
	or	a,@(mIO_SDA)	;
	iow	ioc6	
	ior	IOCD
	and	a,@(0XFF^(mIO_SDA))	;隻改這1個端口上拉
	iow	IOCD
	bs	IO_SDA
	ret
endif
;-----------------372N------------------------------
;;P5口SDA
if ((OTP_372N == 1) && (Port_SDA == P5))
F_SDA_NotPullUpOutZero:	;
	ior	iocd0
	or	a,@(mIO_SDA)
	iow	IOCd0		;P5口上拉控制寄存器,位于第0頁
	bc	IO_SDA		;這一句不能省,會影響EEPROM操作,造成當機
	ior	ioc50
	and	a,@(0XFF^(mIO_SDA))
	iow	ioc50
	;bc	IO_SDA		;這一句不能省,會影響EEPROM操作,造成當機
	ret
	
F_SDA_PullUpInMode:
	ior	ioc50
	or	a,@(mIO_SDA)	;
	iow	ioc50	
	ior	IOCD0
	and	a,@(0XFF^(mIO_SDA))	;隻改這1個端口上拉
	iow	IOCD0
	bs	IO_SDA
	ret
endif
;;P6口SDA
if ((OTP_372N == 1) && (Port_SDA == P6))
F_SDA_NotPullUpOutZero:	;
	bs	IOCS
	ior	iocF1
	or	a,@(mIO_SDA)
	iow	IOCF1		;P5口上拉控制寄存器,位于第0頁
	bc	IOCS
	bc	IO_SDA		;這一句不能省,會影響EEPROM操作,造成當機
	ior	ioc60
	and	a,@(0XFF^(mIO_SDA))
	iow	ioc60
	ret
	
F_SDA_PullUpInMode:
	ior	ioc60
	or	a,@(mIO_SDA)	;
	iow	ioc60
	bs	IOCS	
	ior	IOCF1
	and	a,@(0XFF^(mIO_SDA))	;隻改這1個端口上拉
	iow	IOCF1
	bc	IOCS
	bs	IO_SDA
	ret
endif
           

對于不同的OTP,不同的端口,隻要在檔案頭設定一下,這個檔案就通用了。

5.2僞指令/宏定義

寫彙編有很多問題,操作繁瑣,空間受限,不能很好的傳達代碼的意思。這個不能很好的解決,隻能做改善。宏定義能稍微改善一下這個問題。

;********************************************************;
;CLEAR EM78P372N GENERAL REGISTER MACRO PROGRAM          
;********************************************************;
 M_372NCLRRAMBANK  MACRO 
     MOV   	A,@0X10
     MOV   	RSR,A
__CLRLOOP: 	   
     CLR   	R0   		;清除RSR指定位址的内容
     INC   	RSR		    ;RSR指到下一個位址
     JBC   	RSR,6		;判斷是否Bank0(0x10~0x3F)已清除
     BS    	RSR,5 		;已清除Bank0(0x10~0x3F);改由Bank1 位址0x20~0x3F
     MOV	A,RSR
     AND    A,@0X7F
     JBS	Z     		;這裡不能寫對R3位尋址,不然就編譯出錯   
     JMP   	__CLRLOOP 	;判斷是否Bank0及Bank1皆已清除
     BC	S_BANK		    ;特殊寄存器bank0,預設要還原到這個
     ENDM
   
M_GotoSleepSeting   MACRO ;進入睡眠
_GotoSleepSeting:
	bc 	IOCS
  	clra	              ;a=0
 	iow	IOCF0	          ;禁止所有中斷
 	iow	IOCE0
 	mov	a,@mEnWDTRate8	;允許看門狗,預分頻為2分頻
    iow	ioce0     	    ;允許看門狗 ,P60 是IO
 	slep			    ;喚醒後一般重Reset 開始,後面是保護作用
 	jmp	Main 
 	ENDM
           

這是常用的兩個操作,寫成宏定義,語義表達清楚,且不額外占用空間。

把這兩個宏定義,放到頭檔案裡,每次用相同的IC型号,直接用,也不用改能大大簡化工作。

使用的時候:

M_372NCLRRAMBANK
 M_GotoSleepSeting
           

OTP開發彙編,因為硬體棧受限制,不能像開發ARM晶片一樣各種調用,在一些使用次數不多,且大段程式嚴重影響觀感的時候,應該考慮使用宏定義,一定程度上是借用了函數的殼,但是沒有壓棧的負擔。

已經提到借用了函數的殼,但是沒有壓棧的負擔。這裡還有其他用法:

M_OpenSetLed	MACRO ;
	BS	IO_SetLED
	ENDM
M_CloseSetLed   MACRO ;
	BC	IO_SetLED
     	ENDM
           

開發的時候經常要碰到改邏輯(置高開燈/置低開燈),改端口(不在一個Port上)。如果不能調用函數,最笨的辦法就是每個都改,現在用宏定義也能達到調用函數的效果。