元件说明

数码管介绍

LED数码管是一种简单、廉价的显示器,是由多个发光二极管封装在一起组成“8”字型的器件。

file

开发板上的数码管相关元件:

file

查询开发板原理图:

file

一位数码管引脚定义

file

右上为共阴极连接,右下为共阳极连接。3和8引脚表示共阴极或共阳极。

一位数码管上共有8个LED,正好与1字节相对应,并且51单片机也是8位单片机,这为我们操作数码管提供了很大便利。

图中从左到右的ABCDEFGDP是顺序的。而引脚编号却是乱序的,这是因为各个LED取就近的引脚来连接。通常使用ABCDEFGDP顺序来操作数码管。

file

例如,如果希望数码管显示数字6,则需要点亮ACDEFG。

对于共阴极连接,首先在共阴极接地,称为位选(相当于此位的开关,不位选的话这一位就不会亮。如果有多个数码管就需要位选希望显示的数码管)。之后在下方的电路中进行段选,依次输入10111110(称为段码)即可。

对于共阳极连接,在共阳极接入VCC(位选)。之后输入段码01000001(对应ABCDEFGDP,称为段选)即可。

四位数码管引脚定义

file

右上为共阴极连接,右下为共阳极连接。共阴极和共阳极单独引出(图中的12,9,8,6)。

需要哪个位显示就位选哪个位。段选方式与之前一样,不过不同位的相同段都连接在一起。

这种连接方式不能同时控制4位数码管显示4个不同的数字,因为各个段选端都接在一起。即使让它们同时亮,显示的内容也是一样的。为了使四位数码管各个位显示不同内容,通常会快速地交替显示各个位,利用人眼的余晖效应来达到同时显示不同内容的效果(动态数码管显示)。

例如,要让第三个数码管显示1,其他数码管不亮。对于共阴极连接,位选8,然后段选01100000即可。

138译码器 74HC138

74HC138,有时也会使用74LC138。

上述两个芯片在使用上基本没有区别,中间的字母表示电压、功耗上的差异。他们都属于较为古老的74系列。

主要用于通过3个引脚控制8个引脚,节省单片机IO口。此处用于数码管的位选。

file

引脚介绍

左上ABC为控制引脚,接在单片机IO口上。

右侧为输出引脚,接在2个4位数码管的8个共阴极端。引脚上方的横线表示低电平有效。

上下分别为VCC,GND。

左下为使能引脚。此处要使芯片工作,需要对G1输入1,对G2A和G2B输入0。

使用方法

3个输入端,每个有0和1两种状态,可以看做3位二进制数(C为最高位,A为最低位),能表示十进制0~7的8种状态,刚好就对应了右侧的8个输出端。

因为低电平有效,通过输入端选中的引脚会输出0,其余引脚输出1。因此被选中的引脚就可以位选共阴极数码管。同一时间只能有1个输出引脚有效。

双向数据缓冲器 74HC245

file

用于放大信号,增强驱动能力。单片机高电平驱动能力有限,而使用此芯片可以使用芯片外接电源来驱动,因此单片机只需提供控制信号。此处用于增强单片机驱动能力以进行段选。

引脚介绍

右下角输入电源VCC,GND。有时需要给VCC、GND之间加电容来进行电源滤波。

左下角OE(低电平有效)应该写作CE(Chip Enable 芯片使能),给其低电平就可以让芯片工作。

左下角DIR(Direction)控制信号方向,高电平从左到右,低电平从右到左。

左侧A接单片机,右侧B接数码管进行段选。

静态数码管显示

实现在第三个数码管上显示6。

在位选处,通过38译码器选择第三个数码管。

在段选处,从A到DP依次为1011 1110。注意在控制一整个寄存器输出时,由于高低位是反的,所以需要反着输出至P0,即0111 1101(0x7D)。

#include <REGX52.H>

void main()
{
    //位选,使38译码器选中Y5 -> LED6
    P2_4 = 1;
    P2_3 = 0;
    P2_2 = 1;
    //段选,输出6的段码
    P0 = 0x7D;
    while(1);
}

将控制数码管的代码函数化:

//0~9的段码
int nums[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};

void Nixie(char location, char num) //参数:显示位置和要显示的数字
{
    //位选
    location = 7 - location;
    P2_2 = (location >> 0) % 2;
    P2_3 = (location >> 1) % 2;
    P2_4 = (location >> 2) % 2;

    //段选
    P0 = nums[num];
}

将代码函数化,进一步优化程序:

#include <REGX52.H>

//0~9的段码
int nums[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};

void Nixie(char location, char num) //参数:显示位置和要显示的数字
{
    //位选
    location = 7 - location;
    P2_2 = (location >> 0) % 2;
    P2_3 = (location >> 1) % 2;
    P2_4 = (location >> 2) % 2;

    //段选
    P0 = nums[num];
}

void main()
{
    Nixie(2, 6);
    while(1);
}

效果:

file

动态数码管显示

目前的电路在同一时间只能在一位显示内容,因此我们控制单片机对其快速地扫描,利用人眼的余晖效应达到同时显示的效果。

    while(1)
    {
        Nixie(0, 1);
        Nixie(1, 2);
        Nixie(2, 3);
    }

但是按照上述思路,如果扫描速度太快会出现残影现象(显示123的图样):

file

原因是程序反复重复“位选-段选-位选-段选……”操作。但是在“段选-位选”时,选择完下一位,但上一位的段选数据还存在,所以会短暂地显示在下一位的位置上“窜位”。

解决方法是在每次位选之前将段选数据清零。

#include <REGX52.H>
#include <INTRINS.H>

void Delay(int xms)     //@11.0592MHz延时xms
{
    unsigned char i, j;
    while(xms--)
    {
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }

}

//0~9的段码
int nums[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};

void Nixie(char location, char num)
{
    location = 7 - location;
    P2_2 = (location >> 0) % 2;
    P2_3 = (location >> 1) % 2;
    P2_4 = (location >> 2) % 2;
    P0 = nums[num];

    Delay(1);   //清零前使其稳定显示1ms
    P0 = 0x00;  //清零
}

void main()
{
    while(1)
    {
        Nixie(0, 1);
        Nixie(1, 2);
        Nixie(2, 3);
    }
}

效果:

file

数码管的其他驱动方式

  • 使用单片机直接扫描数码管,硬件设备简单,但会耗费大量的单片机CPU时间。
    74HC595(需要单片机直接扫描,但可以通过3根数据线控制8个数码管):
    file

  • 而一些专用驱动芯片,内部自带显存、扫描电路,单片机只需告诉它显示什么即可。
    TM1640(可控制16个数码管):
    file