例如:1、硬件改为三位一体或二位一体数码管,只需修改Display_Scan()函数COM个数。
2、本例中,采用了共阴数码管,如果用在共阳数码管,只需修改相应段码表。
本程序使用P0口作为段码数据发送端,P2.0-P2.3作为数码管扫描选通,使用P0口时,因单片机内部没有上拉电阻,所以要外接上拉电阻(参考阻值470欧姆).
// STC89C52RC// +---------------+ // | |// | | Digital Number// | | _______________________// | | | __ __ __ __ |// | P0.0--P0.7|===>| | | | | | | | | |// | (a,b...g,h)| | |--| |--| |--| |--| | 4位共阴数码管// | | | |__|.|__|.|__|.|__|.|// | | -----------------------// | | | | | |// | | | | | |// | P2.7(COM3)|--------+ | | |// | | | | |// | P2.6(COM2)|-------------+ | |// | | | |// | P2.5(COM1)|------------------+ |// | | |// | P2.4(COM0)|-----------------------+// +---------------+
#include
// 函数声明
//=======================================================================
void DisplayNumber(unsigned int Num);
void delayms( int ms);
//=======================================================================
unsigned char code LED_table[]={ //使用附带“51单片机工具箱”可以很容易编码
0x3f, //"0"
0x06, //"1"
0x5b, //"2" AAAA
0x4f, //"3" F B
0x66, //"4" F B
0x6d, //"5" GGGG
0x7d, //"6" E C
0x07, //"7" E C
0x7f, //"8" DDDD H
0x6f, //"9"
0x00, //black
0x80 //dot
};
#define black 10 // 空白
#define dot 11 // 小数点
unsigned char DisBuff[4]; //定义显示缓冲数组
unsigned char COM;
// 定义通信端口
//===========================================================================
sbit COM0=P2^4;
sbit COM1=P2^5; //对应口线由硬件确定
sbit COM2=P2^6;
sbit COM3=P2^7;
//===========================================================================
void Sys_Init()
{
TMOD=0x01; //定时器/计数器0为定时器方式16位工作模式
TH0=(65536-1000)/256; //初始时间常数
TL0=(65536-1000)%6; //1.0ms
ET0=1; //定时器/计数器0中断允许
EA=1; //总中断允许
TR0=1; //启动定时器/计数器开始工作
}
void DisplayNumber(unsigned int Num) //显示程序
{
unsigned char i;
EA=0; //禁止总中断
for(i=0;i<4;i++)
{
DisBuff[i]=Num; //拆分数字
Num/=10;
}
for(i=3;i>=0;i--) //循环4次
{
if (DisBuff[i]==0) DisBuff[i]=black; //消隐无效"0"
else break; //例如将 0123 改成 123,仅显示有效数字
}
EA=1; //总中断允许
}
void Display_Scan() interrupt 1 // 中断服务程序,数码管选通扫描
{
TR0=0;
TH0=(65536-1000)/256; //高8位和低8位时间常数
TL0=(65536-1000)%6;
TR0=1; //启动定时器0
if(COM>3) COM=0;
COM0=COM1=COM2=COM3=1; //将COM0-COM3置1,全暗
switch(COM)
{
case 0: P0=LED_table[DisBuff[0]]; COM0=0; break; //分别选通COM0-COM3 低电平有效
case 1: P0=LED_table[DisBuff[1]]; COM1=0; break;
case 2: P0=LED_table[DisBuff[2]]; COM2=0; break;
case 3: P0=LED_table[DisBuff[3]]; COM3=0; break;
} // 与decp(0x20)位或,恰好点亮小数点位段
COM++;
}
void delayms(int ms)
{
unsigned int i;
for(;ms>0;ms--) //循环ms次
{
for(i=0;i<123;i++); // for(i=0;i<123;i++); 每次1ms延迟@ 12.0MHz
} // for(i=0;i<113;i++); 每次1ms延迟@ 11.0592MHz
}
void main()
{
unsigned int i; //定义变量
Sys_Init(); //初始化timer0
while(1) //死循环,单片机必须是死循环
{
DisplayNumber(i); //调用数码管显示函数
delayms(200); //调用延时函数,使显示数字保持一段时间
i++; //这里演示一个数字累加的程序
//也可以直接写一个常数用来显示,看实际效果
} //例如DisplayNumber(1234); 编译后将HEX文件
} //下载到学板里应该正常显示数字 1234 。
// 另一种段编码方法
//===========================================================================
//宏定义,数码管a-g各段对应的比特,更换硬件只用改动以下8行
#define a 0x04 // AAAA
#define b 0x01 // F B
#define c 0x10 // F B
#define d 0x40 // GGGG
#define e 0x80 // E C
#define f 0x02 // E C
#define g 0x08 // DDDD H
#define h 0x20
//用宏定义自动生成段码表,很好的写法,值得学习
//更换硬件无需重写段码表
unsigned char code LED_table[]={
a+b+c+d+e+f, //"0"
b+c, //"1"
a+b+d+e+g, //"2"
a+b+c+d+g, //"3"
b+c+f+g, //"4"
a+c+d+f+g, //"5"
a+c+d+e+f+g, //"6"
a+b+c, //"7"
a+b+c+d+e+f+g, //"8"
a+b+c+d+f+g, //"9"
b+c+e+f+g, //"H"
a+f+e+g, //"C"
d+e+f, //"L"
g, //"-"
0x00 //black
};
#undef a
#undef b
#undef c
#undef d
#undef e
#undef f
#undef g