本文为学习笔记,自己对数码管显示也非常感兴趣,是通过一位讲“单片机抢答器”的UP主那里学到的,感兴趣的可以去看一下。其中up主对数码管显示原理以及扫描原理都讲的非常清楚。
电路仿真图
程序代码
#include <reg52.h>
//管脚定义
#define duanPore P0 //数码管段控制端口,高电平有效
sbit DIG1 = P2^4; //数码管第1位位选控制端口,低电平有效
sbit DIG2 = P2^5; //数码管第2位位选控制端口,低电平有效
sbit DIG3 = P2^6; //数码管第3位位选控制端口,低电平有效
sbit DIG4 = P2^7; //数码管第4位位选控制端口,低电平有效
//数码管段码表,适用于共阴数码管
unsigned char code tab_duan[]=
{
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f, //0~9
0x77,0x7c,0x39,0x5e,0x79,0x71 //A~F
};
unsigned char dat_buf[]={0,0,0,0}; //数据缓存区
int time = 20; //倒计时时间(自行设定,此程序支持两位数倒计时)
unsigned int count = 0; //计数缓存变量
/*定时器0初始化*/
void InitTimer0()
{
TMOD = 0x01; //配置定时器0为工作模式1,16位定时器
TH0 = (65536- 10000) / 256; //定时10ms
TH0 = (65536- 10000) % 256;
EA = 1; //打开总中断
ET0 = 1; //打开定时器0中断
TR0 = 1; //打开定时器0
}
/*定时器0中断服务函数,10ms进行一次中断*/
void Timer0Interrupt(void) interrupt 1
{
TH0 = (65536- 10000) / 256; //定时10ms,重新转载计数值
TL0 = (65536- 10000) % 256;
++count;
if(count == 100) //1s时间计算:10ms * 100 = 1s
{
count =0; //计数值清零
--time;
if(time<0){
time = 20;
} //倒计时时间减一次
}
}
/*数码管扫描延时*/
void DelayMs(unsigned int ms)
{
unsigned char a,b,c;
while(--ms){
for(c=1;c>0;c--)
for(b=142;b>0;b--)
for(a=2;a>0;a--);
}
}
/*数码管显示扫描*/
void dig_scan(unsigned char *dat)
{
static int i=0;
/*动态扫描处理*/
switch(i){
case 0:
duanPore = tab_duan[dat[0]]; //显示第1位数码管内容
DIG1 = 0; //选通第1位数码管
break;
case 1:
duanPore = tab_duan[dat[1]]; //显示第2位数码管内容
DIG2 = 0; //选通第2位数码管
break;
case 2:
duanPore = tab_duan[dat[2]]; //显示第3位数码管内容
DIG3 = 0; //选通第3位数码管
break;
case 3:
duanPore = tab_duan[dat[3]]; //显示第4位数码管内容
DIG4 = 0; //选通第4位数码管
break;
default: break;
}
DelayMs(10); //扫描延时10ms,应根据实际情况适当修改该延时时间(延时越长闪烁越会明显)
DIG1 = 1; //消隐
DIG2 = 1;
DIG3 = 1;
DIG4 = 1;
++i;
if(i>3){
i=0; //扫描变量循环
}
}
int main()
{
InitTimer0();
while(1){
dat_buf[2] = time / 10; //十位数
dat_buf[3] = time % 10; //个位数
dig_scan(dat_buf); //测试数码管显示
}
return 0;
}