LYYDa& 2025-06-07 00:24 采纳率: 50%
浏览 9

根据下面图中的电路原理图和代码解决十位数码管显示时闪烁的问题显示

根据下面图中的电路原理图和代码解决十位数码管显示时闪烁的问题显示

img

img

img

img

  • 写回答

6条回答 默认 最新

  • 一杯年华@编程空间 2025-06-07 12:23
    关注

    一杯年华@编程空间帮您解答,本答案结合 ChatGPT4.0和DeepSeek整理

    我曾经遇到过类似的问题,十位数码管显示闪烁通常是因为动态扫描频率过低或消隐逻辑不完善导致的。结合提供的代码和电路,分析如下:

    问题原因分析

    1. 动态扫描频率不足
      代码中display函数每次只显示十位和个位各1ms,若主循环中存在较长延时或任务阻塞,会导致扫描间隔超过人眼识别的临界值(约50Hz),出现闪烁。
    2. 消隐逻辑不完整
      代码在切换数码管位选时,未正确使用“先消隐后选通”的逻辑,可能导致残影或闪烁。
    3. 定时器与显示任务冲突
      主循环中timer_count递增和按键检测可能占用过多时间,导致显示刷新不及时。

    解决方案

    方案1:优化动态扫描逻辑(最优方案)

    核心思路:提高扫描频率,确保每位显示时间均匀,并完善消隐流程。
    代码优化

    void display(unsigned int digit) {
        unsigned char ten_bit = digit / 10;  // 十位
        unsigned char unit_bit = digit % 10; // 个位
    
        // 显示十位
        A1 = 1; B1 = 1; C1 = 1; // 选通十位数码管(假设A1/B1/C1为位选信号)
        P0 = 0x00;                // 先消隐前一位
        delay_ms(1);              // 消隐延时
        P0 = tab[ten_bit];        // 发送十位段码
        delay_ms(2);              // 显示时间(建议2-5ms,提高扫描频率)
    
        // 显示个位
        A1 = 0; B1 = 1; C1 = 1; // 选通个位数码管
        P0 = 0x00;              // 先消隐前一位
        delay_ms(1);
        P0 = tab[unit_bit];
        delay_ms(2);
    
        P0 = 0x00; // 整体消隐(可选,避免余晖)
    }
    

    优化点

    • 先消隐后选通:每次切换位选前先清零P0,避免残影。
    • 增加显示时间:将单次显示时间从1ms延长至2ms,同时减少主循环其他任务阻塞,确保总扫描周期<20ms(50Hz以上)。
    • 均匀扫描:十位和个位采用相同的显示逻辑,避免因位选顺序导致的亮度不均。

    方案2:引入定时器中断(高级方案)

    核心思路:用定时器中断独立处理显示刷新,避免主循环任务干扰扫描频率。
    步骤

    1. 配置定时器(如T0)每1ms产生一次中断。
    2. 在中断中轮流刷新十位和个位,记录当前扫描位。
    3. 主循环仅处理计数和按键,显示由中断独立完成。

    代码框架

    unsigned char current_bit = 0; // 当前扫描位(0:十位,1:个位)
    
    void Timer0_Init() {
        TMOD |= 0x01; // T0模式116位定时器)
        TH0 = 0xFC;   // 1ms定时初值(12MHz晶振)
        TL0 = 0x66;
        ET0 = 1;      // 使能T0中断
        EA = 1;       // 总中断使能
        TR0 = 1;      // 启动定时器
    }
    
    void Timer0_ISR() interrupt 1 {
        TH0 = 0xFC; // 重新装载初值
        TL0 = 0x66;
    
        if (current_bit == 0) { // 显示十位
            A1 = 1; B1 = 1; C1 = 1; // 选通十位
            P0 = tab[count_seconds / 10];
            current_bit = 1;
        } else { // 显示个位
            A1 = 0; B1 = 1; C1 = 1; // 选通个位
            P0 = tab[count_seconds % 10];
            current_bit = 0;
        }
    }
    
    void main() {
        Timer0_Init(); // 初始化定时器
        while(1) {
            // 主循环仅处理计数和按键,显示由中断自动刷新
            // ...原有按键检测和计数逻辑...
        }
    }
    

    优势

    • 显示刷新与主任务解耦,频率稳定(1ms切换一次,总扫描周期2ms,即500Hz)。
    • 避免delay_ms阻塞导致的显示延迟,适合复杂任务场景。

    方案对比与推荐

    方案实现难度稳定性适用场景
    方案1较高简单任务,无中断场景
    方案2最高多任务并行,高实时性

    推荐方案1:无需修改硬件和中断系统,直接优化现有扫描逻辑,见效快。若后续需扩展功能,可再升级为方案2。

    希望以上方案能解决你的问题!如果对代码实现或Proteus仿真有疑问,请继续留言。期待你的反馈,也请楼主采纳~

    评论

报告相同问题?

问题事件

  • 创建了问题 6月7日