第十三届省赛(第二次)错误总结

# 第十三届省赛(第二次)错误总结

错误概述

本次练习基于蓝桥杯第十三届单片机省赛(第二次)题目,涉及 PCF8591 ADC/DAC、超声波测距、数码管多界面显示、按键控制及 LED 指示等功能。调试过程中主要出现以下几类错误。


错误1:界面对应关系混乱(seg_mode 映射错误)

表现

  • 界面切换顺序不符合题目要求

  • LED 指示灯与界面不对应

  • 按键功能在错误的界面生效

原因

题目要求的界面切换顺序为 U(电压) → L(测距) → P(参数),但代码中 seg_mode 的映射写反了:

 // 错误映射
 seg_mode=0: U(电压)  // 正确
 seg_mode=1: P(参数)  // 应该是 L(测距)
 seg_mode=2: L(测距)  // 应该是 P(参数)

影响范围

  • seg_proc() 中 case 1 和 case 2 的显示内容对调

  • led_proc() 中 case 1 和 case 2 的 LED 指示对调

  • key_proc() 中参数操作的界面判断条件全部错误

修复

交换 seg_proc()led_proc() 中 case 1 和 case 2 的内容,将 key_proc() 中所有 seg_mode == 1 改为 seg_mode == 2

教训

动手写代码前,先明确各状态值与功能的对应关系,写注释标注清楚。


错误2:led_disp() 调用时机错误

表现

LED 状态显示不正确,残留上一次的状态。

原因

 // 错误:先显示旧数据,再修改数组
 void led_proc()
 {
     led_disp(ucled);  // 先显示
     // ... 修改 ucled  // 后修改
 }

修复

led_disp(ucled) 移到函数末尾,确保先修改数据再显示。

教训

显示类函数应在数据准备完毕后再调用,注意"先算后显"的顺序。


错误3:DAC 输出边界条件遗漏

表现

distance == 20 时 DAC 无输出。

原因

 // 错误:distance==20 时三个条件都不满足
 if(distance < 20)       { da_write(51); }
 else if(distance > 20 && distance < 80)  { da_write(...); }
 else if(distance >= 80)  { da_write(255); }

修复

 if(distance <= 20)      { da_write(51); }    // 加等号
 else if(distance < 80)  { da_write(...); }   // 去掉下限
 else                    { da_write(255); }

教训

写多段条件判断时,检查所有边界值是否被覆盖,不要留"缝隙"。


错误4:整数除法精度丢失(核心 Bug)

表现

  • 切换到测距界面时显示距离数值而非 “AAA”

  • DAC 输出 1.7V 而非 0V

  • 超声波测距在不该启动时启动

原因

 // 错误代码
 if(((pram_data_10x[0]/10) > ((float)ad_100x/100.0)) &&
    ((pram_data_10x[1]/10) < ((float)ad_100x/100.0)))

pram_data_10x[0]pram_data_10x[1]unsigned char 类型:

变量 期望结果 实际结果(整数除法)
pram_data_10x[0] / 10 45/10 4.5 4
pram_data_10x[1] / 10 5/10 0.5 0

实际判断条件变成了 0 < VRB2 < 4.0,而非题目要求的 0.5 < VRB2 < 4.5

当测试电压处于 0~0.5V 区间时,代码错误地认为满足测距条件,导致测距启动、显示距离值、DAC 输出电压。

修复

用乘法代替除法,避免整数除法丢精度:

 // 正确代码:全部用乘法比较
 if((pram_data_10x[0] * 10 > ad_100x) && (pram_data_10x[1] * 10 < ad_100x))

验证:

  • 上限:45 × 10 = 450,下限:5 × 10 = 50

  • 电压 2.45V → ad_100x = 245 → 50 < 245 < 450 ✓

  • 电压 0.3V → ad_100x = 30 → 50 < 30 不成立 → 不测距 ✓

  • 电压 4.6V → ad_100x = 460 → 460 < 450 不成立 → 不测距 ✓

教训

C 语言中两个整数相除结果仍为整数,小数部分直接截断。 涉及精度敏感的比较时,优先用乘法替代除法,或显式转换为 float 再运算。这是嵌入式开发中极其常见且隐蔽的 Bug。


总结

序号 错误类型 严重程度 根因
1 界面映射错误 状态值与功能对应关系未理清
2 显示调用时序 先显示后修改数据
3 边界条件遗漏 多段 if-else 未覆盖等号
4 整数除法精度 致命 unsigned char 除法截断

最关键的收获:在嵌入式 C 开发中,整数除法是精度陷阱的重灾区。当需要比较两个经过缩放的数值时,用乘法把两边放大到同一量级,比用除法缩小更安全、更高效。