51单片机数码管实验

1.原理图

51单片机按键部分.jpg

该原理图所示,由38译码器(74HC138N),驱动芯片(74HC245),两个四位共阴数码管与STC89C52RC单片机芯片组成。

1.1 74HC138N

三八译码器为一种将三位二进制数转化为8个独立输出信号的译码器。 如将A0 A1 A2=1 1 0则转为八位数在Y0到Y7上输出0000 0100即Y6置为高电平.A0 A1 A2=111,则转为八位数在Y0到Y7上输出0000 0001即Y7置为高电平。 如上图,

image.png

image.png

CS1,CS2,CS3为三个片选信号输入端,当CS1置为1,CS2CS3同时置为0时,该译码器译码。 而该电路通过NPN型三极管与一个10kΩ电阻连接到P36可通过P36引脚置1置0来控制译码器工作。 当P36置为0时,此时三极管处于截止状态(b=0时,c=0,e=0),不导通,CS1为高电平,正常译码。当P36置为1时,此时三极管处于饱和状态,此时相当于开关的导通状态,此时集电极电压为0,CS1为低电平,停止译码。

1.2 74HC245驱动芯片

由于51单片高电平的驱动能力很微弱,不足以点亮数码管,因此可以使用74HC245N作为驱动芯片。 下图为单片机某一引脚内部结构,

image.png

2.软件设计

image.png

image.png

如上图,数码管位选通过P13,P14,P15实现,段选通过P00-P07实现。

#include <STC89C5xRC.H> //包含STC89C52的头文件

#include <INTRINS.H>

 

#define SMG_EN P36

 

// 增加自定义类型,简化代码编写

typedef unsigned char u8;

typedef unsigned int u16;

typedef unsigned long u32;

 

// 数码管显示缓存

static u8 s_digital_buffer[8];

 

// 数字0-9的编码

static char s_digital_codes[10] = {

    0x3F, // 0

    0x06, // 1

    0x5B, // 2

    0x4F, // 3

    0x66, // 4

    0x6D, // 5

    0x7D, // 6

    0x07, // 7

    0x7F, // 8

    0x6F  // 9

};

 

void DigitalTube_Refresh();

 

void DigitalTube_DisplayNum(u32 num);

 

void main()

{

    // 打开数码管总开关

    SMG_EN = 0;

    // 让数码管显示12345678

    DigitalTube_DisplayNum(12345678);

 

    // 不断刷新数码管

    while (1)

    {

        DigitalTube_Refresh();

    }

}

 

/**

 * @brief 将要显示的数字写进数码管的缓存

 *

 * @param num 要显示的数字

 */

void DigitalTube_DisplayNum(u32 num)

{

    u8 i;

    // 将显存清零

    for (i = 0; i < 8; i++)

    {

        s_digital_buffer[i] = 0;

    }

 

    // 如果待展示的数字为0,直接展示

    if (!num)

    {

        s_digital_buffer[7] = s_digital_codes[0];

        return;

    }

 

    // 赋值显存

    i = 7;

    while (num > 0)

    {

        // 对显存赋值,如果num是12345,则s_digital_buffer[]里面依次存储0,0,0,0x06,0x5B,0x4F,0x66,0x6D

        s_digital_buffer[i] = s_digital_codes[num % 10];

        i--;

        num /= 10;

    }

}

 

void Delay1ms(u16 count) //@11.0592MHz

{

    u8 i, j;

 

    while (count > 0)

    {

        count--;

        nop();

        i = 2;

        j = 199;

        do

        {

            while (--j)

                ;

        } while (--i);

    }

}

 

/**

 * @brief 让数码管的某一位显示特定的组合

 *

 * @param dig 片选,取值范围[0-7]

 * @param dat 段选信号

 */

static void DigitalTube_DisplaySingle(u8 dig, u8 dat)

{

    // 关掉当前数码管

    P0 = 0;

    // 完成片选

    P1 &= 0xC7; // 置零

    dig <<= 3;  // 左移

    P1 |= dig;

 

    // 段选

    P0 = dat;

}

 

void DigitalTube_Refresh()

{

    u8 i;

    // 依次刷新8位数码管

    for (i = 0; i < 8; i++)

    {

        DigitalTube_DisplaySingle(i, s_digital_buffer[i]);

        // 延时增加占空比

        Delay1ms(1);

    }

}