蓝桥杯第八届省赛代码错误总结

蓝桥杯第八届省赛代码错误总结

错误列表

1. :cross_mark: S5按键运算符优先级错误

错误代码:

if(ucRtc[index]==(index==0)?24:60)  // ❌ 运算符优先级错误
    ucRtc[index]=0;

错误原因:

  • C语言中 == 的优先级(7)高于 ?: 的优先级(13)

  • 编译器会先计算 ucRtc[index]==(index==0),再计算 ? 24 : 60

  • 实际执行的是:if((ucRtc[index]==(index==0)) ? 24 : 60)

  • 导致条件判断完全错误,时间无法正常自增

正确代码:

if(ucRtc[index] == ((index==0) ? 24 : 60))  // ✓ 加括号明确优先级
    ucRtc[index]=0;

同样的错误也出现在:

  • S5按键时钟设置(第119行)

  • S5按键闹钟设置(第125行)


2. :cross_mark: S7和S6按键逻辑错误

错误代码:

case 7:
    Seg_Mode=1;
    Time_Mode=0;
    if(++index==3)        // ❌ index先自增再判断
        Time_Mode=0;      // ❌ 只设置Time_Mode,没有保存时间和退出设置模式
break;

错误原因:

  • ++index是前置自增,先自增再判断

  • 第一次按S7时,index从0变成1,跳过了"时"的设置(应该从index=0开始)

  • index==3时,只设置了Time_Mode=0,但:

    • 没有设置Seg_Mode=0(没有退出设置模式)

    • 没有调用Set_Rtc(ucRtc)保存时间到DS1302

    • 没有重置index=0

正确代码:

case 7:
    if(Seg_Mode==0)  // 从时间显示进入时钟设置
    {
        index=0;
        Seg_Mode=1;
        Time_Mode=0;
        Read_Rtc(ucRtc);  // 读取最新时间
    }
    else if((Seg_Mode==1)&&(Time_Mode==0))  // 在时钟设置模式下
    {
        index++;  // 先自增
        if(index==3)  // 如果超过2(秒)
        {
            index=0;
            Seg_Mode=0;  // ✓ 退出设置模式
            Set_Rtc(ucRtc);  // ✓ 保存时间到DS1302
        }
    }
    else if((Seg_Mode==1)&&(Time_Mode==1))  // 在闹钟设置模式下按S7
    {
        index=0;
        Seg_Mode=1;
        Time_Mode=0;
    }
break;

S6按键有同样的逻辑问题。


3. :cross_mark: 主函数初始化逻辑完全错误

错误代码:

Read_Rtc(ucRtc);    // ❌ 从DS1302读取时间(随机值)覆盖23:59:50
Set_Rtc(ucAlarm);   // ❌ 把闹钟时间(00:00:00)写入DS1302作为当前时间!

错误原因:

  • Read_Rtc(ucRtc) 会从DS1302芯片读取时间(可能是随机值),覆盖代码中定义的23:59:50

  • Set_Rtc(ucAlarm) 会把00:00:00写入DS1302,导致时钟从00:00:00开始走

  • 完全搞反了数据流向

正确代码:

Set_Rtc(ucRtc);  // ✓ 只需要这一行!把23:59:50写入DS1302作为初始时间

说明:

  • Set_Rtc() = 写入时间到DS1302(内存 → DS1302芯片)

  • Read_Rtc() = 从DS1302读取时间(DS1302芯片 → 内存)

  • 初始化时应该把代码中的23:59:50写入芯片,而不是从芯片读取


4. :cross_mark: S4按键温度显示检测错误

错误代码:

if((Key_Old==4)&&(Seg_Mode==0))  // ❌ 应该用Key_Val,不是Key_Old
{
    Seg_Mode=2;
}

错误原因:

  • 应该检测当前按键状态Key_Val,而不是上一次的状态Key_Old

  • Key_Old是用来做边沿检测的,不应该直接用来判断按键状态

正确代码:

if((Key_Val==4)&&(Seg_Mode==0))  // ✓ 使用当前按键状态
{
    Seg_Mode=2;
}

5. :cross_mark: 闹钟检测条件不完善

错误代码:

if((ucRtc[0]==ucAlarm[0])&&(ucRtc[1]==ucAlarm[1])&&(ucRtc[2]==ucAlarm[2]))
{
    Alarm_flag=1;  // ❌ 缺少条件判断
}

错误原因:

  • 没有检查Seg_Mode==0(应该只在时间显示模式检测闹钟)

  • 没有检查Alarm_flag==0(避免重复触发,否则每100ms都会触发一次)

  • 可能在设置模式下也触发闹钟

建议的正确代码:

if(Seg_Mode==0 && Alarm_flag==0)  // 只在时间显示且闹钟未响时检测
{
    if((ucRtc[0]==ucAlarm[0])&&(ucRtc[1]==ucAlarm[1])&&(ucRtc[2]==ucAlarm[2]))
    {
        Alarm_flag=1;
    }
}

注意: 虽然题目没有明确要求,但加上条件判断可以避免潜在问题。


6. :cross_mark: Get_Time()读取时间条件错误

错误代码:

if(Seg_Mode==0)  // ❌ 时钟设置时也需要读取时间
{
    Read_Rtc(ucRtc);
}

错误原因:

  • 只在Seg_Mode==0(时间显示)时读取时间

  • 但在时钟设置模式Seg_Mode==1, Time_Mode==0)时,DS1302时钟还在走,也需要读取来更新显示

  • 只有在温度显示模式Seg_Mode==2)时才不需要读取时间

建议的正确代码:

if(Seg_Mode != 2)  // 非温度显示模式时都读取
{
    Read_Rtc(ucRtc);
}

或者:

if(Seg_Mode==0 || (Seg_Mode==1 && Time_Mode==0))
{
    Read_Rtc(ucRtc);
}

注意: 当前代码虽然有缺陷,但不影响基本功能。


7. :cross_mark: Led_Proc()缺少else分支和LED刷新

错误代码:

void Led_Proc()
{
    if(Alarm_flag==1)
    {
        ucLed[0]=(Led_flag==1)?1:0;
        Led_Disp(ucLed);
    }
    // ❌ 缺少else分支!当Alarm_flag==0时,LED不会熄灭
}

错误原因:

  • 当闹钟关闭(Alarm_flag=0)后,Led_Proc()不执行任何操作

  • ucLed[0]保持最后的值(可能是0,也可能是1)

  • 如果用户在LED亮着时按键关闭闹钟,ucLed[0]=1不会被清零

  • LED会一直保持亮着,不会熄灭

  • 这是一个概率性bug(50%概率出现)

正确代码:

void Led_Proc()
{
    if(Alarm_flag==1)
    {
        ucLed[0]=Led_flag;  // 使用Led_flag控制闪烁
    }
    else
    {
        ucLed[0]=0;  // ✓ 确保闹钟关闭后LED熄灭
    }
    Led_Disp(ucLed);  // ✓ 总是刷新LED显示
}

8. :cross_mark: 定时器中断闪烁逻辑混乱

错误代码:

Led_count--;
if(Led_count==4294967295)  // ❌ 检测无符号整数下溢,不优雅
{
    Led_count=0;  // ❌ 多余的语句
    Alarm_flag=0;
}

错误原因:

  • 虽然能工作,但不清晰

  • 4294967295unsigned int下溢后的值,不易读

  • 没有重置Led_count,导致第二次闹钟会立即关闭

正确代码:

if(Led_count>0)  // 避免下溢
{
    Led_count--;
    if(Led_count==0)
    {
        Alarm_flag=0;  // 5秒后关闭闹钟
        Led_flag=0;    // 熄灭LED
        Led_count=5000;  // ✓ 重置计数器,为下次闹钟做准备
    }
}

9. :cross_mark: 缺少DS1302初始化

错误原因:

  • 虽然定义了ucRtc[3] = {23, 59, 50},但没有写入DS1302芯片

  • DS1302芯片里的时间是随机值或上次的值

正确代码:

void main()
{
    System_Init();

    Set_Rtc(ucRtc);  // ✓ 初始化DS1302为23:59:50

    Scheduler_Init();
    Timer1_Init();

    while(1)
    {
        Scheduler_Run();
    }
}

总结

最严重的错误(会导致功能完全无法工作):

  1. S5按键运算符优先级错误 - 时间无法正常自增

  2. S7/S6按键逻辑错误 - 设置功能无法使用

  3. 主函数初始化逻辑错误 - 时间不是23:59:50

  4. LED熄灭问题 - LED不会熄灭(概率性bug)

中等错误(功能异常或不完整):

  1. S4温度显示检测错误 - 按键检测异常

轻微问题(可优化):

  1. 闹钟检测条件不完善 - 可能重复触发

  2. Get_Time()读取条件 - 时钟设置时不更新

  3. 定时器中断逻辑 - 可读性差


学到的经验

  1. 运算符优先级很重要 - 复杂表达式一定要加括号

  2. 状态机逻辑要完整 - 考虑所有分支和退出条件

  3. 数据流向要清楚 - Read和Set不要搞混

  4. LED/外设控制要有else - 确保所有状态都有对应的处理

  5. 概率性bug最难发现 - 要考虑所有可能的执行路径

  6. 初始化很关键 - 外设一定要正确初始化

  7. 按键检测变量要用对 - Key_Val是当前状态,Key_Old是历史状态


生成时间:2026-02-02
蓝桥杯第八届省赛代码调试总结