STC89C52驅(qū)動(dòng)數(shù)碼管
掃描二維碼
隨時(shí)隨地手機(jī)看文章
1.硬件設(shè)計(jì)
數(shù)碼管實(shí)驗(yàn)硬件設(shè)計(jì)中使用到的數(shù)碼管是共陽(yáng)極類型的。因?yàn)閿?shù)碼管的片選引腳“1/2/3/4”都通過(guò)
PNP 三極管來(lái)提供高電平,為什么要選用PNP 三極管和共陽(yáng)極數(shù)碼管的組合?因?yàn)楣碴?yáng)極數(shù)碼管共陽(yáng)端直
接接電源,不用接上來(lái)電阻,而共陰的則要,如此一來(lái)共陽(yáng)極數(shù)碼管亮度較高。再者用單片機(jī)控制時(shí),單
片機(jī)上電和復(fù)位后所有的I/O 口都是高電平,只要單片機(jī)一上電,電路經(jīng)過(guò)數(shù)碼管的位流向共陰至地,耗
電大,不節(jié)能,所以又每次編寫代碼時(shí)都得把位控制端賦予低電平,太過(guò)麻煩,這樣共陽(yáng)極數(shù)碼管就是好,
因?yàn)楣碴?yáng)極端要接電源,而位控制口又是高電平,則數(shù)碼管不會(huì)亮,省去了每次編程賦值的麻煩。
P0.0~P0.3 作為共陽(yáng)極數(shù)碼管的為控制口,P0.4 和P0.5 作為共陽(yáng)極數(shù)碼管的字型碼輸入口。
2.軟件設(shè)計(jì)
#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; //定時(shí)1 秒事件
unsigned int TimeCount=0; //時(shí)間計(jì)數(shù)值
unsigned char SegCurPosition=0; //當(dāng)前點(diǎn)亮的數(shù)碼管
//為了驗(yàn)證共陽(yáng)極的字型碼是共陰極的反碼,共陽(yáng)極字型碼為共陰極的反碼
//共陽(yáng)極字型碼存儲(chǔ)在代碼區(qū),用關(guān)鍵字"code"聲明
code unsigned char SegCode[10]={~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,
~0x07,~0x7F,~0x6F};
//片選數(shù)碼管數(shù)組,存儲(chǔ)在代碼區(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++)//對(duì)輸入數(shù)據(jù)進(jìn)行移位檢測(cè)
{
if(byte&(1<<(7-j))) //檢測(cè)字節(jié)當(dāng)前位
{
LS164_DATA(HIGH); //串行數(shù)據(jù)輸入引腳為高電平
}
else
{
LS164_DATA(LOW); //串行數(shù)據(jù)輸入引腳為低電平
}
LS164_CLK(LOW); //同步時(shí)鐘輸入端以一個(gè)上升沿結(jié)束確定該位的值
LS164_CLK(HIGH);
}
}
void SegRefreshDisplayBuf(void)
{
SegBuf[0] =TimeCount; //個(gè)位
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];//選中一個(gè)數(shù)碼管來(lái)系顯示
if(++SegCurPosition>=4) //下次要點(diǎn)亮的數(shù)碼管
{
SegCurPosition=0;
}
}
void TimerInit(void)
{
TH0 = (65536-5000)/256;
TL0 = (65536-5000)%6; //定時(shí)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) //檢測(cè)定時(shí)中斷事件是否產(chǎn)生
{
Timer0IRQEvent=0;
if(Time1SecEvent) //檢測(cè)1 秒事件是否產(chǎn)生
{
Time1SecEvent=0;
if(++TimeCount>=9999)//計(jì)數(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;
}
}