由數(shù)碼管動(dòng)態(tài)顯示淺談單片機(jī)程序
傳統(tǒng)的數(shù)碼管顯示程序?yàn)椋?/p>本文引用地址:http://m.butianyuan.cn/article/201611/323870.htm
#define DUAN P1
#define WEI P0
void delayms(uchar x)
{
uchar y=120;
while(x--)
while(y--);
}
WEI=0; //消影 共陽,共陰為 WEI=0xff
DUAN=code[value_duan1]; //送段選數(shù)據(jù)
WEI=value_wei1; //送位選數(shù)據(jù),確定第幾個(gè)數(shù)碼管點(diǎn)亮
Delayms(5); //延時(shí)5ms使其顯示穩(wěn)定
WEI=0; //消影 共陽,共陰為 WEI=0xff
DUAN=code[value_duan2]; //送段選數(shù)據(jù)
WEI= value_wei2; //送位選數(shù)據(jù),確定第幾個(gè)數(shù)碼管點(diǎn)亮
Delayms(5); //延時(shí)5ms使其顯示穩(wěn)定
當(dāng)延時(shí)后依次再送下一個(gè)數(shù)據(jù),再延時(shí)······
這里我想再次說一下關(guān)于延時(shí)的問題。一般教科書或者說目前絕大多數(shù)能看到的數(shù)碼管處理程序資料大多都是按照上面的方式處理的。我想問一下,這里延時(shí)5ms的意義何在?可否不延時(shí)?答案是可以,但顯示結(jié)果就是最后一個(gè)被點(diǎn)亮的數(shù)碼管會(huì)比較亮,其余的都比較暗。至于原因很簡(jiǎn)單,點(diǎn)亮最后一個(gè)數(shù)碼管后,單片機(jī)CPU還要跑其他程序,然后再次跑到數(shù)碼管顯示處理函數(shù)時(shí)再依次點(diǎn)亮第一第二個(gè)數(shù)碼管。顯然這樣最后一個(gè)被點(diǎn)亮的數(shù)碼管點(diǎn)亮的時(shí)間遠(yuǎn)遠(yuǎn)比其他的數(shù)碼管時(shí)間要長(zhǎng),自然這一個(gè)特別亮,其余的很暗淡。然而加上5ms延時(shí)的話呢?由于單片機(jī)速度還算比較快(一般一條指令1us),5ms相當(dāng)于5000條指令。5000條指令什么概念呢?怎么說呢,若程序里不用“delay”這樣的空指令的話,一般一個(gè)大型項(xiàng)目就差不多了。一般而言,比如AD測(cè)溫、adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=85d214d39ac24f75&k=%B5%E7%D7%D3%CA%B1%D6%D3&k0=%B5%E7%D7%D3%CA%B1%D6%D3&kdi0=0&luki=8&n=10&p=baidu&q=98059059_cpr&rb=0&rs=1&seller_id=1&sid=754fc29ad314d285&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1831118&u=http%3A%2F%2Fwww%2E51hei%2Ecom%2Fmcu%2F2120%2Ehtml&urlid=0" id="16_nwl" mpid="16" target="_blank">電子時(shí)鐘等這樣小項(xiàng)目實(shí)際有用的指令絕對(duì)不會(huì)達(dá)到好幾千的樣子。所以說5ms對(duì)于單片機(jī)來說是個(gè)相當(dāng)長(zhǎng)的時(shí)間。
再回到延時(shí)5ms后顯示較為穩(wěn)定的問題上。因?yàn)辄c(diǎn)亮最后一個(gè)數(shù)碼管延時(shí)5ms后單片機(jī)在跑其他的指令時(shí)相對(duì)要不了多久(前提是其余地方?jīng)]有“delay”空指令),所以最后一個(gè)數(shù)碼管比其他數(shù)碼管多亮的時(shí)間就不太明顯了,這樣自然顯示也會(huì)比較均勻一些。但是事實(shí)上,最后一個(gè)被點(diǎn)亮的數(shù)碼管還是稍微比別的數(shù)碼管亮一些。注意上面所說的是單片機(jī)跑其他指令用的時(shí)間不長(zhǎng)的情況。如果,程序比較大,模塊很多,單片機(jī)要處理的事情很多呢?比方說一個(gè)float型數(shù)據(jù)的除法(不知道讀者有沒有在單片機(jī)上試過)所耗費(fèi)的指令數(shù)可能你都想象不到(尤其是對(duì)于內(nèi)部不含硬件除法器單片機(jī),其除法指令轉(zhuǎn)換成其他的運(yùn)算)。我當(dāng)時(shí)做AD測(cè)電阻時(shí)用的sonix芯片(沒有除法器),開始程序里面一個(gè)float型除法,整個(gè)程序當(dāng)時(shí)有1.5k的樣子,數(shù)碼管顯示,老是一個(gè)亮,其余的暗淡,而且很不穩(wěn)定。后來查找原因,就是因?yàn)槟菞lfloat型除法的問題,竟然占了大幾ms的時(shí)間。當(dāng)刪除那條指令后,整個(gè)程序只有700多字節(jié),也就是說就這么一條指令就直接讓程序大小翻倍了!查看編譯器翻譯成的匯編指令占了相當(dāng)大一部分,而且還有很多CALL指令。所以說,8位單片機(jī) 確實(shí)不適合做除法以及float運(yùn)算。
扯遠(yuǎn)了,回到數(shù)碼管問題。綜上面所述,delayms(5)的方式是不可靠的。而且最為關(guān)鍵的時(shí)delay指令是毫無意義的,就是讓單片機(jī)啥也不做,在那里死等。試想一下,單片機(jī)還要處理其他事情,光在這里死等豈不是太浪費(fèi)了嗎?就好比人一樣我可以在吃飯的同時(shí)聽音樂,而不是先吃飯,飯吃完了再專門聽音樂。單片機(jī)也是一樣,要的是效率,而不是在那里死等。
那么這種方式不好,該怎么辦呢?要不要延時(shí)?延時(shí)肯定是需要的,不然顯示不均勻,但不是這種方式。正確的方式是定時(shí)器定時(shí)5ms,5ms到后刷新一次數(shù)碼管,這樣一來單片機(jī)不會(huì)在這里死等,二來數(shù)碼管顯示時(shí)間絕對(duì)均勻。對(duì)于定時(shí)器,一般的單片機(jī)至少有一個(gè),而且它作為單片機(jī)的獨(dú)立模塊,根本不影響cpu工作。以3個(gè)數(shù)碼管為例,其程序代碼如下
#define DUAN P1 //宏定義段選
#define WEI P0 //宏定義位選
void timer(); //定時(shí)器處理函數(shù),用定時(shí)器定時(shí)5ms
{
if(定時(shí)標(biāo)志位置一)
{
定時(shí)標(biāo)志清零;
If(T_5ms) //若T_5ms大于0,每5ms減1
T_5ms--;
}
}
if(T_5ms==2)
{
WEI=0; //消影 共陽,共陰為 WEI=0xff
DUAN=code[value_duan1];
WEI= value_wei1;
}
if(T_5ms==1)
{
WEI=0;
DUAN=code[value_duan1];
WEI= value_wei2;
}
if(T_5ms==0)
{
T_5ms=3; //計(jì)時(shí)寄存器重新賦值
WEI=0;
DUAN=code[value1];
WEI=value2;
}
這樣CPU不用在這里死等,每次程序跑到這里時(shí),只需做個(gè)判斷就好了,5ms到后就進(jìn)去點(diǎn)亮數(shù)碼管,否則就不進(jìn)去,顯示效果絕對(duì)均勻。同理,諸如鍵盤掃描程序,延時(shí)消抖,都可以采用這種方式,而不用delay。
也許讀者可能發(fā)現(xiàn)了問題,對(duì),還是有點(diǎn)問題。假若程序在其他地方耗費(fèi)時(shí)間大于5ms的話,那么這里的定時(shí)5ms就失去了作用。確實(shí)是這樣的。實(shí)際上對(duì)于好程序來說,主循環(huán)絕對(duì)控制在1ms一下(CPU跑1Mhz,即1條指令1us)。也許你會(huì)問,有些模塊不可能1ms以內(nèi)就完成啊。是的,有些時(shí)候某些模塊確實(shí)需要很久才能完成。這就涉及到程序分時(shí)分段處理的問題。好比人做事情一樣,我這件事今天做不完,但可以明天再做,而且同時(shí)今天我也要吃飯、睡覺做其他的事情,而不是說這件事沒做完,別的什么也不干了。單片機(jī)也是如此。不管在大的程序,都是分時(shí)分段處理的,不然CPU會(huì)崩潰的,CPU不可能同時(shí)把所有的都一起處理了,而是這段時(shí)間處理一點(diǎn),下段時(shí)間再處理一點(diǎn)。這樣在總的時(shí)間上是一樣的,CPU完成的事情卻翻倍了。說道這里程序主循環(huán)控制在1ms絕對(duì)不成問題了。在試想一下,在程序里面到處delay是不是很可怕?比如按鍵,消抖可以delay 10ms,如果是長(zhǎng)按鍵呢?難道要delay 3s或更長(zhǎng)?所以說不管從功能上還是程序結(jié)構(gòu)上,delay是絕對(duì)不可取的。對(duì)于delay,幾個(gè)us(相當(dāng)于幾個(gè)nop指令)還是允許的。
說到這里,程序分時(shí)分段思想已經(jīng)很明白了。雖然說一個(gè)大型項(xiàng)目,包括很多模塊,比如按鍵、AD采樣、數(shù)碼管顯示(或lcd顯示)、PWM輸出、UART、IIC通訊等等,但是并不是說每個(gè)模塊都在同一時(shí)間完成。比如按鍵按一下大概幾百毫秒的樣子,長(zhǎng)按好幾秒的樣子,主程序不是一直在這里等,而是一遍又一遍的循環(huán)掃描,當(dāng)掃描的按鍵鍵值變化而且連續(xù)在100ms以內(nèi)沒有變化,那么確認(rèn)此次為短按鍵按下。每次在掃描鍵盤時(shí)大概耗費(fèi)幾十us,然后接著以同樣的方式掃描其他模塊。這樣主循環(huán)把所有的模塊都掃一遍頂多也就幾百us的樣子。這樣說來,一次按鍵按下事件,程序已經(jīng)把它分成了大概幾百次來完成,即為分時(shí)處理。而不是以delay的方式死等這一次事件完成。其他模塊都遵循這個(gè)道理。
告別delay,主循環(huán)while(1)周期做到小于1ms,那么就告別了學(xué)校教育從而進(jìn)入實(shí)際應(yīng)用!為什么學(xué)校所教的不是這種思想呢?因?yàn)樵趯W(xué)校和實(shí)踐嚴(yán)重脫節(jié),沒有考慮過真正的項(xiàng)目。所學(xué)的都是一些獨(dú)立子程序模塊。由于子程序結(jié)構(gòu)簡(jiǎn)單,程序較小,delay無所謂。而把各個(gè)模塊都加在一起,可能就會(huì)出毛病。實(shí)際情況要考慮的還多的很,比如功耗、成本等等。在學(xué)校只管能搞出結(jié)果就不錯(cuò)了,哪管這個(gè)芯片多少錢,這個(gè)電容多少錢?對(duì)于真正的項(xiàng)目應(yīng)用,實(shí)現(xiàn)功能只算很小很小的一部分。由于學(xué)校所學(xué)和實(shí)際脫節(jié),所以這也是當(dāng)今大學(xué)生難找工作的原因之一,這也是當(dāng)今中國(guó)教育的缺陷!當(dāng)然成為單片機(jī)高手,還有很多路要走,了解這些只是一個(gè)門檻而已。
評(píng)論