51单片机计数器和数码管

img

img


通过T0计数器,实现计数,显示数码管,可是到十位的数码管会溢出来,变成a,要实现数码管显示999

  • 你可以看下这个问题的回答https://ask.csdn.net/questions/7547196
  • 这篇博客你也可以参考下:51单片机利用定时器T0让数码管延时显示数字
  • 除此之外, 这篇博客: 学蓝桥Chapter8:计时/定数器及相关的寄存器中的 51单片机定时器T0的大体运作图 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 在这里插入图片描述

  • 以下回答由chatgpt基于相关博客总结生成:

    由参考资料可知,问题出在同时使用了串口和定时器T0时,无法正常使用定时器T0,需要关闭串口中断即将ES=0。因此,解决该问题的具体步骤如下:

    1. 关闭串口中断,即在Uart_Init()函数中加入ES=0。
    void Uart_Init(void)
    {
        PCON &= 0x7F;// SMOD=0:波特率不加倍
        SCON = 0x50;// UART方式1:8UART;   REN=1:允许接收
    
        TMOD |= 0x20;//T1方式2,八位自动重载,用于UART波特率
    
        TL1 = 0xFD;
        TH1 = 0xFD;// UART波特率设置:FDFD9600;FFFF,57600
    
        TR1 = 1;   //启T1计数
    
        ES = 0; //关闭串口中断
    
        EA = 1;
    }
    
    1. 修改定时器T0初始化函数,使其能够计数,并将溢出时触发中断,同时修改溢出常数,使得能够计数到999而不会溢出。
    void Timer0_Init()
    {
        TMOD |= 0x05; // 设置T0为16位计数模式
    
        TH0 = 0x03; // 初始化高8位为3
        TL0 = 0xE8; // 初始化低8位为0xE8,该值是65535-1000的值
    
        ET0 = 1; // 允许定时器T0中断
        TR0 = 1; // 启动定时器T0计数
    
        EA = 1;
    }
    
    1. 修改显示函数,将显示的范围扩大到999,并保证不会出现溢出的情况。
    void DigitalDisplay()
    {
        show[0] = counter / 100; // 显示百位数
        show[1] = (counter / 10) % 10; // 显示十位数
        show[2] = counter % 10; // 显示个位数
    
        P2 = 0x01;
        P0 = Display[show[0]];
        Delay(15);
    
        P2 = 0x02;
        P0 = Display[show[1]];
        Delay(15);
    
        P2 = 0x04;
        P0 = Display[show[2]];
        Delay(15);
    }
    

    完整代码如下:

    #include <regx51.h>
    #define uint unsigned int
    
    sbit K = P3 ^ 4;
    
    // 共阳极数码管0-F的字符码
    unsigned char Display[] = {
        0x3f, // '0'
        0x06, // '1'
        0x5b, // '2'
        0x4f, // '3'
        0x66, // '4'
        0x6d, // '5'
        0x7d, // '6'
        0x07, // '7'
        0x7f, // '8'
        0x6f, // '9'
        0x77, // 'A'
        0x7c, // 'B'
        0x39, // 'C'
        0x5e, // 'D'
        0x79, // 'E'
        0x71  // 'F'
    };
    
    uint counter = 0; // 计数器
    uint show[3] = {0, 0, 0}; // 显示数码管的值(百位、十位、个位)
    
    void Delay(uint i)
    {
        while (i--)
            ;
    }
    
    void Uart_Init(void)
    {
        PCON &= 0x7F; // SMOD=0:波特率不加倍
        SCON = 0x50; // UART方式1:8位UART;   REN=1:允许接收
    
        TMOD |= 0x20; //T1方式2,八位自动重载,用于UART波特率
    
        TL1 = 0xFD;
        TH1 = 0xFD; // UART波特率设置:FDFD,9600;FFFF,57600
    
        TR1 = 1; //启T1计数
    
        ES = 0; //关闭串口中断
    
        EA = 1;
    }
    
    void Timer0_Init()
    {
        TMOD |= 0x05; // 设置T0为16位计数模式
    
        TH0 = 0x03; // 初始化高8位为3
        TL0 = 0xE8; // 初始化低8位为0xE8,该值是65535-1000的值
    
        ET0 = 1; // 允许定时器T0中断
        TR0 = 1; // 启动定时器T0计数
    
        EA = 1;
    }
    
    // 计数器溢出时触发中断
    void Timer0Interrupt() interrupt 1
    {
        TH0 = 0x03; // 初始化高8位为3
        TL0 = 0xE8; // 初始化低8位为0xE8,该值是65535-1000的值
    
        counter++; // 每次中断增加计数器的值
        counter = counter % 1000; // 保证计数器不溢出,显示范围0~999
    
        // 更新显示的值
        show[0] = counter / 100; // 显示百位数
        show[1] = (counter / 10) % 10; // 显示十位数
        show[2] = counter % 10; // 显示个位数
    }
    
    void DigitalDisplay()
    {
        P2 = 0x01;
        P0 = Display[show[0]];
        Delay(15);
    
        P2 = 0x02;
        P0 = Display[show[1]];
        Delay(15);
    
        P2 = 0x04;
        P0 = Display[show[2]];
        Delay(15);
    }
    
    int main()
    {
        Uart_Init();
        Timer0_Init();
    
        while (1)
        {
            DigitalDisplay();
        }
    
        return 0;
    }