代碼的移植性問題
(1)用宏定義代替直接IO操作
本文引用地址:http://m.butianyuan.cn/article/201611/315480.htm我覺得最典型的例子就是蜂鳴器,4KHZ驅(qū)動的交流蜂鳴器,如果蜂鳴器接在 P50 口,那么驅(qū)動的代碼就應(yīng)該是:
mov a,@0x01
xor 0x05,a
代碼很簡單,0x01 和 P5口異或出來的結(jié)果,就是 P50 口取反,不斷的取反那么得到的是 P50 口輸出方波,用C語言來描述就是:
PORT5 ^= 0x01
好了,這個代碼的移植性超級差,如果我的蜂鳴器現(xiàn)在需要修改到 P62口,那么代碼也必須相應(yīng)的修改為:
mov a,@0x04
xor 0x06,a
當(dāng)然了,我們這里只需要一處,還不見得麻煩,如果你的代碼中有50處,乃至100處需要修改,我想你肯定要抓狂。所以這種不可移植的代碼必須扔掉。
修改版1:
通過定義蜂鳴器的IO口來處理
buz_port EQU 0x05
mov a,@0x01
xor buz_port,a
這里用 buz_port 這個名字代替了蜂鳴器的輸出端口,那么現(xiàn)在移植性有了提高,如果修改了端口的話,我們只需要重新定義 buz_port 這個宏,就完成了對代碼的所有的修改。
按照上面的描述,能解決了端口的問題,但是我們發(fā)現(xiàn),問題還沒有完全解決,mov a,@0x01 我們還得手工計算蜂鳴器在哪個引腳上面,而且還得在一個一個的修改,所以還需要改進(jìn)。
修改版2:
buz_port EQU 0x05
buz_pin EQU 0
mov a,@1< xor buz_port,a 這個代碼就真正實現(xiàn)了所謂的移植性。用C語言來解釋一下 buz_port ^= 1< 如果C語言過關(guān)的同學(xué)應(yīng)該對這個表達(dá)式很熟悉了。1< 例如 1<<0 得到的結(jié)果是 1 (00000001b) 1<<3 得到的結(jié)果是 8 (00001000b) 道理是這樣,但是使用起來一點也不負(fù)責(zé),可以說是很好用??梢灾苯雍虸O的名字對應(yīng)起來,例如前面說的 P62 的話,那么定義就應(yīng)該為: buz_port EQU 0x06 buz_pin EQU 2 只需要修改一下定義,程序當(dāng)中所有使用了這個IO口的部分都不需要修改,這樣移植性就非常好了。這個技巧雖然簡單,但是是必須學(xué)會的。 (2)動態(tài)綁定IO口 思考一種情況,我們使用 3個IO口分別發(fā)不同占空比的PWM,驅(qū)動3個不同顏色的LED發(fā)光,形成彩燈效果。要求就是3個IO口獨立控制,那么很自然的想法就是,3段程序,每一段程序都生成PWM,也就是說將1路的情況擴(kuò)展到3路,分別控制。但是寄存器的消耗和ROM的消耗也相對應(yīng)的變成了3倍,這是很好理解的。但是3段程序驚人的類似,很可能只是IO口輸出部分修改了一下,我們思考,時候可以合在一起寫呢?也就是說,用1個PWM程序生成PWM,分別輸出到3個不同的IO口,我建議,在看下去之前先自己思考一下,敲一下程序,就能很深刻的理解到這個問題的難點。 類似的情況也不少見,例如RC測溫,如果測1路的話很好辦,但是如果測很多路呢?你不會真的需要將每一路都一份對應(yīng)的程序吧?那絕對不可能,處理的辦法類似,也就是說,用一個程序處理多個IO的輸入數(shù)據(jù),切換。這有點類似數(shù)字電路里面的數(shù)據(jù)選擇器。 答案是:動態(tài)綁定IO口輸入輸出,途徑是R0和R4配合的間接尋址。怎么實現(xiàn)?其實很簡單,因為間接尋址本身能訪問地址 0x05 和 0x06 ,也就是能直接訪問 PORT5 和 PORT6 ,這樣就很容易聯(lián)想到,例如 PORT6 口輸出狀態(tài),然后 PORT6 的輸出狀態(tài)修改為 0X0F (P60~P63高電平,P64~P67低電平)一般的做法是: mov a,@0x0f mov PORT6,a 如果通過間接尋址的辦法,那么就是 mov a,@0x06 mov R4,a mov a,@0x0f mov R0,a 首先將要訪問的寄存器地址 0x06放到地址寄存器 R4,然后將數(shù)據(jù) 0x0f 送到 R0中,那么實際的效果就是將 0xf 送到 PORT6 當(dāng)中,用仿真器跑一下就OK了,很簡單的。 懂了這個原理之后,那么所謂的“動態(tài)綁定”就很容易理解了,將原來用 PORT5 PORT6訪問IO口的指令,變成用 R0 R4 間接尋址來訪問,這樣程序就可以變得很靈活。 例如有用回之前的那個蜂鳴器的例子 系統(tǒng)有兩個蜂鳴器,P50和P62,那么下面看看怎么通過動態(tài)綁定將方波分別輸出到這兩個蜂鳴器當(dāng)中。 分配兩個寄存器,分別保存當(dāng)前需要操作的端口信息。 REG_PORT == 0x10 REG_PIN == 0x11 假如當(dāng)前需要對 P50輸出 Mov a,@0x05 Mov REG_PORT,a Mov a,@1<<0 Mov REG_PIN,a 那么蜂鳴器的驅(qū)動函數(shù)就應(yīng)該做相應(yīng)的修改,前面說了,原來是直接對PORT口操作,現(xiàn)在變成間接尋址 Mov a,REG_PORT Mov R4,a Mov a,REG_PIN Xor R0,a 可以理解么?其實很簡單,首先確定當(dāng)前需要操作的端口,前面設(shè)定了REG_PORT的值為0x05,也就是說操作 PORT5,然后將需要操作的腳 1<<0 也就是 0x01 和 R0(現(xiàn)在指向PORT5)異或,得出來的效果就是 P50 改變電平,多次調(diào)用就變成輸出方波了。 如果現(xiàn)在需要對 P62輸出,那么事情就變得很簡單,只需要: Mov a,@0x06 Mov REG_PORT,a Mov a,@1<<2 Mov REG_PIN,a 那么中間的方波生成部分就通用了,我們需要操作哪個端口,直接送值就OK。 看到?jīng)]有?這里就是所謂的動態(tài)綁定。如果考慮移植性,也就是說以后可能會修改端口的話,那集合第一點當(dāng)中所說的,定義一個宏就OK了,反正這東西需要自己靈活的運用。 結(jié)束語: 很簡單的兩個東西,我用了大篇幅來描述就是為了說明問題而已,如果理解的話真的很簡單,甚至是不足掛齒。但是,怎么說呢,程序就是這類小技巧一點一點的積累起來的。希望今天說的2個小技巧能對你有益。
評論