数码管由于内部由多段LED灯构成,也被称为多段式LED数码管。
从数码管里面包含的LED个数来分,可以分为七段式、八段式、十四段式等。
七段式数码管:
八段式数码管(比七段式右下角多了一个小点):
十四段式数码管:
从数码管电极性质来分可分为共阴数码管(CC)和共阳数码管(AC)。
共阴数码管内部所有的LED灯段的负极接在了一起,只需要给相应位高电平即可点亮一段。
共阳数码管只需给低电平即可点亮一段。
以八段共阳数码管为例:
A,B,C,D,E,F,G,DP分别对应数码管上的一段。
在程序中我们给A,G,D三段置低电平,点亮这三段数码管。
#include <reg52.h>
sbit a = P2^0;
sbit b = P2^1;
sbit c = P2^2;
sbit d = P2^3;
sbit e = P2^4;
sbit f = P2^5;
sbit g = P2^6;
sbit dp = P2^7;
void main()
{
a = 0;
b = 1;
c = 1;
d = 0;
e = 1;
f = 1;
g = 0;
dp = 1;
while(1);
}
(在这里我没有给单片机接晶振部分的时钟电路以及其他基本电路,是因为在proteus里面其实不需要接也能正常工作,仿真就是仿真,与实际工程中还是有很大的区别的,在实际过程中是一定要接的)
(如果你的数码管直接接在P0口没有亮的话是正常的,P0口要加上拉电阻做普通输入输出口)
看到这里也许会有小伙伴发出疑问:“51单片机总共就4组32个IO口,你控制一个八位数码管就要一组8位IO口,那不是最多就能控制4个八位数码管吗?怎么实现数码管电子时钟的效果呢?”。
孙大圣有了金箍棒才能战无不胜攻无不克成为斗战胜佛,我们也要找一个“金箍棒”来帮我们完成“西天取经”。
我们的“金箍棒”:74hc573,一个8位数据锁存器。
引脚功能描述:
引脚 | 功能 |
---|---|
OE(Output Enable,低电平有效) | 输出使能 |
1D~8D | 8位数据输入 |
1Q~8Q | 8位数据输出 |
LE(Latch Enable,高电平有效) | 锁存使能 |
74hc573功能表:
第一行/第二行:OE=0、LE=1时,输出端数据等于输入端数据。
第三行:OE=0、LE=0时,输出端数据保持为上一次数据不变。
第四行:OE=1,无论其他是高电平低电平,输出端为高阻态。
#include <reg52.h>
#include <intrins.h>
sbit LE = P3^0; //Ëø´æÊ¹ÄܶË
sbit OE = P3^1; //Êä³öʹÄܶË
//¹²Ñô¹ÜÊýÂë¹Ü±àÂë±í£º¶ÔÓ¦0~F
unsigned char table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
void Delay1000ms() //@11.0592MHz£¬ÀûÓÃSTC-ISP×Ô¶¯Éú³É±È½Ï¾«È·µÄÒ»ÃëÑÓʱ
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
unsigned int i = 0;
LE = 1; //Ëø´æÊ¹ÄÜ
OE = 0; //Êä³öʹÄÜ
while(1)
{
P2 = table[i];
Delay1000ms();
i++;
if(i > 15)
i = 0;
}
}
(第一次用GIF截屏工具,等到数码管回复到0还走了两下我再按的停止,这个程序绝对没有问题,狗头)
进行到这一步,这个数码管时钟你已经掌握了一大部分了,只需要再坚持一下就会出成果了。然而现在还存在的问题是,虽然完成了动态显示,但是似乎IO口还是少了,如果按这样的接线方式来看的话,那么在下一步,我们将解决这个问题。
既然一个数码管满足不了我们的要求,我们换一个多位数码管集成的元件:7SEG-MPX6-CC是7段六位共阴级数码管,通过给123456这几位低电平来点亮对应的位。
时钟的每一个位的是一直动态变化的,如果直接一次把123456这几位都打开那么数码管六个位显示的数据都一样,就像:
显然不是我们时钟想要的效果。
这时候就引进我们的段选和位选的概念。
段选就是选择数码管7段亮哪些段。
位选就是选择六位数码管中亮哪一位。
用很短的时间来完成6位数码管的依次显示,就是我们数码管时钟最精髓的思想了。
#include <reg51.h>
#include <intrins.h>
sbit LE = P3^0; //Ëø´æÊ¹ÄܶË
sbit OE = P3^1; //Êä³öʹÄܶË
sbit w1 = P3^2; //λѡ
sbit w2 = P3^3;
sbit w3 = P3^4;
sbit w4 = P3^5;
sbit w5 = P3^6;
sbit w6 = P3^7;
//¹²Òõ¹ÜÊýÂë¹Ü±àÂë±í
unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 9;
j = 244;
do
{
while (--j);
} while (--i);
}
void Timer0Init(void) //³õʼ»¯¶¨Ê±Æ÷0£¬50ms½øÒ»´ÎÖжÏ
{
TMOD &=0X0F;
TMOD |=0x01;
TH0 = (65536 - 50000)/256;
TL0 = (65536 - 50000)%256;
EA = 1;
ET0 = 1;
TR0 = 1;
}
static unsigned int j = 0;
unsigned int s1 = 5,s2 = 5,m1 = 9,m2 = 5,h1 = 3,h2 = 2; //23:59:55ʱ¼ä
void main()
{
Timer0Init();
LE = 1; //Ëø´æÊ¹ÄÜ
OE = 0; //Êä³öʹÄÜ
while(1)
{
w1=0;w2=1;w3=1;w4=1;w5=1;w6=1;
P2 = table[h2];
Delay5ms();
w1=1;w2=0;w3=1;w4=1;w5=1;w6=1;
P2 = table[h1]+0x80; //¼Ó0x80ÏÔʾСÊýµã£¬·Ö¸ôСʱ·ÖÖÓÃëÖÓ
Delay5ms();
w1=1;w2=1;w3=0;w4=1;w5=1;w6=1;
P2 = table[m2];
Delay5ms();
w1=1;w2=1;w3=1;w4=0;w5=1;w6=1;
P2 = table[m1]+0x80;
Delay5ms();
w1=1;w2=1;w3=1;w4=1;w5=0;w6=1;
P2 = table[s2];
Delay5ms();
w1=1;w2=1;w3=1;w4=1;w5=1;w6=0;
P2 = table[s1];
Delay5ms();
}
}
void interruptTimer0() interrupt 1 //Öжϴ¦Àíʱ¼ä½øÎ»
{
ET0 = 0;
TR0 = 0;
TH0 = (65536 - 50000)/256;
TL0 = (65536 - 50000)%256;
j++;
if(j >= 20)
{
s1++;
j = 0;
if(s1 > 9)
{
s1 = 0;
s2++;
if(s2 > 5)
{
s2 = 0;
m1++;
if(m1 > 9)
{
m1 = 0;
m2++;
if(m2 > 5)
{
m2 = 0;
h1++;
if(h2 < 2)
{
if(h1 > 9)
{
h1 = 0;
h2++;
}
}
else
{
if(h1 > 3)
{
h1 = 0;
h2 = 0;
m1 = 0;
m2 = 0;
s1 = 0;
s2 = 0;
}
}
}
}
}
}
}
ET0 = 1;
TR0 = 1;
}
(这里秒没有显示出来,是刷新率太短,要加延时,但是在proteus里面我试了很多值,要么显示秒钟有明显的一位一位亮起来的感觉,要么就不显示,大家也可以帮我解决一下)
在实际中不会出现这种不亮的情况,只会亮度低,如果亮度低了就加延时,若果肉眼分辨的出每位亮起的时间差就减少延时。
OK,祝大家五一劳动节快乐。