STC89C52驱动数码管
扫描二维码
随时随地手机看文章
1.硬件设计
数码管实验硬件设计中使用到的数码管是共阳极类型的。因为数码管的片选引脚“1/2/3/4”都通过
PNP 三极管来提供高电平,为什么要选用PNP 三极管和共阳极数码管的组合?因为共阳极数码管共阳端直
接接电源,不用接上来电阻,而共阴的则要,如此一来共阳极数码管亮度较高。再者用单片机控制时,单
片机上电和复位后所有的I/O 口都是高电平,只要单片机一上电,电路经过数码管的位流向共阴至地,耗
电大,不节能,所以又每次编写代码时都得把位控制端赋予低电平,太过麻烦,这样共阳极数码管就是好,
因为共阳极端要接电源,而位控制口又是高电平,则数码管不会亮,省去了每次编程赋值的麻烦。
P0.0~P0.3 作为共阳极数码管的为控制口,P0.4 和P0.5 作为共阳极数码管的字型码输入口。
2.软件设计
#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 //控制数码管字型码端口
unsigned char Timer0IRQEvent=0; //T/C0 中断事件
unsigned char Time1SecEvent=0; //定时1 秒事件
unsigned int TimeCount=0; //时间计数值
unsigned char SegCurPosition=0; //当前点亮的数码管
//为了验证共阳极的字型码是共阴极的反码,共阳极字型码为共阴极的反码
//共阳极字型码存储在代码区,用关键字"code"声明
code unsigned char SegCode[10]={~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,
~0x07,~0x7F,~0x6F};
//片选数码管数组,存储在代码区,用关键字"code"声明
code unsigned char SegPosition[4]={0xf7,0xfb,0xfd,0xfe};
//数码管显示数据缓冲区
unsigned char SegBuf[4] ={0};
void LS164Send(unsigned char byte)
{
unsigned char j;
for(j=0;j<=7;j++)//对输入数据进行移位检测
{
if(byte&(1<<(7-j))) //检测字节当前位
{
LS164_DATA(HIGH); //串行数据输入引脚为高电平
}
else
{
LS164_DATA(LOW); //串行数据输入引脚为低电平
}
LS164_CLK(LOW); //同步时钟输入端以一个上升沿结束确定该位的值
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; //熄灭所有数码管
t = SegCode[SegBuf[SegCurPosition]]; //确定当前的字型码
LS164Send(t);
SEG_PORT = SegPosition[SegCurPosition];//选中一个数码管来系显示
if(++SegCurPosition>=4) //下次要点亮的数码管
{
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) //检测定时中断事件是否产生
{
Timer0IRQEvent=0;
if(Time1SecEvent) //检测1 秒事件是否产生
{
Time1SecEvent=0;
if(++TimeCount>=9999)//计数值自加
{
TimeCount=0;
}
SegRefreshDisplayBuf();//刷新缓冲区
}
SegDisplay(); //点亮选中的数码管
}
}
}
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;
}
}