前言

上一次实验,完成流水灯。本次实验,将学习开发板上的新器件——数码管,可以显示数字和其他信息的电子器件。

一、数码管介绍

1.1 数码管简介

数码管可分为七段和八段,区别在于是否包含小数点——dp。本实验使用的是八段数码管。每一段是一个LED灯,数码管通过LED灯亮灭组合显示不同数字和字母。如图1.1所示。

51单片机实验2:动态数码管显示_嵌入式

图1.1 数码管

1.2 数码管连接方式

共阳极数码管是指将所有发光二极管的阳极接到一起形成公共阳极的数码管,共阳极数码管在应用时将公共端接到+5V。如图1.2.1所示。

51单片机实验2:动态数码管显示_动静态数码管_02

图1.2.1 共阳极接法

共阴极数码管是指将所有发光二极管的阳极接到一起形成公共阴极的数码管,共阴极数码管在应用时将公共端接到GND。如图1.2.2所示。

51单片机实验2:动态数码管显示_动静态数码管_03

图1.2.2 共阴极接法

二、硬件设计

2.1 74HC138译码器

译码器的逻辑功能是将每个输入的二进制代码译成对应的输出高、低电平或另外一个代码。74HC138就是CMOS门电路组成的3线-8线译码器。逻辑框图如2.1.1所示。

51单片机实验2:动态数码管显示_嵌入式_04

图2.1.1 74HC138逻辑框图

74HC138管脚说明如2.1.2所示。

51单片机实验2:动态数码管显示_单片机_05

                               图2.1.2 74HC138管脚说明图

真值表(输入高电平有效,输出低电平有效)如图2.1.3所示。

51单片机实验2:动态数码管显示_单片机_06

                                       图2.1.3 真值表

2.2 数码管电路原理图

电路图如图2.2.1、图2.2.2所示。

51单片机实验2:动态数码管显示_数码管_07

图2.2.1 数码管电路图

74HC245的作用是驱动数码管。

51单片机实验2:动态数码管显示_单片机_08

图2.2.2 74HC138电路图

P0口是段选,LEDx(x=1~8)是位选。图来源普中51单片机A2板。

三、程序设计

数码管显示有两种方法显示。

3.1 法一

  1. 创建数码管显示函数。
void display(u8 dat[], u8 pos1)//dat[]显示信息,pos1为数码管显示位置
{
    u8 i= 0;
    u8 pos = pos1 - 1;
    for (i = pos; i < 8; i++) {
        switch (i) {
            case 0:LSC = 1;LSB = 1;LSA = 1;break;
            case 1:LSC = 1;LSB = 1;LSA = 0;break;
            case 2:LSC = 1;LSB = 0;LSA = 1;break;
            case 3:LSC = 1;LSB = 0;LSA = 0;break;
            case 4:LSC = 0;LSB = 1;LSA = 1;break;
            case 5:LSC = 0;LSB = 1;LSA = 0;break;
            case 6:LSC = 0;LSB = 0;LSA = 1;break;
            case 7:LSC = 0;LSB = 0;LSA = 0;break;
        }
        PORT = gsmg_code[dat[i-pos]];
        delay_10us(10);//消影
        PORT = 0x00;
    }
}
  1. 创建主函数。
void main()
{
    u8 dat[8] = {1, 2, 3, 4, 5, 6, 7,8};
    while (1)
    {
    display(dat,1);//display(dat,8);是静态数码管
    } 
}

3.2 法二

  1. 创建数码管段码储存函数。
void seg(unsigned char *buf, unsigned char *code1)//地址传参,buf显示信息,code1保存段码的数组
{
    unsigned char i, j, temp;
    for (i = 0, j = 0; i < 8; i++, j++) {
        switch (*buf++) {//*buf++ ==buf[j],指针运算
            case '0':temp = 0x3f;break;
            case '1':temp = 0x06;break;
            case '2':temp = 0x5b;break;
            case '3':temp = 0x4f;break;
            case '4':temp = 0x66;break;
            case '5':temp = 0x6d;break;
            case '6':temp = 0x7d;break;
            case '7':temp = 0x07;break;
            case '8':temp = 0x7f;break;
            case '9':temp = 0x6f;break;
            case ' ':temp = 0x00;break;
            default:break;
        }
        *(code1++) = temp;//*(code1++)=code1[j]
    }
}
  1. 创建显示函数。
void disp(unsigned char *code1, unsigned char pos)//pos数码管显示位置
{
    P2=0X00;//初始P2口的状态
    for (int i = 0; i <= pos - 1; i++) {
        P2 = i << 2;
        P0 = *code1++;
        delay_10us(100);//消影
        P0 = 0X00;
    }
}
  1. 创建主函数。
int main()
{
    unsigned char buf[8] ="12345678";
    seg(buf, code1);
    while (1) {
        disp(code1, 8);//disp(code1, 1);是静态数码管
    }

    return 0;
}


四、程序测试

4.1 法一现象

51单片机实验2:动态数码管显示_嵌入式_09

4.2 法二现象

51单片机实验2:动态数码管显示_单片机_10

4.3 现象分析

数码管显示相反,LED灯显示不同;原因在于:

void disp(unsigned char *code1, unsigned char pos)//pos数码管显示位置
{
    P2=0X00;//初始P2口的状态
    for (int i = 0; i <= pos - 1; i++) {
        P2 = i << 2;
        P0 = *code1++;
        delay_10us(100);//消影
        P0 = 0X00;
    }
}//部分代码

假设pos=2,i=0,P2=0<<2;P22=0,P23=0,P24=0;LED灯全亮,138译码器输出LED1=0;i=1,P2=1<<2,实际P2=0x1<<2,P2=0x04;P22=1,P23=0,P24=0;LED3不亮,LED2=0,加上LED1=0,那么就有两个数码管工作。但是LED灯是共阳极,在视觉感觉全亮。数码管显示相反,也与P2 = i << 2有关。

case 0:LSC = 1;LSB = 1;LSA = 1;break;
case 1:LSC = 1;LSB = 1;LSA = 0;break;
case 2:LSC = 1;LSB = 0;LSA = 1;break;
case 3:LSC = 1;LSB = 0;LSA = 0;break;
case 4:LSC = 0;LSB = 1;LSA = 1;break;
case 5:LSC = 0;LSB = 1;LSA = 0;break;
case 6:LSC = 0;LSB = 0;LSA = 1;break;
case 7:LSC = 0;LSB = 0;LSA = 0;break;//部分代码

只是提供P22,P23,P24,其余的没有用上,导致不亮。

五、总结

本文介绍数码管显示原理,通过程序数码管动态显示。静态数码管显示在代码中有标注。即可实现静态显示。

附录

完整代码

法一:

#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define PORT          P0
#define LSA           P22
#define LSB           P23
#define LSC           P24
//段码表
u8 gsmg_code[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,
                    0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};

void delay_10us(u16 ten_us)
{
    while (ten_us--);
}
void display(u8 dat[], u8 pos1)//dat[]显示信息,pos1为数码管显示位置
{
    u8 i= 0;
    u8 pos = pos1 - 1;
    for (i = pos; i < 8; i++) {
        switch (i) {
            case 0:LSC = 1;LSB = 1;LSA = 1;break;
            case 1:LSC = 1;LSB = 1;LSA = 0;break;
            case 2:LSC = 1;LSB = 0;LSA = 1;break;
            case 3:LSC = 1;LSB = 0;LSA = 0;break;
            case 4:LSC = 0;LSB = 1;LSA = 1;break;
            case 5:LSC = 0;LSB = 1;LSA = 0;break;
            case 6:LSC = 0;LSB = 0;LSA = 1;break;
            case 7:LSC = 0;LSB = 0;LSA = 0;break;
        }
        PORT = gsmg_code[dat[i-pos]];
        delay_10us(10);//消影
        PORT = 0x00;
    }
}
void main()
{
    u8 dat[8] = {1, 2, 3, 4, 5, 6, 7,8};
    while (1)
    {
    display(dat,1);//display(dat,8);是静态数码管
    } 
}

法二:

#include "reg52.h"
unsigned char code1[8];
unsigned char pos;
void seg(unsigned char *buf, unsigned char *code1)//地址传参,buf显示信息,code1保存段码的数组
{
    unsigned char i, j, temp;
    for (i = 0, j = 0; i < 8; i++, j++) {
        switch (*buf++) {//*buf++ ==buf[j],指针运算
            case '0':temp = 0x3f;break;
            case '1':temp = 0x06;break;
            case '2':temp = 0x5b;break;
            case '3':temp = 0x4f;break;
            case '4':temp = 0x66;break;
            case '5':temp = 0x6d;break;
            case '6':temp = 0x7d;break;
            case '7':temp = 0x07;break;
            case '8':temp = 0x7f;break;
            case '9':temp = 0x6f;break;
            case ' ':temp = 0x00;break;
            default:break;
        }
        *(code1++) = temp;//*(code1++)=code1[j]
    }
}
void delay_10us(unsigned int ten_us)
{
    while (ten_us--);
}
void disp(unsigned char *code1, unsigned char pos)//pos数码管显示位置
{
    P2=0X00;//初始P2口的状态
    for (int i = 0; i <= pos - 1; i++) {
        P2 = i << 2;
        P0 = *code1++;
        delay_10us(100);//消影
        P0 = 0X00;
    }
}
int main()
{
    unsigned char buf[8] ="12345678";
    seg(buf, code1);
    while (1) {
        disp(code1, 8);//disp(code1, 1);是静态数码管
    }

    return 0;
}