十五届省赛第二场笔记更正

蓝桥杯第十五届省赛第二场代码错误总结

最终得分: 85 / 85 分 :white_check_mark: (经历: ~0分 → 77.7分 → 79分 → 85分满分)
题目: 温度测量与DAC控制系统


错误列表

1. :cross_mark: 温度采样逻辑错误:新旧温度变量赋值顺序错误

错误代码:

void Get_Temperature()
{
    // ❌ 先读取新温度,再保存旧温度
    Temperature_10x = rd_temperature() * 10;
    Temperature_10xOld = Temperature_10x;  // ❌ 新旧温度永远相等!
}

错误原因:

  • 读取新温度后立即赋值给旧温度变量

  • 导致 Temperature_10x == Temperature_10xOld 永远成立

  • 所有基于温度变化的判断全部失效

导致的后果:

  • 温度上升/下降判断永远不触发 → L2、L3永远不亮

  • 温度突变报警永远不触发 → L4永远不闪烁

  • 所有温度监测功能完全失效

4T测评失败点:

序号8:L2点亮
- 正确结果:温度上升时L2点亮
- 你的结果:L2未点亮 ❌
​
序号9:L2熄灭
- 正确结果:温度不上升2s后L2熄灭
- 你的结果:L2未点亮过,无法测试熄灭 ❌
​
序号16:L3点亮
- 正确结果:温度下降时L3点亮
- 你的结果:L3未点亮 ❌
​
序号4,5,12,13:L4闪烁
- 正确结果:温度突变时L4闪烁3秒
- 你的结果:L4未闪烁 ❌

正确代码:

void Get_Temperature()
{
    // ✅ 先保存旧值,再读取新值
    Temperature_10xOld = Temperature_10x;     // ✓ 保存旧温度
    Temperature_10x = rd_temperature() * 10;  // ✓ 读取新温度
​
    // 现在可以正确比较新旧温度
    if(Temperature_10x > Temperature_10xOld)
        // 温度上升
    if(Temperature_10x < Temperature_10xOld)
        // 温度下降
}

关键点:

  • 先保存旧值,再读取新值 - 这是基本逻辑!

  • 顺序错了,后果严重,所有温度监测功能全废

  • 这是最基础的变量更新逻辑,务必牢记


2. :cross_mark: LED4触发时未初始化闪烁状态

错误代码(更早版本):

void Get_Temperature()
{
    // ...
    if(((Temperature_10x - Temperature_10xOld) >= 10) ||
       ((Temperature_10xOld - Temperature_10x) >= 10))
    {
        L4_Blinking = 1;   // ❌ 只置位,不初始化状态
    }
}

错误原因:

  • L4 闪烁不是只靠一个标志位就够了,还依赖 Count_LED4Count_200msLed4_Flag

  • 如果触发时没有同步初始化这些状态量:

    • Count_200ms 可能不是从 0 开始,导致首次翻转间隔不准

    • Count_LED4 可能不是从 0 开始,导致 3 秒总时长不准

    • Led4_Flag 可能不是亮灯态,导致触发后 L4 不能立即亮起

4T测评失败点:

序号4,12:L4闪烁间隔error
- 正确结果:0.2秒闪烁间隔
- 错误结果:首次闪烁间隔不稳定,或触发后不能立即亮起 ❌

当前满分代码:

if(((Temperature_10x-Temperature_10xOld)>=10)||((Temperature_10xOld-Temperature_10x)>=10))
{
    Alarm_Flag=1;           // 当前满分代码仍然保留该标志位
    if(L4_Blinking==0)      // ✅ 只在首次触发时初始化
    {
        L4_Blinking=1;
        Count_LED4=0;       // ✅ 3秒总计时器清零
        Count_200ms=0;      // ✅ 0.2秒间隔计时器清零
        Led4_Flag=1;        // ✅ L4立即亮起
    }
}

关键点:

  • 触发闪烁时,要把标志位、总计时器、间隔计时器、当前灯态一起初始化

  • 只置 L4_Blinking=1 还不够,必须把整套闪烁状态带起来

  • 最稳的做法是: 只在首次触发时初始化一次

  • Alarm_Flag 在当前满分代码中仍然保留,但 L4 的实际闪烁执行由 L4_Blinking 决定


3. :cross_mark: 温度显示未使用校准后的温度值

错误代码:

void Seg_Proc()
{
    case 0:  // 温度界面
        // ❌ 显示的是原始温度,未加校准值
        Seg_Buf[6] = Temperature_10x / 100 % 10;
        Seg_Buf[7] = Temperature_10x / 10 % 10;
        break;
}

错误原因:

题目要求(3.3节第1点):

温度测量:通过DS18B20测量环境实时温度数据,经过校准值校准后为温度数据的最终结果
T = T_DS18B20 + 温度校准值(可为负)

  • 题目明确要求显示校准后的温度

  • 你显示的是原始温度 Temperature_10x

  • 应该显示 Temperature_10x + Correct_Data * 10

4T测评失败点:

序号6,7:设置校准值后温度显示
- 正确结果:显示校准后的温度(原始温度±校准值)
- 你的结果:显示原始温度,未加校准值 ❌

正确代码:

void Get_Temperature()
{
    Temperature_10xOld = Temperature_10x;
    Temperature_10x = rd_temperature() * 10;
    // ✅ 计算校准后的温度
    Correct_10x = Temperature_10x + Correct_Data * 10;
}

void Seg_Proc()
{
    case 0:  // 温度界面
        // ✅ 显示校准后的温度
        Seg_Buf[6] = Correct_10x / 100 % 10;
        Seg_Buf[7] = Correct_10x / 10 % 10;
        break;
}

关键点:

  • 题目说"校准后为最终结果",就要显示校准后的值

  • 用一个专门的变量 Correct_10x 存储校准后的温度

  • 显示时使用校准后的值


4. :cross_mark: L2、L3 LED控制逻辑错误

错误代码(第一版):

void Get_Temperature()
{
    // ...
    // ❌ 设置Flag后立即根据温度清零
    if(Temperature_10x > Temperature_10xOld)
    {
        Rise_Flag = 1;
        Drop_Flag = 0;  // ❌ 立即清零
    }
    else if(Temperature_10x < Temperature_10xOld)
    {
        Rise_Flag = 0;  // ❌ 立即清零
        Drop_Flag = 1;
    }
    else
    {
        Rise_Flag = 0;  // ❌ 温度稳定立即清零
        Drop_Flag = 0;
    }
}

void Led_Proc()
{
    ucLed[1] = Rise_Flag;  // ❌ 直接赋值Flag
    ucLed[2] = Drop_Flag;
}

错误原因:

  • 温度上升时设置 Rise_Flag=1, L2点亮

  • 下次采样如果温度稳定,立即设置 Rise_Flag=0, L2立即熄灭

  • 根本到不了2秒,因为每300ms采样一次,温度不可能一直上升

错误代码(第二版):

void Led_Proc()  // 每10ms执行
{
    if(Temp_Count == 2)
    {
        // ❌ 直接比较新旧温度
        if(Temperature_10x > Temperature_10xOld)
        {
            ucLed[1] = 1;
            Count_LED2 = 0;
        }
        else if(Count_LED2 >= 2000)  // ❌ 问题在这!
            ucLed[1] = 0;
    }
}

第二版的问题:

  • Temperature_10xTemperature_10xOld300ms才更新一次

  • Led_Proc10ms执行一次

  • 在两次温度采样之间(290ms), Temperature_10x == Temperature_10xOld

  • 会错误地走到 else if 分支,2秒后熄灭LED

正确代码(使用Flag):

void Get_Temperature()  // 每300ms执行,设置Flag
{
    Temperature_10xOld = Temperature_10x;
    Temperature_10x = rd_temperature() * 10;

    if(Temp_Count == 2)
    {
        // ✅ 温度上升:只在首次触发时重置计时器
        if(Temperature_10x > Temperature_10xOld)
        {
            if(Rise_Flag == 0)  // 首次触发
                Count_LED2 = 0;
            Rise_Flag = 1;  // 设置标志,不清除
        }

        // ✅ 温度下降:只在首次触发时重置计时器
        if(Temperature_10x < Temperature_10xOld)
        {
            if(Drop_Flag == 0)
                Count_LED3 = 0;
            Drop_Flag = 1;
        }
    }
}

void Led_Proc()  // 每10ms执行,根据Flag控制LED
{
    // ✅ L2处理:根据Flag和计时器
    if(Rise_Flag == 1)
    {
        ucLed[1] = 1;  // 点亮
        if(Count_LED2 >= 2000)
        {
            ucLed[1] = 0;      // 2秒后熄灭
            Rise_Flag = 0;     // 清除标志
        }
    }
    else
        ucLed[1] = 0;

    // ✅ L3处理:根据Flag和计时器
    if(Drop_Flag == 1)
    {
        ucLed[2] = 1;
        if(Count_LED3 >= 2000)
        {
            ucLed[2] = 0;
            Drop_Flag = 0;
        }
    }
    else
        ucLed[2] = 0;
}

关键点:

  • 需要用Flag保存温度变化的状态

  • 温度采样时设置Flag,不清除

  • LED处理时根据Flag和计时器控制

  • 2秒后才清除Flag

  • 只在首次触发时重置计时器,避免反复重置


5. :cross_mark: Led_Proc执行频率设置过高

错误代码:

idata task_t Scheduler_Task[] = {
    {Led_Proc, 1, 0},  // ❌ LED处理每1ms执行
    {Key_Proc, 10, 0},
    {Seg_Proc, 20, 0},
    {Get_Temperature, 300, 0},
    {AD_DA, 150, 0}
};

错误原因:

  • Led_Proc 每1ms执行,频率太高

  • 可能导致L2、L3判断时序混乱

  • 满分代码都是10ms执行一次

  • 没必要这么高频率

正确代码:

idata task_t Scheduler_Task[] = {
    {Led_Proc, 10, 0},  // ✅ LED处理每10ms
    {Key_Proc, 10, 0},
    {Seg_Proc, 20, 0},
    {Get_Temperature, 300, 0},
    {AD_DA, 150, 0}
};

关键点:

  • LED处理10ms足够了

  • 太高频率可能导致逻辑混乱

  • 参考满分代码的设置


6. :cross_mark: L4闪烁状态管理缺陷:检测逻辑与执行逻辑耦合,导致闪烁被提前终止(79分→85分)

问题本质:温度突变的"检测"和 L4 闪烁的"执行"没有分离,导致执行流程会被后续采样打断

79分错误代码(3处问题):

问题点①:缺少独立的闪烁进行中标志

// 79分:没有 L4_Blinking 变量
idata unsigned char Alarm_Flag = 0;  // ← 既当"检测标志"又当"闪烁控制标志"
idata unsigned char Led4_Flag = 0;
// ❌ 缺少: idata unsigned char L4_Blinking = 0;

问题点②:Get_Temperature() 中未初始化闪烁状态

// 79分代码 - Get_Temperature() 中
if(((Temperature_10x-Temperature_10xOld)>=10)||((Temperature_10xOld-Temperature_10x)>=10))
    Alarm_Flag = 1;    // ← 只设置了检测/执行混合标志
    // ❌ 没有独立的执行状态,后续闪烁会受 Alarm_Flag 清零影响
    // ❌ 没有设置 Led4_Flag=1,L4不会立即亮起
else
    Alarm_Flag = 0;    // ← 300ms后温度没突变就清零!

问题点③:Timer1_Isr() 中用 Alarm_Flag 控制闪烁

// 79分代码 - Timer1_Isr() 中
if(Alarm_Flag == 1)    // ❌ 用 Alarm_Flag 控制闪烁计时
{
    Count_LED4++;
    Count_200ms++;
    if(Count_200ms == 200) { Count_200ms = 0; Led4_Flag ^= 1; }
    if(Count_LED4 == 3000)
    {
        Count_LED4 = 0;
        Alarm_Flag = 0;  // ❌ 在这里清零 Alarm_Flag
        Count_200ms = 0;
        Led4_Flag = 0;
    }
}

致命的执行流程(79分):

时间线:
  0ms    Get_Temperature(): 检测到突变, Alarm_Flag=1 ✓
                            (但Count_LED4/Count_200ms未重置!)
  1ms    Timer1_Isr(): Alarm_Flag==1, 开始计数 ✓
  ...
  300ms  Get_Temperature(): 这次温差<1℃, Alarm_Flag=0 !!!
  301ms  Timer1_Isr(): Alarm_Flag==0, 计数停止! L4冻结在当前状态!
         ↑ L4只闪了约300ms就停了, 远未到3秒! ❌

85分满分代码(3处修复):

修复点①:新增独立的 L4_Blinking 标志,同时保留 Alarm_Flag

// ✅ 新增变量:专门用于标记"L4正在闪烁中"
idata unsigned char Alarm_Flag = 0;   // 保留:温度突变检测标志
idata unsigned char L4_Blinking = 0;  // L4闪烁进行中标志

修复点②:Get_Temperature() 中检测突变,并初始化执行状态

// 当前满分代码 - Get_Temperature() 中
if(((Temperature_10x-Temperature_10xOld)>=10)||((Temperature_10xOld-Temperature_10x)>=10))
{
    Alarm_Flag = 1;             // ✅ 检测标志保留
    if(L4_Blinking == 0)       // ✅ 只在首次触发时初始化
    {
        L4_Blinking = 1;       // ✅ 设置独立的闪烁执行标志
        Count_LED4 = 0;        // ✅ 重置3秒总计时器
        Count_200ms = 0;       // ✅ 重置0.2秒闪烁间隔计时器
        Led4_Flag = 1;         // ✅ L4立即亮起(不用等第一个200ms)
    }
}
else
    Alarm_Flag = 0;

修复点③:Timer1_Isr() 中只由 L4_Blinking 控制闪烁

// 当前满分代码 - Timer1_Isr() 中
if(L4_Blinking == 1)           // ✅ 用独立标志控制
{
    Count_LED4++;
    Count_200ms++;
    if(Count_200ms == 200) { Count_200ms = 0; Led4_Flag ^= 1; }
    if(Count_LED4 == 3000)
    {
        Count_LED4 = 0;
        L4_Blinking = 0;      // ✅ 3秒到了才清除闪烁标志
        Count_200ms = 0;
        Led4_Flag = 0;
    }
}

正确的执行流程(85分):

时间线:
  0ms    Get_Temperature(): 检测到突变
         → Alarm_Flag=1, L4_Blinking=1
         → Count_LED4=0, Count_200ms=0, Led4_Flag=1 (L4立即亮)
  1ms    Timer1_Isr(): L4_Blinking==1, 开始计数 ✓
  200ms  Timer1_Isr(): Led4_Flag翻转 → L4灭
  300ms  Get_Temperature(): 这次温差<1℃, Alarm_Flag=0
         → 但 L4_Blinking 仍然==1! 不受影响! ✓
  400ms  Timer1_Isr(): Led4_Flag翻转 → L4亮
  ...    (继续0.2秒闪烁)
  3000ms Timer1_Isr(): Count_LED4==3000
         → L4_Blinking=0, Led4_Flag=0 → L4停止闪烁 ✓
         ↑ 完整闪烁了3秒! ✅

核心设计模式:检测与执行分离

┌─────────────────────────────────────────────────┐
│  79分的错误设计(单标志位身兼二职):            │
│                                                   │
│  Alarm_Flag ──→ 温度检测(每300ms可能清零)      │
│       │                                           │
│       └──────→ 闪烁控制(需要持续3秒)           │
│                                                   │
│  💥 冲突:检测清零会中断闪烁执行!                │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│  85分的正确设计(触发与执行分离):              │
│                                                   │
│  L4_Blinking ─→ 闪烁控制(只在3秒后才清零)     │
│                                                   │
│  Alarm_Flag ──→ 温度检测(可随时清零)          │
│                                                   │
│  温度比较 ────→ 负责驱动 Alarm_Flag / 触发执行   │
│                                                   │
│  ✅ 互不干扰:触发归触发,执行归执行            │
└─────────────────────────────────────────────────┘

4T测评失败点(79分 vs 85分):

序号4:温度突变时L4闪烁3秒
- 79分结果:L4只闪约0.3秒就停止 ❌ (Alarm_Flag被下次采样清零)
- 85分结果:L4完整闪烁3秒 ✅

序号5:L4闪烁期间的0.2秒间隔
- 79分结果:首次闪烁间隔可能不正确 ❌ (计数器未初始化)
- 85分结果:从触发瞬间开始精确0.2秒间隔 ✅

序号12,13:再次温度突变时L4闪烁
- 79分结果:同上问题 ❌
- 85分结果:正确 ✅

关键点:

  • 定时闪烁/延时操作必须用独立标志位控制,不能复用检测标志

  • 闪烁控制标志只在定时器ISR中到期时才清零

  • 触发闪烁时必须初始化:L4_Blinking=1, Count_LED4=0, Count_200ms=0, Led4_Flag=1

  • 当前满分代码中 Alarm_Flag 仍然保留,但它不再直接控制闪烁执行

  • 检查每个Flag:谁设置它?谁清除它?清除时机会不会打断其他逻辑?


7. :cross_mark: 清理“疑似无用变量”时误删分支结构,导致功能连锁损坏(实测教训)

问题本质:这次真正把满分代码改坏的,不是删掉 Alarm_Flag 这个动作本身,而是清理过程中把两个关键 else 一起误删了。

被误删的第一个 else:短按/长按分支

if(Count_1500ms<1500)
{
    DAC_Control^=1;
    Key13=Count_1500ms=0;
}
else
{
    Lock^=1;
    Key13=Count_1500ms=0;
}

删坏后的后果:

  • 短按 S13 本来只该切换 DAC_Control

  • else 没了以后,短按时会继续执行 Lock^=1

  • 直接引发 L8 状态、继电器吸合/断开、锁定逻辑相关测评异常

被误删的第二个 else:DAC 三段式控制分支

if(temp_celsius<=10)
    DAC_Mode_0=(102);
else if(temp_celsius>=40)
    DAC_Mode_0=(255);
else
{
    DAC_Mode_0=(5.1 * (temp_celsius - 10) + 102);
}

删坏后的后果:

  • 当温度 <=10>=40 时,本来应该直接取固定端点值

  • else 没了以后,后面的线性公式块仍会继续执行

  • 导致前面已经算好的 DAC 值被覆盖,出现 47℃、5℃、13℃ 等温度点 DAC 输出错误

这次实测结论:

  • Alarm_Flag 是否保留,不是这次掉分的直接原因

  • 真正致命的是:机械删除代码时误伤了控制流结构

  • 以后清理“疑似无用变量”时,必须先做完整 diff,再做完整回归测试

关键点:

  • 删除变量引用时,要特别检查它周围的 if / else / switch 结构有没有被顺手破坏

  • 逻辑分支里的一个 else,往往比一个“看起来没用的变量”更不能乱动

  • 单片机题目测评点很多,一个分支结构损坏就可能同时炸掉 DAC、LED、继电器三条线


8. :cross_mark: 温度比较未做采样稳定门控(Temp_Count

问题本质:温度变化判断不能在刚启动或首帧采样时立即生效,需要先让采样进入稳定阶段。

推荐写法(当前满分代码同款思路):

// 采样稳定控制
Temp_Count++;
if(Temp_Count == 3)
    Temp_Count = 2;
​
// 只有稳定后才做温度变化判断
if(Temp_Count == 2)
{
    // 上升/下降/突变判断
}

不做这层门控的风险:

  • 上电初期 Temperature_10xOld 历史值不可靠,容易误触发上升/下降/突变

  • 首次或早期读数抖动会引发 L2/L3/L4 错误动作

  • 测评边界场景中更容易出现“偶发通过/偶发失败”

关键点:

  • Temp_Count 的目标不是“延时”,而是“只在稳定采样后才允许比较”

  • 写法可以不同,但必须有等价效果(例如首帧只更新 old、不判定)

  • 这层保护建议保留,属于低成本高收益的稳定性措施


总结

最严重的错误(会导致功能完全失效):

  1. 温度采样变量赋值顺序错误 - 新旧温度永远相等,所有温度监测功能全废

  2. 温度显示未校准 - 显示错误的温度值

中等错误(逻辑不完善):

  1. LED4触发时未初始化完整闪烁状态 - 闪烁间隔或起始灯态错误

  2. L2、L3逻辑错误 - LED无法正确点亮2秒

  3. L4闪烁检测与执行未分离 - 闪烁被温度采样提前终止,只闪约0.3秒

  4. 清理代码时误删 else - 会同时破坏 DAC 分段控制、按键长短按和继电器逻辑

  5. 温度比较未做采样稳定门控 - 启动初期易误判,导致 LED/报警偶发异常

轻微错误(优化问题):

  1. Led_Proc频率过高 - 性能浪费,可能导致时序混乱

学到的经验

1. 变量更新的基本逻辑

标准模式(保存历史值):

// ✅ 先保存旧值,再读取新值
Old_Value = Current_Value;  // 保存旧值
Current_Value = 读取新值();  // 读取新值

// 现在可以比较新旧值
if(Current_Value > Old_Value)
    // 上升

错误模式:

// ❌ 先读取新值,再保存旧值
Current_Value = 读取新值();
Old_Value = Current_Value;  // 新旧值永远相等!

记忆技巧:

  • "旧"在前,"新"在后

  • 先保存历史,再获取现在

  • 逻辑顺序不能颠倒

2. 理解"校准"的含义

校准的完整流程:

原始测量 → 加上校准值 → 校准后的值 → 显示/使用

使用温度的地方要用校准后的值:

  • :white_check_mark: 数码管显示: 显示校准后的温度

  • :cross_mark: 温度变化判断: 用原始温度(判断传感器变化)

3. LED延时控制的正确方法

使用Flag保存状态:

// 采样函数:设置Flag,不清除
if(条件触发)
{
    if(Flag == 0)  // 首次触发
        Count = 0;
    Flag = 1;  // 设置标志
}

// LED处理:根据Flag和计时器
if(Flag == 1)
{
    LED = ON;  // 点亮
    if(Count >= 延时时间)
    {
        LED = OFF;    // 熄灭
        Flag = 0;     // 清除标志
    }
}
else
    LED = OFF;

关键点:

  • Flag用于保存触发状态

  • 触发时设置Flag,不清除

  • 延时到了才清除Flag

  • 只在首次触发时重置计时器

4. 标志位的单一职责原则(79分→85分的教训)

当一个标志位需要在不同地方被设置/清除时,必须检查是否存在冲突!

// ❌ 危险模式:一个Flag被多处修改,职责冲突
Flag = 1;  // 在A函数中设置
Flag = 0;  // 在B函数中清零 ← 可能打断A的逻辑!
if(Flag) { /* 在C函数中使用 */ }  // ← C依赖A的设置,但B把它清了

// ✅ 安全模式:分离职责,各管各的
Detect_Flag = 1;   // A函数:检测
Detect_Flag = 0;   // B函数:检测结束
Execute_Flag = 1;  // 触发时设置,只在执行完成后清零
if(Execute_Flag) { /* C函数中使用 */ }  // ← 不受B影响

记忆技巧:

  • 每个Flag只做一件事

  • 检测标志:随业务逻辑设置/清除

  • 执行标志:触发时设置,执行完毕后才清除

  • 两者不能合并为一个

5. 清理代码前先看控制流

不要因为一个变量“看起来没用”,就直接做机械删除。

// ❌ 危险做法:只盯着变量名删代码,顺手把 else 结构删坏
if(条件A)
{
    ...
}
else
{
    ...
}

// ✅ 稳妥做法:先看变量是否参与控制流,再删,再回归
1. 搜索变量的所有读写点
2. 检查附近的 if / else / switch 结构
3. 删除后做完整 diff
4. 用测评点回归关键功能

这次实测教训:

  • Alarm_Flag 不是直接炸分点

  • 误删 else 才是导致满分代码退化的直接原因

  • 改单片机逻辑代码时,控制流结构比“看起来无用的变量”更敏感

6. 采样稳定门控不是可有可无

Temp_Count 这类门控的价值,是把“采样稳定”与“业务判定”分层。

// 先稳定采样,再开放判定
Temp_Count++;
if(Temp_Count == 3) Temp_Count = 2;
if(Temp_Count == 2)
{
    // 做温度变化判定
}

记忆要点:

  • 首帧/早期样本优先用于建立历史值,不要急着触发业务动作

  • 可以不用完全同样的代码,但必须保留“稳定后再判定”的语义

  • 这类门控通常能显著减少边界场景抖动和误报


复盘检查清单

在蓝桥杯单片机比赛中,遇到类似题目时,务必检查:

变量更新相关:

  • 先保存旧值,再读取新值(Old=Current; Current=Read;)

  • 新旧变量用于比较,确保能正确判断变化

  • 所有历史值变量都要在读取新值之前保存

温度校准相关:

  • 所有显示温度的地方用校准后的值

  • 校准值计算公式: Correct_10x = Temperature_10x + Correct_Data * 10

LED控制相关:

  • 使用Flag保存触发状态

  • 触发时设置Flag,不立即清除

  • 延时到了才清除Flag

  • 只在首次触发时重置计时器

  • 计时器要在触发时初始化

  • 定时闪烁/延时操作必须用独立标志位,不能复用检测标志

  • 检查每个Flag:谁设置?谁清除?清除时机会不会打断其他逻辑?

调度器相关:

  • LED处理函数执行频率设置为10ms

  • 温度采样300ms执行一次

  • 避免过高的执行频率导致时序混乱

逻辑判断相关:

  • "或"条件要两个都判断(上升或下降)

  • 边界值要考虑取等号

  • 计时器溢出要考虑

  • 温度比较前是否做了采样稳定门控(如 Temp_Count

  • 首帧/早期样本是否只建历史值,不直接触发LED/报警判定


得分演进记录

版本 得分 主要问题
初版 ~0分 温度新旧值赋值顺序错误,所有温度功能全废
修复后 77.7分 修复了赋值顺序、校准显示、L2/L3逻辑、调度频率
79分版 79分 L4闪烁复用 Alarm_Flag 控制,被温度采样提前清零
当前满分版 85分 保留 Alarm_Flag 作为检测标志,L4_Blinking 独立负责闪烁执行

经验总结:

  • 蓝桥杯单片机对时序控制要求很高

  • LED的延时熄灭要用Flag+计时器方式

  • 计时器初始化和重置要特别注意

  • 标志位要遵循单一职责,触发逻辑和执行逻辑必须分离

  • 清理代码前先保护好 if / else 结构,不要机械删变量


初次生成: 2026-02-13 (77.7分错误总结)
更新时间: 2026-03-20 (按实测满分代码修订: 保留 Alarm_Flag,补充“误删 else 导致掉分”的复盘)
蓝桥杯第十五届省赛第二场代码错误总结
最终得分: 85 / 85 分 :white_check_mark: