【51单片机】(三)数码管(原理,静态、动态显示)
一.数码管基础知识四位一体数码管:数码管电路原理:与之有关的元件——“138译码器”:①想要点亮一个数码管并让其显示数字,我们需要操作两个端口,给两个端口不同的电平。我们的单片机数码管上端是共阴极的,所以发光的条件是上端赋予低电平,下端赋予高电平。【通俗理解:上方LED端口选择要点亮哪一个数码管;下方abcdefg端口确定点亮什么数字。】(1)数码管上方有8个接口LED1~8,分别对应接到“译码器
一.数码管基础知识
四位一体数码管:
数码管电路原理:
与之有关的元件——“138译码器”:
①想要点亮一个数码管并让其显示数字,我们需要操作两个端口,给两个端口不同的电平。我们的单片机数码管上端是共阴极的,所以发光的条件是上端赋予低电平,下端赋予高电平。
【通俗理解:上方LED端口选择要点亮哪一个数码管;下方abcdefg端口确定点亮什么数字。】
(1)数码管上方有8个接口LED1~8,分别对应接到“译码器”的右输出端。译码器的左端连接单片机的3个P2口。(具体如何用三个P2口控制8个LED输出口,后面会单独讲解)
(2)每一体数码管下方引出abcdefg和dp共八个接口,分别对应点亮一个LED长条(图中有标注)或是小数点,点亮几个就可以组合成一个数字。这八个接口接到74HC245缓冲器的右输出端,而74HC245的左端连接单片机的8个P0口。74HC245左右端一一对应(A0-B0,A1-B1……)。
(缓冲器是用来提高单片机驱动能力的一个元件,VCC可以增强信号强度)
比如我现在想让LED6数码管发出“3”的数字。那么,上方接口所赋予的电平情况应该是(从左往右)1101 1111;下方接口接通abcdg,应该是(从左往右)1111 0010。但是,
我们在缓冲器左端传入的二进制必须从高位往低位读取。
比如,现在从左往右端口是1111 0010,但是P0输入端输入的是0100 1111,也就是P0=0x4F。
为了方便,这里总结数码管段码表:
②数码管静态显示时,只能让其中一个数码管发光。也就是说,在同一时间,上端接口只能保证有一个输入0。(具体原因见“译码器”工作方法)
③译码器工作方法:
左端输入端输入的信号按CBA排序,组成一个三位的二进制数,再将这个二进制数转化为十进制数,这个十进制数对应右端输出端的下标,这个输出端将会输出低电平。
比如输入:A : 0 、B : 1 、C : 1,排序为110,转十进制为6,Y6口(对应LED7)将会输出低电平,其他端口均输出高电平。
二.数码管静态显示
根据之前的讲解,不难写出代码了:
这个代码可以让数码管LED3显示数字“3”。
#include<regx52.h>
void main()
{
P2_4=0; P2_3=1; P2_2=0; //CBA:010
P0=0x4F; //OUTPUT 3:abcdg -> 1111 0010 -> 0100 1111 -> 0x4F
while(1)
{
}
}
为了方便操作,我们将数码管每一个位置的数字显示封装在函数中。
①首先,使用段码表,初始化一个数组NixieTable,后面可以直接调用,显示数字。
②其次用分支语句写出所有数码光发光的情况。(P2端口)
void Nixie(int LED,int number)
{
char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00}
switch(LED) //CBA
{
case 1: P2_4=0; P2_3=0; P2_2=0; break;
case 2: P2_4=0; P2_3=0; P2_2=1; break;
case 3: P2_4=0; P2_3=1; P2_2=0; break;
case 4: P2_4=0; P2_3=1; P2_2=1; break;
case 5: P2_4=1; P2_3=0; P2_2=0; break;
case 6: P2_4=1; P2_3=0; P2_2=1; break;
case 7: P2_4=1; P2_3=1; P2_2=0; break;
case 8: P2_4=1; P2_3=1; P2_2=1; break;
}
P0=NixieTable[number];
}
当然,我们可以把函数改的人性化一些。内部LED1~8序号是从右往左的,我们在写函数的时候,可以反一反。
三.数码管动态显示
由于数码管在同一时间只能静态显示一个数字,那么如果我们让多个数字同时显示,该怎么办呢?
我们可以让这些LED按顺序以极高的频率快速闪烁,在人眼看来就是同时显示。
有了这样的方法,我们先付诸实践:(略去函数部分)
void main()
{
while(1)
{
Nixie(1,1);
Nixie(2,2);
Nixie(3,3);
}
}
但是,实际上的效果却是:虽然显示了321,但是每个数字不该点亮的灯条会有一些模糊的光泛出:
这显然是不符合我们的预期的。原因是单片机在操作“段选->位选”的时候,速度很快,可能会篡位,导致顺序错乱。
于是,我们在数码管动态显示时,还必须完成一步“消影”操作。
在Nixie函数中,每一次“位选->段选”操作完,在极短的时间之内,完成将P0清零(P0=0x00;)的操作。
void Nixie(int LED,int number)
{
char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00};
switch (LED) //CBA
{
case 1: P2_4=0; P2_3=0; P2_2=0; break;
case 2: P2_4=0; P2_3=0; P2_2=1; break;
case 3: P2_4=0; P2_3=1; P2_2=0; break;
case 4: P2_4=0; P2_3=1; P2_2=1; break;
case 5: P2_4=1; P2_3=0; P2_2=0; break;
case 6: P2_4=1; P2_3=0; P2_2=1; break;
case 7: P2_4=1; P2_3=1; P2_2=0; break;
case 8: P2_4=1; P2_3=1; P2_2=1; break;
}
P0=NixieTable[number];
Delay(100); //<----------------------
P0=0x00; //<-----------------------
}
这样执行之后,就不会出现残影了。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)