STC89C52驅(qū)動數(shù)碼管
1.硬件設(shè)計
數(shù)碼管實驗硬件設(shè)計中使用到的數(shù)碼管是共陽極類型的。因為數(shù)碼管的片選引腳“1/2/3/4”都通過
PNP 三極管來提供高電平,為什么要選用PNP 三極管和共陽極數(shù)碼管的組合?因為共陽極數(shù)碼管共陽端直
接接電源,不用接上來電阻,而共陰的則要,如此一來共陽極數(shù)碼管亮度較高。再者用單片機(jī)控制時,單
片機(jī)上電和復(fù)位后所有的I/O 口都是高電平,只要單片機(jī)一上電,電路經(jīng)過數(shù)碼管的位流向共陰至地,耗
電大,不節(jié)能,所以又每次編寫代碼時都得把位控制端賦予低電平,太過麻煩,這樣共陽極數(shù)碼管就是好,
因為共陽極端要接電源,而位控制口又是高電平,則數(shù)碼管不會亮,省去了每次編程賦值的麻煩。
P0.0~P0.3 作為共陽極數(shù)碼管的為控制口,P0.4 和P0.5 作為共陽極數(shù)碼管的字型碼輸入口。
2.軟件設(shè)計
#include "stc.h"
#define HIGH 1
#define LOW 0
#define LS164_DATA(x) {if((x))P0_4=1;else P0_4=0;}
#define LS164_CLK(x) {if((x))P0_5=1;else P0_5=0;}
#define SEG_PORT P0 //控制數(shù)碼管字型碼端口
unsigned char Timer0IRQEvent=0; //T/C0 中斷事件
unsigned char Time1SecEvent=0; //定時1 秒事件
unsigned int TimeCount=0; //時間計數(shù)值
unsigned char SegCurPosition=0; //當(dāng)前點(diǎn)亮的數(shù)碼管
//為了驗證共陽極的字型碼是共陰極的反碼,共陽極字型碼為共陰極的反碼
//共陽極字型碼存儲在代碼區(qū),用關(guān)鍵字"code"聲明
code unsigned char SegCode[10]={~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,
~0x07,~0x7F,~0x6F};
//片選數(shù)碼管數(shù)組,存儲在代碼區(qū),用關(guān)鍵字"code"聲明
code unsigned char SegPosition[4]={0xf7,0xfb,0xfd,0xfe};
//數(shù)碼管顯示數(shù)據(jù)緩沖區(qū)
unsigned char SegBuf[4] ={0};
void LS164Send(unsigned char byte)
{
unsigned char j;
for(j=0;j<=7;j++)//對輸入數(shù)據(jù)進(jìn)行移位檢測
{
if(byte&(1<<(7-j))) //檢測字節(jié)當(dāng)前位
{
LS164_DATA(HIGH); //串行數(shù)據(jù)輸入引腳為高電平
}
else
{
LS164_DATA(LOW); //串行數(shù)據(jù)輸入引腳為低電平
}
LS164_CLK(LOW); //同步時鐘輸入端以一個上升沿結(jié)束確定該位的值
LS164_CLK(HIGH);
}
}
void SegRefreshDisplayBuf(void)
{
SegBuf[0] =TimeCount; //個位
SegBuf[1] =TimeCount/10; //十位
SegBuf[2] =TimeCount/100; //百位
SegBuf[3] =TimeCount/1000; //千位
}
void SegDisplay(void)
{
unsigned char t;
SEG_PORT = 0x0F; //熄滅所有數(shù)碼管
t = SegCode[SegBuf[SegCurPosition]]; //確定當(dāng)前的字型碼
LS164Send(t);
SEG_PORT = SegPosition[SegCurPosition];//選中一個數(shù)碼管來系顯示
if(++SegCurPosition>=4) //下次要點(diǎn)亮的數(shù)碼管
{
SegCurPosition=0;
}
}
void TimerInit(void)
{
TH0 = (65536-5000)/256;
TL0 = (65536-5000)%6; //定時5MS
TMOD = 0x01; //T/C0 模式1
}
void Timer0Start(void)
{
TR0 = 1;
ET0 = 1;
}
void PortInit(void)
{
P0=P1=P2=P3=0xFF;
}
void main(void)
{
PortInit();
TimerInit();
Timer0Start();
SegRefreshDisplayBuf();
EA=1;
while(1)
{
if(Timer0IRQEvent) //檢測定時中斷事件是否產(chǎn)生
{
Timer0IRQEvent=0;
if(Time1SecEvent) //檢測1 秒事件是否產(chǎn)生
{
Time1SecEvent=0;
if(++TimeCount>=9999)//計數(shù)值自加
{
TimeCount=0;
}
SegRefreshDisplayBuf();//刷新緩沖區(qū)
}
SegDisplay(); //點(diǎn)亮選中的數(shù)碼管
}
}
}
void Timer0IRQ(void) interrupt 1
{
static unsigned int cnt=0;
TH0 = (65536-5000)/256;
TL0 = (65536-5000)%6; //重載初值
Timer0IRQEvent=1;
if(++cnt>=200)
{
cnt=0;
Time1SecEvent=1;
}
}