#include <reg51.h> sbit dula=P2^6; sbit wela=P2^7; sbit P34=P3^4; char Tab [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //共阴极数码管0到f的短编码 unsigned char Dat[4]={0xf7,0xfb,0xfd,0xfe}; unsigned char Second=0; unsigned long i,c=0; void main() { char t; char b[2]; TMOD=0x01; TR0=1; TH0=(65536-46080)/256; TL0=(65536-46080)%256; ET0=1; //允许T0中断 EA=1; //允许所有中断 while(1) { b[3]=c/1000; //千 b[2]=c/100%10; //百 b[1]=c/10%10; //十 b[0]=c%10; //个 for(t=0;t<2;t++){ //t是多少个数码管显示 P0=Tab[b[t]]; dula=1;dula=0; P0=Dat[t]; wela=1;wela=0; for(i=0;i<2;i++); P0=0xFF; }}} /*定时器0中断服务子程序*/ void time0() interrupt 1 { TH0= (65536-46080)/256; TL0= (65536-46080)%256; i++; if(i==1){ i=0; c++; if(c>=20) c=0; //计数到20秒自动回0 } }
数码管原理(显示)及编码(段码)
常用的7段数码管由发光二极管(组合)构成,如下图:
分为:共阳极和共阴极(如上图)
如果显示“0”,共阳极为:abcdefg dp ,dp为对应最高位,a为对应最低位,编码:11000000 ,16进制0xC0,共阴极正好相反:00111111,16进制0x3f。
以此类推。
共阳极数码管的0 到f的段编码:
0xc0,0xf9,0xa4,0xb0,//0~3
0x99,0x92,0x82,0xf8,//4~7
0x80,0x90,0x88,0x83,//8~b
0xc6,0xa1,0x86,0x8e //c~f
共阴极数码管0到f的短编码:
0x3f,0x06,0x5b,0x4f, //0~3
0x66,0x6d,0x7d,0x07, //4~7
0x7f,0x6f,0x77,0x7c, //8~b
0x39,0x5e,0x79,0x71 //c~f
这段代码是一个基于单片机的数字时钟,具体实现了以下功能:
- 通过四个共阴数码管显示当前时刻,每秒更新一次;
- 使用定时器0作为计时器,每隔50ms产生一次中断,从而实现秒表计时功能;
- 将计时结果(单位为秒)以“xx.xx”形式显示在第一个数码管上,最多可以计时20秒。
下面是对这段代码的详细分析:
首先,在 main 函数中,定义了一些变量,包括:
- Tab:数字 0~9 在数码管上的显示码表;
- Dat:数码管控制位模式表;
- Second:用于存储当前时间的秒数,初始值为 0;
- i:用于计时的计数器,初始值为 0;
- c:用于秒表计时的计数器,初始值为 0。
接着,在 main 函数中,初始化定时器0,并开启 T0 中断和全局中断使能。
随后进入主循环,其中先通过将计数值 c 格式化为四个数字,存储在数组 b 中。循环遍历数组 b,依次将每个数字通过选择相应的码表值和数码管控制位模式,发送给数码管进行显示。
在 T0 中断服务子程序 time0 中,首先重新加载定时器初值,然后每隔一定周期执行一次计时操作:将计数值 i 加 1,如果 i 达到指定阈值(50ms),则将当前秒表计数值 c 加 1,并判断是否超过20秒,如果超过则将其清零。
需要注意的是,此代码仅仅是一个简单的实现,还存在一些问题。例如,由于使用了延时函数,这会影响程序的实时性。而且,由于只在主循环中更新时钟显示,如果程序在处理其他任务时比较繁忙,则可能导致时钟显示出现明显的卡顿或错误。因此,在实际应用中需要对代码进行进一步的优化和改进。