单片机:实现数码管动态显示(0~99999999)74hc138驱动(附带源码)

单片机实现数码管动态显示(0~99999999)并使用74HC138驱动

在本项目中,我们将介绍如何在单片机上实现一个八位数码管(显示0到99999999)的动态显示,并使用74HC138解码器来控制数码管的选择。74HC138是一种常见的3线至8线解码器,可以通过它来控制8个数码管的显示位置,使得我们能够动态地切换每个数码管并显示相应的数字。

1. 项目需求分析

目标:
  1. 八位数码管显示:在8个数码管上动态显示一个8位数字,支持0到99999999的数字显示。
  2. 使用74HC138解码器驱动:通过74HC138解码器控制8个数码管的位置,实现动态显示。
  3. 数码管显示内容:每个位数显示0-9的数字,通过动态扫描显示多个数字。
功能需求:
  1. 动态扫描显示:使用定时器中断周期性地切换数码管显示的位置。
  2. 数字显示:控制数码管显示对应的数字。
  3. 使用74HC138控制显示:通过74HC138的选择端(A、B、C)控制数码管的显示位置。
  4. 简易数字递增:为了方便观察效果,模拟数字从0到99999999递增并在数码管上显示。

2. 硬件设计

2.1 单片机选择

选择51系列单片机(如AT89C51)作为开发平台,原因是该单片机具有足够的I/O端口,适合控制多个数码管,并且资源较为丰富,便于开发。

2.2 数码管与74HC138解码器连接
  • 74HC138解码器:它有3个输入端(A、B、C)用于选择8个输出端(Y0至Y7)。每个输出端对应一个数码管,输入端控制哪个数码管被选中。
  • 数码管:使用8个共阴或共阳的七段数码管,通过单片机的端口控制每个数码管的段选。
  • 连接设计
  • 74HC138的输出端连接到每个数码管的位选端。
  • 每个数码管的段选端连接到单片机的GPIO口。
  • 2.3 数码管段选数据表

    每个数字(0-9)对应的七段数码管的显示,可以使用一个数组来表示每个数字的段选状态(即每个数字的显示对应于7个段的开关状态)。

    // 数码管段选数据(共阴,0表示亮,1表示灭)
    unsigned char code digit[] = {
        0x3F,  // 0
        0x06,  // 1
        0x5B,  // 2
        0x4F,  // 3
        0x66,  // 4
        0x6D,  // 5
        0x7D,  // 6
        0x07,  // 7
        0x7F,  // 8
        0x6F   // 9
    };
    

    3. 软件设计

    3.1 定时器中断

    使用定时器中断来实现数码管的动态扫描。定时器定时触发中断,每次中断发生时,我们依次切换不同的数码管进行显示。

    3.2 代码实现
    #include <reg51.h>  // 包含51系列单片机的寄存器定义文件
    
    // 数码管段选数据(共阴,0表示亮,1表示灭)
    unsigned char code digit[] = {
        0x3F,  // 0
        0x06,  // 1
        0x5B,  // 2
        0x4F,  // 3
        0x66,  // 4
        0x6D,  // 5
        0x7D,  // 6
        0x07,  // 7
        0x7F,  // 8
        0x6F   // 9
    };
    
    // 定义74HC138的输入端口(A, B, C)
    sbit A = P3^0;  // 74HC138的A端连接到P3.0
    sbit B = P3^1;  // 74HC138的B端连接到P3.1
    sbit C = P3^2;  // 74HC138的C端连接到P3.2
    
    // 数码管的段选端口(假设连接在P2端口)
    sbit SEG_A = P2^0;
    sbit SEG_B = P2^1;
    sbit SEG_C = P2^2;
    sbit SEG_D = P2^3;
    sbit SEG_E = P2^4;
    sbit SEG_F = P2^5;
    sbit SEG_G = P2^6;
    
    // 定义一个8位数字
    unsigned long display_number = 0;  // 当前显示的数字,最大可显示到99999999
    
    // 数码管显示函数
    void display_digit(unsigned char position, unsigned char number) {
        // 根据数字选择相应的段选数据
        unsigned char seg = digit[number];  // 获取数字对应的段选数据
        
        SEG_A = (seg >> 0) & 0x01;
        SEG_B = (seg >> 1) & 0x01;
        SEG_C = (seg >> 2) & 0x01;
        SEG_D = (seg >> 3) & 0x01;
        SEG_E = (seg >> 4) & 0x01;
        SEG_F = (seg >> 5) & 0x01;
        SEG_G = (seg >> 6) & 0x01;
    }
    
    // 选择要显示的数码管位置(通过74HC138)
    void select_digit(unsigned char position) {
        // 根据位置选择对应的数码管
        switch (position) {
            case 0: A = 0; B = 0; C = 0; break;
            case 1: A = 0; B = 0; C = 1; break;
            case 2: A = 0; B = 1; C = 0; break;
            case 3: A = 0; B = 1; C = 1; break;
            case 4: A = 1; B = 0; C = 0; break;
            case 5: A = 1; B = 0; C = 1; break;
            case 6: A = 1; B = 1; C = 0; break;
            case 7: A = 1; B = 1; C = 1; break;
        }
    }
    
    // 定时器中断服务函数
    void Timer0_ISR(void) interrupt 1 {
        static unsigned char pos = 0;  // 当前显示的数码管位置
        static unsigned char digits[8];  // 存储显示的每一位数字
    
        // 将当前数字转换为8位数字数组
        digits[0] = display_number % 10;
        digits[1] = (display_number / 10) % 10;
        digits[2] = (display_number / 100) % 10;
        digits[3] = (display_number / 1000) % 10;
        digits[4] = (display_number / 10000) % 10;
        digits[5] = (display_number / 100000) % 10;
        digits[6] = (display_number / 1000000) % 10;
        digits[7] = (display_number / 10000000) % 10;
    
        // 选择并显示当前数码管
        select_digit(pos);  // 选择当前数码管
        display_digit(pos, digits[pos]);  // 显示对应的数字
    
        // 更新显示的数码管位置
        pos++;
        if (pos == 8) pos = 0;  // 8个数码管显示完后重新从第一个开始
    }
    
    // 定时器初始化
    void Timer0_Init() {
        TMOD = 0x01;  // 定时器0模式1,16位定时器
        TH0 = 0xFC;   // 设置定时器初值
        TL0 = 0x66;
        ET0 = 1;      // 使能定时器0中断
        EA = 1;       // 开启总中断
        TR0 = 1;      // 启动定时器0
    }
    
    void main() {
        // 初始化定时器0
        Timer0_Init();
    
        // 主循环,模拟数字递增
        while (1) {
            display_number++;  // 模拟数字递增
            if (display_number > 99999999) {
                display_number = 0;  // 数字达到最大值后重置
            }
        }
    }
    

    4. 代码解释

    1. 数码管段选数据digit数组包含0到9对应的七段数码管显示数据,每个数字对应一个字节,每个字节的7个位表示一个七段数码管的段(a-g)的开关状态。0表示该段亮,1表示该段灭。

    2. display_digit函数:此函数负责根据给定的位置(0-7)和数字,控制相应的段选端口(a-g)显示对应的数字。

    3. select_digit函数:此函数控制74HC138解码器的选择端A、B、C的状态,从而选择哪个数码管进行显示。

    4. Timer0_ISR函数:定时器中断服务函数,每次定时器中断时,它都会更新当前显示的数码管,并通过select_digitdisplay_digit函数来显示数字。

    5. Timer0_Init函数:初始化定时器,设置为16位定时器模式,定时器溢出时会产生中断,从而周期性地更新数码管的显示。

    6. 主程序:在主程序中,我们通过递增display_number来模拟数字从0到99999999的递增,并在数码管上动态显示。

    5. 总结

    通过定时器中断与74HC138解码器,我们实现了8个数码管的动态显示,显示范围为0到99999999的数字。每次定时器中断触发时,我们通过select_digit选择显示的数码管,并通过display_digit显示数字。这个方法有效地实现了多个数码管的动态显示,同时利用74HC138简化了数码管的控制。

    作者:Katie。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 单片机:实现数码管动态显示(0~99999999)74hc138驱动(附带源码)

    发表回复