新聞中心

代碼的移植性問題

作者: 時間:2016-11-17 來源:網(wǎng)絡(luò) 收藏
代碼移植性是對編程人員的一大考驗,這個問題應(yīng)該時刻考慮。甚至從你策劃項目的一瞬間開始,就應(yīng)該考慮到代碼可能會被多次修改,或者功能模塊的刪減等。項目的外圍硬件很多時候都會根據(jù)需求改變,到底怎么樣的編寫技巧能使修改量降至最小,而又能很好的完成項目呢?這就是今天研究的話題。這里先說一些小的例子,以及實際怎樣運用。

(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個小技巧能對你有益。



關(guān)鍵詞: 代碼移

評論


技術(shù)專區(qū)

關(guān)閉