蓝桥杯单片机第十届省赛代码错误总结
错误列表
1.
电压显示计算精度丢失
错误代码:
Seg_Buf[5]=(unsigned char)Voltage*100/100%10+','; // ❌ 类型转换顺序错误
Seg_Buf[6]=(unsigned char)Voltage*100/10%10;
Seg_Buf[7]=(unsigned char)Voltage*100%10;
错误原因:
-
C语言运算符优先级:类型转换 > 乘法 > 除法 > 取模
-
(unsigned char)Voltage*100的执行顺序:-
先执行
(unsigned char)Voltage→ 3.41V 转换为 3 -
再执行
3 * 100= 300
-
-
导致小数部分全部丢失,3.41V显示成3.00V
数值验证(假设Voltage=3.41V):
❌ 错误计算过程:
Seg_Buf[5] = (unsigned char)3.41 * 100 / 100 % 10 + 44
= 3 * 100 / 100 % 10 + 44
= 300 / 100 % 10 + 44
= 3 % 10 + 44 = 47(显示3.)
Seg_Buf[6] = 3 * 100 / 10 % 10
= 300 / 10 % 10
= 30 % 10 = 0(显示0)
Seg_Buf[7] = 3 * 100 % 10
= 300 % 10 = 0(显示0)
最终显示:U _ _ _ _ 3.00 ❌ 应该是3.41
正确代码:
case 1:
Seg_Buf[0]=12;
Seg_Buf[1]=10;
Seg_Buf[2]=10;
Seg_Buf[3]=10;
Seg_Buf[4]=10;
Seg_Buf[5]=(unsigned int)(Voltage*100)/100%10+','; // 个位 + 小数点标志
Seg_Buf[6]=(unsigned int)(Voltage*100)/10%10; // 小数第一位
Seg_Buf[7]=(unsigned int)(Voltage*100)%10; // 小数第二位
break;
正确计算过程(假设Voltage=3.41V):
✓ 正确计算过程:
Seg_Buf[5] = 341/100%10 + 44 = 3 + 44 = 47(显示3.)
Seg_Buf[6] = 341/10%10 = 34%10 = 4(显示4)
Seg_Buf[7] = 341%10 = 1(显示1)
最终显示:U _ _ _ _ 3.41 ✓ 正确!
关键点:
-
括号位置决定计算顺序:(unsigned int)(Voltage * 100)vs(unsigned int)Voltage * 100 -
浮点数运算完成后再转换为整数,避免精度丢失 -
使用临时变量避免重复计算,提高效率和可读性
2.
缺少DAC输出调用
错误代码:
void AD_DA()
{
RB2=Ad_Read(0x43); // 只读取了ADC
Voltage=(Output_Mode==0)?2:RB2; // 只设置了变量
// ❌ 完全没有调用 Da_Write() 输出到DAC!
}
错误原因:
-
题目明确要求: “使用 PCF8591 测量电位器 RB2 的输出电压,并根据试题要求通过其 DAC 功能输出该电压值”
-
PCF8591有两个功能:
-
ADC(模数转换):读取模拟电压 →
Ad_Read() -
DAC(数模转换):输出模拟电压 →
Da_Write()
-
-
只读取了电压,但没有输出到DAC的AOUT引脚
-
导致DAC完全不工作,不符合题目要求
-
评分时可能直接测量AOUT引脚电压,没有输出会直接扣分或零分!
题目要求对照:
| 要求 | 对应操作 | 是否完成 |
|---|---|---|
| 测量RB2电压 | Ad_Read(0x43) |
|
| 通过DAC输出电压 | Da_Write(...) |
|
| S5切换固定2V/跟随RB2 | Output_Mode |
|
| LED L5指示输出模式 | ucLed[4] |
正确代码(完整版):
void AD_DA()
{
RB2=Ad_Read(0x43)/51.0; // 读取ADC原始值,ADC值转换为实际电压
Voltage=(Output_Mode==0)?2:RB2; //根据输出模式确定要输出的电压
Da_Write((unsigned char)(Voltage * 51.0)); //通过DAC输出电压(关键!)
}
3.
ADC转电压公式错误
初次错误代码:
RB2=Ad_Read(0x43); // ❌ 直接赋值,没有转换
Voltage=(Output_Mode==0)?2:RB2; // ❌ RB2是0-255,不是实际电压!
错误原因:
-
Ad_Read()返回的是8位ADC的数字量,范围:0-255 -
PCF8591的参考电压是5V
-
转换公式:
实际电压 = ADC值 × 5.0 ÷ 255 -
直接赋值会导致:
-
RB2的值是0-255,而不是0-5V的实际电压
-
数码管显示错误(显示超大的数字)
-
DAC输出错误
-
数值验证(假设电位器输出3.41V):
❌ 错误:
Ad_Read(0x43) = 174 (ADC采样值)
RB2 = 174 (直接赋值)
Voltage = 174 (Output_Mode=1时)
数码管显示:U _ _ _ _ 174.00 ❌ 完全错误!
✓ 正确:
Ad_Read(0x43) = 174
RB2 = 174 × 5.0 ÷ 255 = 3.41V
Voltage = 3.41V
数码管显示:U _ _ _ _ 3.41 ✓ 正确!
正确代码(两种等价写法):
// 方法1: 标准公式(推荐,易理解)
RB2 = Ad_Read(0x43) * 5.0 / 255.0;
// 方法2: 简化公式(更高效)
RB2 = Ad_Read(0x43) / 51.0; // 255÷5 = 51
转换对照表:
| ADC值 | 标准公式 | 简化公式 | 实际电压 |
|---|---|---|---|
| 0 | 0×5/255 | 0/51 | 0.00V |
| 51 | 51×5/255 | 51/51 | 1.00V |
| 102 | 102×5/255 | 102/51 | 2.00V |
| 174 | 174×5/255 | 174/51 | 3.41V |
| 255 | 255×5/255 | 255/51 | 5.00V |
4.
DAC输出转换公式错误
初次错误代码:
Da_Write((unsigned char)Voltage); // ❌ 直接转换,范围错误
错误原因:
-
Voltage的范围是 0-5V (float类型) -
Da_Write()需要的参数是 0-255的数字量 -
直接转换
(unsigned char)Voltage:-
Voltage=2.0V → (unsigned char)2.0 = 2
-
Voltage=3.41V → (unsigned char)3.41 = 3
-
-
转换后的值只有0-5,而不是0-255
-
导致DAC输出电压只有实际电压的1/51
数值验证(假设Voltage=2.0V):
❌ 错误转换:
Voltage = 2.0V
(unsigned char)Voltage = 2
Da_Write(2)
实际输出电压 = 2 × 5.0 ÷ 255 = 0.039V ❌ 应该输出2.0V!
✓ 正确转换:
Voltage = 2.0V
(unsigned char)(Voltage × 255 / 5.0) = (unsigned char)(2.0 × 51) = 102
Da_Write(102)
实际输出电压 = 102 × 5.0 ÷ 255 = 2.0V ✓ 正确!
正确代码(两种等价写法):
// 方法1: 标准公式(推荐,易理解)
Da_Write((unsigned char)(Voltage * 255.0 / 5.0));
// 方法2: 简化公式(更高效)
Da_Write((unsigned char)(Voltage * 51.0)); // 255÷5 = 51
关键点:
-
括号位置非常重要:-
(unsigned char)Voltage * 51.0→ 先转换再乘,错误! -
✓
(unsigned char)(Voltage * 51.0)→ 先乘再转换,正确!
-
-
ADC和DAC的转换是互逆的:-
ADC: 数字量 → 电压:
V = ADC ÷ 51 -
DAC: 电压 → 数字量:
DAC = V × 51
-
DAC转换对照表:
| 电压 | 标准公式 | 简化公式 | DAC值 |
|---|---|---|---|
| 0.00V | 0×255/5 | 0×51 | 0 |
| 1.00V | 1×255/5 | 1×51 | 51 |
| 2.00V | 2×255/5 | 2×51 | 102 |
| 3.41V | 3.41×255/5 | 3.41×51 | 174 |
| 5.00V | 5×255/5 | 5×51 | 255 |
5.
电压显示重复计算问题(可优化)
当前代码:
Seg_Buf[5]=(unsigned int)(Voltage*100)/100%10+',';
Seg_Buf[6]=(unsigned int)(Voltage*100)/10%10;
Seg_Buf[7]=(unsigned int)(Voltage*100)%10;
潜在问题:
-
每行都重复计算
(unsigned int)(Voltage*100),共计算3次 -
如果在计算过程中发生中断,Voltage被AD_DA()修改,可能导致三位数字不一致
-
代码可读性差,不符合DRY原则(Don’t Repeat Yourself)
改进建议(使用临时变量):
case 1:
{
unsigned int temp; // 临时变量,只计算一次
Seg_Buf[0]=12;
Seg_Buf[1]=10;
Seg_Buf[2]=10;
Seg_Buf[3]=10;
Seg_Buf[4]=10;
temp = (unsigned int)(Voltage * 100); // ✓ 只计算一次
Seg_Buf[5] = temp/100%10 + ',';
Seg_Buf[6] = temp/10%10;
Seg_Buf[7] = temp%10;
}
break;
优势:
-
✓ 避免重复计算,提高效率
-
✓ 确保三位数字来自同一次计算,显示一致
-
✓ 代码可读性更好
总结
最严重的错误(会导致功能完全无法工作或不符合题目要求):
-
缺少DAC输出调用 - 题目核心功能缺失,评分时可能直接零分
-
ADC转电压公式错误 - 显示数值完全错误,超出0-5V范围
-
电压界面提示符错误 - 界面标识错误,不符合题目要求
中等错误(会导致功能异常):
-
电压显示计算精度丢失 - 小数部分全部丢失,显示错误
-
DAC输出转换公式错误 - 输出电压只有应该值的1/51
轻微问题(可优化,不影响基本功能):
- 电压显示重复计算 - 效率低,可能有极小概率的显示不一致问题
学到的经验
1. 类型转换的顺序很重要
-
(unsigned char)Voltage * 100- 先转换再乘,精度丢失 -
✓
(unsigned char)(Voltage * 100)- 先乘再转换,保留精度 -
口诀: 浮点运算做完再转整数
2. ADC/DAC芯片的双重功能要理解
-
PCF8591既有ADC又有DAC,是两个独立的功能
-
ADC(读取)≠ DAC(输出),不要混淆
-
题目要求"通过DAC输出",必须调用
Da_Write()
3. 数字量和实际物理量的转换公式
-
ADC/DAC都是数字量(0-255),需要转换为实际电压(0-5V)
-
ADC转电压:
V = ADC ÷ 51或V = ADC × 5 ÷ 255 -
电压转DAC:
DAC = V × 51或DAC = V × 255 ÷ 5 -
记忆技巧: 255÷5=51,记住51这个转换系数
4. 仔细阅读题目要求
-
题目明确说"通过其 DAC 功能输出该电压值"
-
不要以为只读取ADC就够了,输出DAC也是必须的
5. 代码优化的基本原则
-
DRY原则: 不要重复计算,使用临时变量
-
括号原则: 复杂表达式加括号,明确优先级
-
原子性原则: 相关的多位数据应该来自同一次计算,避免中断导致的不一致
生成时间: 2026-02-06
蓝桥杯第十届省赛代码调试总结