数码管的学习
1.数码管的基本介绍
以上是数码管的基本原理图。a~g是8个LED小灯(8段),外围10条竖线是它的引脚。数码管分为共阳和共阴两种,共阳数码管就是8只LED小灯的阳极是连在一起的,通过控制阳极的电压来控制LED小灯的亮灭,同理我们可以理解共阴的含义。数码管上有两个COM口,它是数码管的公共端,因为公共端通过的电流较大,两个COM口就可以将电流分到两个引脚上,降低单条线路承受的电流。
ps:学习板上的数码管一般都是6位(6个数码管)共阳极的,如果单买的学习用的数码管4位就足够了,以下内容都以学习板上数码管为例。
2.数码管的控制
首先介绍两个概念:位选和段选。
*位选:选择某一个数码管进行操作。
*段选:选择数码管上某一段LED灯进行操作。
一般情况下编程过程中是先位选然后段选。
*数码管显示电路图:
由上图可知,和LED电路系统一样,数码管电路也是由三八译码器控制三极管导通来控制整个数码管的使能。由图可以看出,最右侧的数码管由三极管Q17控制,而Q17又由LEDS0控制,对应的就是三八译码器上的Y0输出口。由Y0口的输出值来控制Q17三极管的导通,进而控制该位数码管。
综上所述,三八译码器控制数码管的位选。
*数码管的段选可以由单片机的IO口直接控制(也可以在中间加一个74HC245驱动),单片机的P0端8个IO口可以直接按数码管的符号引脚图进行连接,进而通过IO口的输出值直接控制数码管每段的亮灭。
3.数码管的真值表
字符 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
数值 | 0xC0 | 0xF9 | 0xA4 | 0xB0 | 0x99 | 0x92 | 0x82 | 0xF8 |
字符 | 8 | 9 | A | B | C | D | E | F |
数值 | 0x80 | 0x90 | 0x88 | 0x83 | 0xC6 | 0xA1 | 0x86 | 0x8E |
该表格用在编程中,通过对P0口整体的赋值使数码管显示相应的数字符号,如写P0=0XC0,运行后的结果是数码管显示0。
4.数码管的静态显示
三八译码器在同一时刻只能让1个输出口为低电平,也就是说在一个十克内,只能使能一个数码管,并根据给出的P0的值来改变这个数码管的显示字符,这就输数码管的静态显示。
(在这里介绍一个关键字code,它起到对数据的修饰作用,它能使数据储存到程序空间FLASH中而不是RAM中,使数据在使用过程中无法发生改变。)
具体程序代码如下:
#include<reg52.h>
sbit ADDR0=P1^0;
sbit ADDR1=P1^1;
sbit ADDR2=P1^2;
sbit ADDR3=P1^3;
sbit ENLED=P1^4;,0x99
unsigned char code Led Char[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
void main()
{unsigned char cnt=0; //记录T0中断次数
unsigned char sec=0; //记录经过的秒数
ENLED=0;ADDR3=1;
ADDR2=0;
ADDR1=0;
TOMD=0x01;
THO=0xB8;
TLO=0x00;
TR0=1; //设置定时器
while(1)
{
if(TF0==1) //判断是否溢出
{
TF0=0; //溢出后清零中断标志
TH0=0xB8; //重新赋值
tl0=0x00;
cnt++; //计数值自动加1
if(cnt>=50) //判断是否溢出达到50次
{cnt=0;
P0=LedChar[sec]; //当前描述对应的真值表中的属值到P0口
sec++; //秒数自动加1
if(sec>=16) //当秒数超过15后,重新从0开始
{sec=0;}
}
}
}
}
*数码管的动态显示
*多个数码管显示数字时,实际上时轮流点亮数码管,利用人眼的”余晖效应“(视觉暂留现象),可以做到看起来多个数码管都亮了,这就是动态显示,也叫动态扫描。
*完成一次全部数码管的扫描时间 即整体扫描时间=单个数码管点亮时间-数码管个数。它的值应是10ms以内,事实上,刷新时间小于10ms就可以做到无闪烁,这也就是动态扫描的硬性指标。
以下是动态扫描的程序代码:
#include<reg52.h>
sbit ADDR0=P1^0;
sbit ADDR1=P1^1;
sbit ADDR2=P1^2;
sbit ADDR3=P1^3;
sbit ENLED=P1^4;,0x99
unsigned char code Led Char[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
void main()
{
unsigned char i=0; //动态扫描的索引
unsinged int cnt=0; //记录T0中断次数
unsigned long sec=0; //记录经过的秒数
unsigned char LedBuff[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} //数码管显示缓冲区
ENLED=0;
ADDR3=1; //因为需要动态改变数码管的位选,所以ADDR0~2不需要初始化了
TMOD=0x01;
TH0=0xFC; //定时1ms
TL0=0x67;
TR0=1;
while(1)
{
if(TF0==1)
{
TF0=0;
TH0=0xFC;
TL0=0x67;
cnt++;
if(cnt>=1000)
{
cnt=0;
sec++;
//以下代码将sec按十进制从低到高依次提取并转为数码管显示字符
LedBuff[0]=LedChar[sec%10];
LedBuff[1]=LedChar[sec/10%10];
LedBuff[2]=LedChar[sec/100%10];
LedBuff[3]=LedChar[sec/1000%10];
LedBuff[4]=LedChar[sec/10000%10];
LedBuff[5]=LedChar[sec/100000%10];
}
//以下代码王城数码管的动态扫描刷新
switch(i)
{
case 0:ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=LedBuff[0];break;
case 1:ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=LedBuff[1];break;
case 2:ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=LedBuff[2];break;
case 3:ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=LedBuff[3];break;
case 4:ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=LedBuff[4];break;
case 5:ADDR2=1;ADDR1=0;ADDR0=1;i=0;P0=LedBuff[5];break;
drfault:break;
}
}
}
}