我開發的是義隆單片機,是以以義隆的彙編舉例。
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上)。如果不能調用函數,最笨的辦法就是每個都改,現在用宏定義也能達到調用函數的效果。