# 第十三届省赛(第二次)错误总结
错误概述
本次练习基于蓝桥杯第十三届单片机省赛(第二次)题目,涉及 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 开发中,整数除法是精度陷阱的重灾区。当需要比较两个经过缩放的数值时,用乘法把两边放大到同一量级,比用除法缩小更安全、更高效。