这是一个电压采集与计数系统,具有以下功能:
核心功能
- 电压采集:输入4位数字表示电压值(0.001V~9.999V)
- 数据显示:显示当前电压值
- 参数设置:设置参考电压(1.0V~6.0V,步进0.5V)
- 计数统计:统计电压下降沿次数(从高于参考值变为低于参考值)
- LED指示:
- LED0:电压低于参考值超过5秒点亮
- LED1:计数值奇偶指示
- LED2:无效按键指示(≥3次点亮)
四种显示模式
┌──────┬──────────────┬─────────────────────────┐
│ 模式 │ 功能 │ 显示格式 │
├──────┼──────────────┼─────────────────────────┤
│ 0 │ 电压采集界面 │ --XXXX(输入4位数字) │
├──────┼──────────────┼─────────────────────────┤
│ 1 │ 数据显示界面 │ A–X.XX(显示电压) │
├──────┼──────────────┼─────────────────────────┤
│ 2 │ 参数设置界面 │ C–X.XX(设置参考电压) │
├──────┼──────────────┼─────────────────────────┤
│ 3 │ 计数统计界面 │ PXXXXX(显示计数值) │
└──────┴──────────────┴─────────────────────────┘
二、严重BUG与解决方案 ![]()
![]()
![]()
BUG 1:数字输入逻辑错误(第40-48行) ![]()
问题代码:
if(Key_Down >=1 && Key_Down <= 10)
{
if(Seg_Disp_Mode==0 && Seg_Input_Index<4)
Seg_Input[Seg_Input_Index]=Key_Down - 1; //
缺少大括号
Seg_Input_Index++; //
这行总是执行!
Key_Error_Count=0; //
这行总是执行!
}
else //
这个else对应的是外层if
Key_Error_Count++;
问题分析:
- 第43行的if语句后面没有大括号
- 导致第44-45行(Seg_Input_Index++和Key_Error_Count=0)总是执行
- 即使不在采集界面或数组已满,指针也会增加
- 会导致数组越界和逻辑混乱
后果:
场景1:在非采集界面按数字键
→ Seg_Input_Index++ 仍然执行
→ 指针不断增加,可能超过3
→ 下次进入采集界面时,数组越界!
场景2:输入满4位后继续按数字键
→ Seg_Input_Index继续增加(4, 5, 6…)
→ 数组越界访问!
正确写法:
if(Key_Down >= 1 && Key_Down <= 10)
{
if(Seg_Disp_Mode == 0 && Seg_Input_Index < 4)
{
Seg_Input[Seg_Input_Index] = Key_Down - 1;
Seg_Input_Index++;
Key_Error_Count = 0;
}
else
{
Key_Error_Count++;
}
}
BUG 2:界面切换逻辑错误(第91-93行) ![]()
问题代码:
case 12: // 界面切换按键
if(Seg_Disp_Mode != 0)
{
Key_Error_Count = 0;
if(Seg_Disp_Mode == 2)
Voltage_Parameter_Ctrol = Voltage_Parameter; // 保存参数
Seg_Disp_Mode++; //
第一次加1
if(++Seg_Disp_Mode == 4) //
又加1!
Seg_Disp_Mode = 1;
}
问题分析:
- 第91行:Seg_Disp_Mode++(加1)
- 第92行:++Seg_Disp_Mode(又加1)
- 导致每次按S12,模式会跳过一个!
实际效果:
初始:模式1(数据显示)
按S12 → 91行:1+1=2,92行:2+1=3 → 跳到模式3(计数统计)
→ 跳过了模式2(参数设置)!
初始:模式2(参数设置)
按S12 → 91行:2+1=3,92行:3+1=4,判断==4,设为1
→ 跳到模式1
→ 跳过了模式3!
正确写法:
case 12:
if(Seg_Disp_Mode != 0)
{
Key_Error_Count = 0;
if(Seg_Disp_Mode == 2)
Voltage_Parameter_Ctrol = Voltage_Parameter;
// ✓ 方法1:只用一次++
if(++Seg_Disp_Mode == 4)
Seg_Disp_Mode = 1;
// ✓ 方法2:更清晰的写法
Seg_Disp_Mode++;
if(Seg_Disp_Mode >= 4)
Seg_Disp_Mode = 1;
}
else
Key_Error_Count++;
break;
BUG 3:变量j未初始化(第193行) ![]()
问题代码:
case 3: // 计数统计界面
// …
unsigned char j; //
第143行声明但未初始化
// …
while(Seg_Buf[j] == 0) //
第193行:j的值是随机的!
{
Seg_Buf[j] = 10;
if(++j == 5)
break;
}
break;
问题分析:
- 变量j在第143行声明,但没有初始化
- 第193行直接使用j,其值是随机的(可能是0,也可能是255)
- 如果j的初始值很大,会导致数组越界
后果:
场景1:j初始值为0(运气好)
→ 正常工作,去除前导零
场景2:j初始值为100(运气不好)
→ Seg_Buf[100]访问越界!
→ 程序崩溃或显示异常
正确写法:
case 3:
Seg_Point[3+(int)Voltage/10] = 0;
Seg_Buf[0] = 14;
Seg_Buf[1] = Count / 10000 % 10;
Seg_Buf[2] = Count / 1000 % 10;
Seg_Buf[3] = Count / 100 % 10;
Seg_Buf[4] = Count / 10 % 10;
Seg_Buf[5] = Count % 10;
// ✓ 初始化j
j = 1; // 从第1位开始去除前导零
while(j < 5 && Seg_Buf[j] == 0) // ✓ 添加边界检查
{
Seg_Buf[j] = 10;
j++;
}
break;
BUG 4:Led_Pos未更新(第243行) ![]()
问题代码:
void Timer0Server() interrupt 1
{
// …
if(++Seg_Pos == 6) Seg_Pos = 0; // ✓ 数码管位置更新
Seg_Disp(Seg_Pos, Seg_Buf[Seg_Pos], Seg_Point[Seg_Pos]);
Led_Disp(Led_Pos, ucLed[Led_Pos]); // ❌ Led_Pos没有更新!
// ...
}
问题分析:
- Seg_Pos在中断中每1ms加1,实现数码管扫描
- 但Led_Pos没有更新,一直是0
- 导致只有第0个LED会被刷新,其他LED不工作
后果:
LED0:正常工作(一直被刷新)
LED1:不工作(从不被刷新)
LED2:不工作(从不被刷新)
LED3-7:不工作
正确写法:
void Timer0Server() interrupt 1
{
TL0 = 0x18;
TH0 = 0xFC;
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;
if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;
// 数码管扫描
if(++Seg_Pos == 6) Seg_Pos = 0;
Seg_Disp(Seg_Pos, Seg_Buf[Seg_Pos], Seg_Point[Seg_Pos]);
// ✓ LED扫描
if(++Led_Pos == 8) Led_Pos = 0;
Led_Disp(Led_Pos, ucLed[Led_Pos]);
if(Voltage < Voltage_Parameter_Ctrol)
Sys_Tick++;
if(++Timer_500Ms == 500)
{
Timer_500Ms = 0;
Seg_Flag ^= 1;
}
}