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