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

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


错误列表

1. :cross_mark: LED3显示逻辑错误 — Collect_Flag 覆盖了 LED1/2 的模式指示

错误代码:

void Led_Proc()
{
    switch(Seg_Mode)
    {
        case 0:
            ucLed[0]=1;
            ucLed[1]=0;
            ucLed[2]=0;
        break;
        case 1:
            ucLed[0]=0;
            ucLed[1]=1;
            ucLed[2]=0;
        break;
        default:
            ucLed[0]=0;
            ucLed[1]=0;
            ucLed[2]=0;
        break;
    }
​
    // ❌ 问题在这里!采集期间把 LED1/2 强制清零
    if(Collect_Flag==1)
    {
        ucLed[0]=0;  // ❌ 把模式指示 LED1 灭了!
        ucLed[1]=0;  // ❌ 把模式指示 LED2 灭了!
        ucLed[2]=1;
    }
}

错误原因:

题目要求:

  • LED1 = 当前在时间界面(Seg_Mode==0 时常亮)

  • LED2 = 当前在回显界面(Seg_Mode==1 时常亮)

  • LED3 = 采集显示期间(Collect_Flag==1 时亮)

三者是独立关系,不应相互覆盖。采集显示的3秒内,用户依然在某个界面,LED1/2不应被清零。

参考代码(82.4分版)的正确逻辑:

void led_proc()
{
    // ✓ LED1/2 始终独立反映当前模式
    ucLed[0]=(seg_mode_disp==0);
    ucLed[1]=(seg_mode_disp==1);
    // ✓ LED3 独立反映采集显示状态
    ucLed[2]=display_flag;
    // ...
}

正确代码:

void Led_Proc()
{
    switch(Seg_Mode)
    {
        case 0:
            ucLed[0]=1;
            ucLed[1]=0;
            ucLed[2]=0;
        break;
        case 1:
            ucLed[0]=0;
            ucLed[1]=1;
            ucLed[2]=0;
        break;
        default:
            ucLed[0]=0;
            ucLed[1]=0;
            ucLed[2]=0;
        break;
    }
​
    // ✓ 只更新 LED3,不影响 LED1/2
    ucLed[2]=Collect_Flag;
    ucLed[3]=Led4_Flag;
    ucLed[4]=Error_Flag;
    // ...
}

关键点:

  • LED1/2 和 LED3 各管各的,互不干扰

  • Collect_Flag 只控制 ucLed[2],不得触碰 ucLed[0]ucLed[1]

  • 采集3秒显示期间,模式指示灯应保持正常


2. :cross_mark: S9按键逻辑错误 — 参数-1 放在了 Key_Down,且 Key_Up 条件过严

错误代码:

void Key_Proc()
{
    // ...
​
    // ❌ 只有 Key_Flag==1(即曾在时间回显界面按下S9)才处理S9抬起
    if(Key_Up == 9 && Key_Flag == 1)
    {
        if(Count_2000ms >= 2000)
        {
            // 长按复位...
        }
        // ❌ 短按在参数界面的 Param-- 完全没有处理!
        Key_Flag = 0;
        Count_2000ms = 0;
    }
​
    if(Collect_Flag == 0)
    {
        switch(Key_Down)
        {
            // ...
            case 9:
                // ❌ 在 Key_Down 时就立即减参数!
                if(Seg_Mode == 2)
                {
                    if(--Param >= 200) Param = 99;
                }
                // ❌ 问题:长按S9试图复位时,Param 会先减1再复位,行为不一致
                if(Seg_Mode == 1 && Show_Mode == 2)
                {
                    Key_Flag = 1;
                }
            break;
        }
    }
}

错误原因:

参考代码(82.4分版)的设计逻辑是:

  • S9 按下时:仅当在"时间回显界面"时才启动长按计时(其他界面什么都不做)

  • S9 抬起时:统一判断 → 若长按(≥2s)则全量复位;否则若在参数界面则 Param–

这样设计的好处:

  1. 防止误减:在时间回显界面长按S9准备复位时,不会同时减少参数

  2. 逻辑统一:所有 S9 的实际执行效果都在抬起时决定,符合"抬起生效"的设计习惯

错误代码的问题:

  • 在参数界面按下S9立即减1,用户还没抬起就已经生效

  • Key_Up 的条件 && Key_Flag == 1 使得参数界面的S9抬起完全不被处理

正确代码:

void Key_Proc()
{
    // ...
​
    // ✓ 始终检测S9抬起
    if(Key_Up == 9)
    {
        if(Count_2000ms >= 2000)
        {
            // ✓ 长按:全量复位
            Collect_Count = 0;
            Humidity_100x = Humidity_100x_Current = Humidity_100x_Last
                          = Humidity_100xMAX = Humidity_100x_Average = 0;
            Temperature_10x = Temperature_10x_Current = Temperature_10x_Last
                            = Temperature_10xMAX = Temperature_10x_Average = 0;
            Param = 30;                // ✓ 参数复位到默认值30
            Collect_Time[0] = 0;       // ✓ 最后采集时间清零
            Collect_Time[1] = 0;
        }
        else if(Seg_Mode == 2)
            // ✓ 短按:在参数界面才减参数(且在抬起时生效)
            Param = (Param == 0) ? 0 : Param - 1;
        Key_Flag = 0;
        Count_2000ms = 0;
        Led_Proc();
    }
​
    if(Collect_Flag == 0)
    {
        switch(Key_Down)
        {
            // ...
            case 9:
                // ✓ 按下时只启动长按计时,不做任何减参数操作
                if(Seg_Mode == 1 && Show_Mode == 2)
                {
                    Key_Flag = 1;
                }
                Led_Proc();
            break;
        }
    }
}

对比表:

场景 :cross_mark: 错误行为 :white_check_mark: 正确行为
参数界面按下S9 立即 Param– 什么都不做,等待抬起
参数界面抬起S9(短按) 无响应(Key_Flag==0 跳过) Param-- 生效
时间回显界面长按S9 Param-- 先执行(如果在参数界面) 仅启动计时,抬起后复位
复位时 Param 是否归30 :cross_mark: 否,遗漏了 :white_check_mark:

3. :cross_mark: 复位逻辑不完整 — 漏掉 Param=30 和 Collect_Time 清零

错误代码:

// 长按复位块
Collect_Count = 0;
Humidity_100x = Humidity_100x_Current = Humidity_100x_Last
              = Humidity_100xMAX = Humidity_100x_Average = 0;
Temperature_10x = Temperature_10x_Current = Temperature_10x_Last
                = Temperature_10xMAX = Temperature_10x_Average = 0;
// ❌ 没有重置 Param 回默认值30
// ❌ 没有清零 Collect_Time(最后一次采集时间)

错误原因:

参考代码(82.4分版)中,长按S9复位时明确重置了 temperature_para=30ctrlRtc 两个字段。这是完整复位的一部分:

  • Param=30:温度参数应回到初始默认值30℃

  • Collect_Time:显示的"最后采集时刻"时间戳应清零,否则还会显示上次采集时刻

正确代码:

// ✓ 完整复位
Collect_Count = 0;
Humidity_100x = Humidity_100x_Current = Humidity_100x_Last
              = Humidity_100xMAX = Humidity_100x_Average = 0;
Temperature_10x = Temperature_10x_Current = Temperature_10x_Last
                = Temperature_10xMAX = Temperature_10x_Average = 0;
Param = 30;            // ✓ 恢复默认参数值
Collect_Time[0] = 0;   // ✓ 清除最后采集时刻(小时)
Collect_Time[1] = 0;   // ✓ 清除最后采集时刻(分钟)

4. :cross_mark: 亮度触发采集无滞回 — 上下阈值相同导致不稳定

错误代码:

void AD_DA()
{
    Ad_Read(0x41);
    AD_1_Data_100x = (float)Ad_Read(0x41) / 51.0f * 100;
​
    if(AD_1_Data_100x > 200)   // 上阈值:亮度>200时置标志
        Light_Flag = 1;
​
    // ❌ 下阈值也是200!上下阈值相同,没有滞回区间
    if(AD_1_Data_100x < 200 && Light_Flag == 1 && Assist_Flag == 1)
    {
        Collect_Flag = 1;
        // ...
    }
}

错误原因:

题目逻辑:亮度先亮后暗时触发一次采集。正确实现需要滞回(Hysteresis):

亮度值:  ... 暗 ... [超过上阈] 亮 亮 亮 [低于下阈] 暗 ... → 触发!
                      ↑置Light_Flag=1              ↑实际触发

若上下阈值相同(都是200),在亮度值徘徊在200附近时会发生:

  • 略高于200 → 置 Light_Flag=1

  • 略低于200 → 立即触发采集(连 Assist_Flag 都来不及阻止多次触发的边缘情况)

参考代码(82.4分版)使用原始 ADC 值:

  • 上阈值:brightness > 100(原始ADC)≈ 换算后 AD_1_Data_100x > 196

  • 下阈值:brightness < 50(原始ADC)≈ 换算后 AD_1_Data_100x < 98

有约100个单位的滞回区间,确保稳定触发。

正确代码:

void AD_DA()
{
    Ad_Read(0x41);
    AD_1_Data_100x = (float)Ad_Read(0x41) / 51.0f * 100;
​
    if(AD_1_Data_100x > 200)    // 上阈值:检测"变亮"事件
        Light_Flag = 1;
​
    // ✓ 下阈值改为100,与上阈值200形成滞回区间,稳定触发
    if(AD_1_Data_100x < 100 && Light_Flag == 1 && Assist_Flag == 1)
    {
        Collect_Flag = 1;
        // ...
    }
}

滞回区间示意图:

AD_1_Data_100x:
  300 |
  200 |-------- 上阈值(超过此值置 Light_Flag=1)
      |  ←滞回区间(处于100~200之间时,什么都不触发)
  100 |-------- 下阈值(低于此值 + Light_Flag=1 → 触发采集)
    0 |

总结

最严重的错误(逻辑完全错误):

  1. S9 参数-1 放在 Key_Down — 行为与参考代码完全相反,导致用户长按复位时Param被误减,短按时无响应

中等错误(部分功能失效):

  1. LED3 覆盖 LED1/2 — 采集期间模式指示灯熄灭,与题目要求不符

  2. 亮度触发无滞回 — 阈值边缘可能出现异常触发

轻微错误(细节缺失):

  1. 复位漏掉 Param=30 和 Collect_Time — 复位后参数不归默认,时间戳不清零

学到的经验

1. LED 多灯独立控制原则

规则:每个LED只由其对应的状态变量控制,不允许互相覆盖

// ✅ 正确:各自独立
ucLed[0] = (Seg_Mode == 0);     // LED1:时间界面指示
ucLed[1] = (Seg_Mode == 1);     // LED2:回显界面指示
ucLed[2] = Collect_Flag;        // LED3:采集显示指示
ucLed[3] = Led4_Flag;           // LED4:温度超限闪烁
ucLed[4] = Error_Flag;          // LED5:湿度无效指示
ucLed[5] = Led6_Flag;           // LED6:温湿度同时上升
​
// ❌ 错误:用一个状态覆盖其他状态
if(Collect_Flag==1)
{
    ucLed[0]=0;  // ❌ 不能在这里清LED1
    ucLed[1]=0;  // ❌ 不能在这里清LED2
    ucLed[2]=1;
}

2. 长按/短按按键的标准模式

核心原则:按键实际效果统一在 Key_Up(抬起)时生效

// ① 按下时:仅记录意图(启动计时)
if(Key_Down == S9键号)
{
    if(处于长按检测界面)
        Key_Flag = 1;  // 只在特定界面才开始计时
    // 其他界面:什么都不做,等待抬起
}
​
// ② 抬起时:统一判断执行
if(Key_Up == S9键号)
{
    if(Count_2000ms >= 2000)
    {
        // 长按:复位(含Param、Collect_Time等所有相关变量)
    }
    else if(当前界面 == 参数界面)
    {
        // 短按:在参数界面才减参数
        Param--;
    }
    Key_Flag = 0;
    Count_2000ms = 0;
}

为什么不在 Key_Down 减参数:

  • 用户按下S9后可能保持按下准备长按复位

  • Key_Down 时就减参数 → 用户还没松手参数就变了

  • 然后用户松手时又触发复位,行为混乱

3. 传感器触发的滞回设计

规则:凡是"先超过阈值A,后低于阈值B才触发"的逻辑,A 必须 > B

// 通用模板
if(value > HIGH_THRESHOLD)   // 检测"变高"事件
    flag = 1;
​
if(value < LOW_THRESHOLD && flag == 1)  // 检测"变低"事件
{
    // 触发逻辑
    flag = 0;
}
// 确保 HIGH_THRESHOLD > LOW_THRESHOLD,形成稳定的滞回区间

本题中建议值:

  • 上阈值:> 200(AD_1_Data_100x 单位,对应原始 ADC ≈ 102)

  • 下阈值:< 100(AD_1_Data_100x 单位,对应原始 ADC ≈ 51)


复盘检查清单

比赛中遇到光敏+采集类题目时,务必检查:

LED 逻辑相关:

  • 每个 LED 只由对应状态变量控制,不互相覆盖

  • 有无 if 块强制清零了不该清零的 LED

  • 各 LED 语义是否与题目要求一一对应

S9 按键长按/短按相关:

  • 参数-1 是否在 Key_Up(抬起)时执行,而非 Key_Down

  • Key_Up 的检测条件是否覆盖了所有需要处理的场景

  • 长按时不会误执行短按效果

  • 按下时仅启动计时,不立即修改变量

复位逻辑相关:

  • 复位是否包含了所有统计变量(温度/湿度 当前/最大/平均/求和)

  • 复位是否恢复了参数到默认值(如 Param=30)

  • 复位是否清零了时间戳(如 Collect_Time)

亮度触发采集相关:

  • 上下阈值是否不同(HIGH > LOW,形成滞回)

  • 有无防重复触发机制(如 Assist_Flag)

  • Assist_Flag 在采集结束后是否正确恢复为 1


修改前后对比(本次4处修正)

位置 修改前 修改后 影响
Led_Proc Collect_Flag==1 时清零 LED1/2 只设置 ucLed[2]=Collect_Flag LED1/2 采集期间保持正常
Key_Up 条件 Key_Up==9 && Key_Flag==1 Key_Up==9 参数界面S9短按得到响应
Key_Down case 9 立即执行 Param-- 删除,只保留长按计时 与抬起生效的设计一致
Key_Up 长按复位 漏掉 Param=30Collect_Time 补充完整 复位后状态完全干净
AD_DA 下阈值 < 200(无滞回) < 100(有100单位滞回) 亮度触发更稳定

生成时间: 2026-03-01
蓝桥杯第十四届省赛代码错误总结