書名: 51單片機應用開發案例手冊作者名: 程國鋼編著本章字數: 3810字更新時間: 2018-12-27 19:43:09
1.3 I/O引腳驅動數碼管
在單片機系統中,有時需要顯示一些簡單的數字或者字符,此時可以使用數碼管。數碼管是一種由多個發光二極管組成的半導體發光器件,是51單片機系統常用的一種外圍顯示器件。常見的數碼管可按顯示的段數分為7段數碼管、8段數碼管和異型數碼管;按能顯示多少個字符/數字分為一位、兩位等“X”位數碼管;按照數碼管中各個發光二極管的連接方式分為共陰極數碼管和共陽極數碼管。常見的數碼管實物如圖1.5所示。

圖1.5 常見數碼管實物
1.3.1 單位數碼管的工作原理
常見的單位(一位)8段數碼管的內部結構如圖1.6所示,其由8個發光二極管組成,通過點亮不同的發光二極管組合可顯示數字0~9,字符A、F、H、L、P、R、U、Y,符號“-”及小數點“.”。

圖1.6 一位8段數碼管內部結構
如圖1.6所示,8段共陽極數碼管中8個發光二極管的陽極(正極)連接在一起,其他引腳接各段驅動電路輸出端。當這些發光二極管的正極輸入高電平,對應發光二極管的輸出端為低電平時,對應發光二極管導通,對應的段點亮,根據發光字段的不同組合顯示出各種數字或字符。八段共陰極數碼管的結構正好相反,8個發光二極管的陰極(負極)連接在一起,其他引腳接各段驅動電路輸出端,當這些發光二極管的負極輸入低電平,對應發光二極管的輸出端為高電平時,對應的發光二極管導通,對應的段點亮,根據發光字段的不同組合可顯示出各種數字或字符。與LED類似,當通過數碼管的電流較大時顯示段的亮度較高,反之較低,通常使用限流電阻來決定數碼管的亮度。
51單片機一般采用軟件譯碼和硬件譯碼兩種方式來擴展數碼管,前者是指通過軟件控制51單片機的I/O輸出從而達到控制數碼管顯示的方式,后者則是指使用專門的譯碼驅動硬件來控制數碼管顯示的方式;前者的硬件成本較低,但是占用單片機更多的I/O引腳,軟件較為復雜,后者的硬件成本較高,但是程序設計簡單,只占用較少的I/O引腳。
根據8段數碼管的顯示原理,要使數碼管顯示出相應的字符必須使單片機I/O口輸出的數據即輸入到數碼管每個字段發光二極管的電平符合想要顯示的字符要求。這個從目標輸出字符反推出數碼管各段應該輸入數據的過程稱為字形編碼,8段數碼管的字形編碼如表1.3所示。
表1.3 8段數碼管的字形編碼


也就是說,對于I/O口驅動的數碼管而言,只需在I/O上輸出對應的字形編碼,8段數碼管即可顯示所需要的字符或者數字。應該注意,在擴展數碼管時也要考慮單片機的I/O驅動能力,與LED的驅動方式類似,數碼管也有“拉電流”和“灌電流”兩種驅動方式。
1.3.2 應用實例——流水數字
流水數字是一個51單片機使用I/O引腳驅動單位8段數碼管的實例,數碼管輪流地循環顯示“0”~“F”數字或者字符,通常用于在單片機系統中顯示一些數字或者字符。
流水數字實例的電路圖如圖1.7所示,單位8段共陽極數碼管的公共端連接到VCC上,數碼管的8位數據引腳則連接到P1的八位引腳上,使用1 kΩ電阻作為限流電阻,表1.4是實例使用的典型器件說明。
表1.4 數字流水實例器件列表


圖1.7 流水數字實例電路圖
【例1.3】 與LED閃爍實例類似,51單片機使用兩個嵌套的for循環來進行軟件延時,然后通過P1引腳將對應字符的字形編碼送出供數碼管顯示,代碼中使用一個存放在code存儲器的數組SEGtable來存放字形編碼,用一個conter計數器來指示當前應該輸出的數字或者字符的字形編碼在表格中的位置。
#include <AT89X51.h> unsigned char code SEGtable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83, 0xC6,0xA1,0x86,0x8E}; //“0”~“F”對應的字形編碼,共陽極8段數碼管 main() { unsigned char i,j; unsigned char counter=0; //指示當前顯示的數字或字符在表格中的存放位置 while(1) { for(i=0;i<250;i++) //軟件延時 { for(j=0;j<250;j++); for(j=0;j<250;j++); } if(counter>=15) //已經顯示到F,回到0繼續顯示 { counter=0; } else { counter++; //數字字符增加 } P1 =SEGtable[counter]; //輸出字符 } }
1.3.3 多位數碼管的工作原理
在實際的單片機系統應用中,常常是使用多個數碼管來顯示多個字符或者數字,此時需要多位數碼管。可以使用多個獨立的8段數碼管來自己拼接,其優點是位數不限,布局靈活;也可以直接使用集成好的多位數碼管,優點是引線簡單(只有一套8段驅動引腳),價格相對來說便宜一些。
圖1.8是6位共陽極集成數碼管的結構圖,可以看到,6位數碼管的a、b、c、d、e、f、dp引腳都集成到了一起,而位選擇1、2、3、4、5、6引腳則對應位數碼管的陽極端點,用于選擇點亮的位。

圖1.8 6位共陽極集成數碼管的結構圖
多位數碼管可以使用多個I/O端口驅動,如P0~P3分別驅動4個數碼管,但是這樣極大地浪費了I/O資源,所以通常在實際使用中用動態掃描的方法來實現多位數碼管的顯示。動態掃描是針對靜態顯示而言的,所謂靜態顯示是指數碼管顯示某一字符時,相應的發光二極管恒定導通或恒定截止,這種顯示方式的每個數碼管相互獨立,公共端恒定接地(共陰極)或接電源(共陽極),每個數碼管的每個字段分別與一個I/O口地址相連或與硬件譯碼電路相連,這時只要I/O口或硬件譯碼器有所需電平輸出,相應字符即顯示出來,并保持不變,直到需要更新所顯示字符。采用靜態顯示方式占用單片機時間少,編程簡單,但其占用的口線多,硬件電路復雜,成本高,只適合于顯示位數較少的場合。而動態掃描則是一個一個地輪流點亮每個數碼管,方法是多位數碼管的a~dp數據段都用相同的I/O引腳來驅動,而使用不同的I/O引腳來控制位選擇引腳。在動態掃描顯示時,先選中第一個數碼管,把數據送給它顯示,一定時間后再選中第二個數碼管,把數據送給它顯示,一直到最后一個。這樣雖然在某一時刻只有一個數碼管在顯示字符,但是只要掃描的速度足夠高(超過人眼的視覺暫留時間),動態顯示的效果在人看來就是幾個數碼管同時顯示。采用動態掃描的方式比較節省I/O口,硬件電路也較靜態顯示方式簡單,但其亮度不如靜態顯示方式,而且在顯示的數碼管較多時,51單片機要依次掃描,占用了單片機較多的時間。
在動態掃描的電路中,使用不同的I/O引腳來進行位選擇,此時該I/O引腳必須能完成“點亮”→“熄滅”數碼管的控制功能。該功能一般是通過一個通斷電路控制共陽/共陰極端(位選擇端)來實現的,當I/O引腳控制該電路接通時共陽/共陰極端被連接到VCC/地,對應的位數碼管被選中顯示。通常這個通斷電路使用三極管來實現,圖1.9是使用三極管控制4位8段數碼管的電路結構圖。

圖1.9 用三極管控制4位8段數碼管電路結構圖
圖1.9中,使用4個PNP三極管來控制4位數碼管,當對應的控制引腳NUM1~NUM4輸出高電平時,三極管導通,VCC被加在對應數碼管的公共端(選擇端),對應的數碼管被選中,按照該數碼管的數據輸入顯示對應的字符或者數字。
1.3.4 應用實例——多位數字顯示和流水數碼管顯示
1. 多位數字顯示實例
本實例使用51單片機驅動6位數碼管顯示“123456”6位數字,該應用常常用于需要顯示多位數字或者字符的應用系統。
圖1.10是實例的應用電路,51單片機用P1給NUM0~NUM5共6個獨立的8段數碼管提供字形編碼,而用P2.0~P2.5共6個引腳通過PNP三極管來選通對應的數碼管顯示。表1.5是實例使用的典型器件說明。

圖1.10 多位數碼管顯示數字實例電路圖
表1.5 多位數字顯示實例器件列表

【例1.4】 為了精確控制延時的時間以便于造成“掃描”效果,使用Delayus和DleayMs兩個函數來控制精確延時。整個掃描過程如下:先通過P1端口輸出要顯示數字或者字符對應的字形編碼,然后用P2口控制對應的位選通引腳輸出高電平,PNP三極管導通,數碼管顯示;延時一段時間,關閉P2口對應的引腳,切換到下一位數碼管,重復上述操作。
#include <AT89X52.h> unsigned char code SEGtable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83, 0xC6,0xA1,0x86,0x8E}; //字形編碼表 void Delayus(unsigned int US) //延時US函數 { unsigned int i; US=US*5/4; for(i=0;i<US;i++); } void Delayms(unsigned int MS) //延時MS函數 { unsigned int i,j; for(i=0;i<MS;i++) for(j=0;j<1141;j++); } main() { P2=0x00; //全部數碼管未選中 while(1) { P1 =SEGtable[0]; //送數字1 P2=0x01; //選中數碼管0 Delayms(1); //延時保證顯示完成 P2=0x00; //停止選中數碼管0 Delayus(100); //延時,切換到下一位數碼管 P1 =SEGtable[1]; P2=0x02; //選中數碼管1 Delayms(1); P2=0x00; Delayus(100); P1 =SEGtable[2]; P2=0x04; //選中數碼管2 Delayms(1); P2=0x00; Delayus(100); P1 =SEGtable[3]; P2=0x08; //選中數碼管3 Delayms(1); P2=0x00; Delayus(100); P1 =SEGtable[4]; P2=0x10; //選中數碼管4 Delayms(1); P2=0x00; Delayus(100); P1 =SEGtable[5]; P2=0x20; //選中數碼管5 Delayms(1); P2=0x00; } }
2. 流水數碼管顯示實例
流水數碼管顯示實例中,使用6位數碼管從左到右輪流顯示“0”~“F”字符。在類似于廣告牌等的實際應用場合中,常常需要從左到右或者從右到左流動顯示一些數字或字符。
該實例的電路圖和多位數碼管顯示數字實例相同,如圖1.10所示,【例1.5】是流水數碼管顯示實例的代碼。
【例1.5】 與 【例1.4】類似,使用51單片機的P1口輸出字形編碼,使用P2口選通對應的位數碼管,區別在于使用兩個for循環嵌套,構成較長時間的延時,沒有“視覺殘留”效果。在P2輸出選擇的代碼段,用switch-case語句來判斷應該使P2的哪一位引腳輸出高電平。
#include <AT89X52.h> unsigned char code SEGtable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83, 0xC6,0xA1,0x86,0x8E}; main() { unsigned char i,j; unsigned char counter=0; //用于確定顯示的數字或者字符 unsigned char Lcounter=0; //用于確定選中的數碼管 P2=0x00; while(1) { for(i=0;i<250;i++) //延時 { for(j=0;j<250;j++); for(j=0;j<250;j++); } P1 =SEGtable[counter]; //輸出用于顯示數字或者字符的字形編碼 if(counter>=15) //如果到了“F”則回到“0” { counter=0; } else { counter++; } switch(Lcounter) //根據選中的位輸出對應的控制信號 { case 0x00:P2=0x01;break; case 0x01:P2=0x02;break; case 0x02:P2=0x04;break; case 0x03:P2=0x08;break; case 0x04:P2=0x10;break; case 0x05:P2=0x20;break; default:P2=0x01;break; } if(Lcounter>=5) //如果到了最邊上的第5 位,回到0位 { Lcounter=0; } else { Lcounter++; } } }