蓝桥杯模块训练笔记:PCF8591 电压采集与输出
1. 核心功能概述
本系统主要实现两个功能:
-
ADC 采集:读取板载电位器 (RB2) 的电压值。
-
DAC 输出:根据模式,输出固定电压或跟随采集电压。
同时配合数码管显示界面切换和 LED 状态指示。
2. 代码与题目需求对照解析
2.1 初始状态设置 (Initial State)
题目要求:
“初始状态上电默认处于电压测量状态… PCF8591 DAC 芯片输出固定电压值 2.0V。” 1
代码实现:
C
// 1. 定义全局变量时直接初始化
unsigned char seg_disp_mode; // 默认为0,即电压测量显示界面(U)
bit voltage_mode = 1; // 【关键】初始化为1,代表固定电压模式
void seg_proc() {
// ...
// 2. 三目运算符决定输出值:如果 mode 是 1,输出 2.0,否则跟随 voltage
voltage_out = voltage_mode ? 2 : voltage;
// ...
}
解析:
通过将 voltage_mode 显式初始化为 1,保证了上电第一刻 voltage_out 就是 2.0V,完美符合题目对初始状态的要求。
2.2 AD/DA 核心驱动 (ADC & DAC)
题目要求:
“电位器 RB2 输出的电压值” 22"DAC 输出电压…" 3
代码实现:
C
// 在 seg_proc 中:
voltage = ad_read(0x43) / 51.0;
// 在 led_proc 中:
da_write(voltage_out * 51);
解析与防坑:
-
ad_read(0x43)的含义:-
0x03代表读取通道 3 (AIN3,即电位器 RB2)。 -
0x40代表 允许 DAC 输出 (DA Output Enable)。 -
重点: 如果只写
0x03,在读取电压的同时会关闭 DA 输出。写成0x43是为了保证“一边读电压,一边还能正常输出电压”。
-
-
/ 51.0与\* 51: 8位 AD/DA 的分辨率是 255 (5V)。即 1V = 51 (255/5)。
2.3 按键逻辑映射 (Key Logic)
S4:界面切换
题目要求:
“S4…切换选择电压显示界面和电压输出界面” 4
代码实现:
C
case 4:
if(++seg_disp_mode == 2) seg_disp_mode = 0;
break;
解析: 利用 seg_disp_mode 在 0 和 1 之间循环,0 代表 U 界面,1 代表 F 界面。
S5:DAC 模式切换
题目要求:
“S5…DAC 输出电压跟随电位器…再次按下 S5,DAC 输出固定电压 2.0V” 5
代码实现:
C
case 5:
voltage_mode ^= 1; // 0和1之间取反
break;
解析: voltage_mode 变量控制了数据源的选择逻辑。
S6 & S7:显示功能控制
题目要求:
“S6…关闭或打开 LED 指示灯” 6"S7…关闭或打开数码管显示" 7
代码实现:
C
case 6: led_flag ^= 1; break; // 翻转 LED 标志位
case 7: seg_flag ^= 1; break; // 翻转 数码管 标志位
// 在中断函数 timer0serve 中生效:
if(seg_flag) seg_disp(...); // 标志位为 1 才扫描显示
if(led_flag) led_disp(...);
解析: 使用标志位控制底层扫描函数的执行,是实现“整体熄灭”最干净的方法。
2.4 数码管显示逻辑 (Display)
题目要求:
“测量界面显示 U…输出界面显示 F” 8888"保留小数点后两位有效数字" 9999
代码实现:
C
if(seg_disp_mode == 0) { // U 界面
seg_buf[0] = 11; // 对应字模 'U'
// 显示采集到的电压 voltage
seg_buf[5] = (unsigned char)voltage % 10;
seg_buf[6] = (unsigned char)(voltage * 10) % 10;
seg_buf[7] = (unsigned char)(voltage * 100) % 10;
} else { // F 界面
seg_buf[0] = 12; // 对应字模 'F'
// 显示输出电压 voltage_out
// ...同上处理 voltage_out ...
}
解析:
-
精度处理: 浮点数取小数位的经典算法。例如 2.34V:
-
个位:
2.34 % 10(强转int) = 2 -
十分位:
23.4 % 10= 3 -
百分位:
234 % 10= 4
-
2.5 LED 逻辑 (Logic Operation)
L3:电压区间指示(重点逻辑)
题目要求:
1.5V ≤ V < 2.5V 点亮; V ≥ 3.5V 点亮;其余熄灭 10
代码实现:
C
ucled[2] = ((voltage >= 1.5 && voltage < 2.5) || (voltage >= 3.5));
解析:
这段代码直接把数学区间翻译成了 C 语言逻辑表达式:
-
区间1:
[1.5, 2.5)→voltage >= 1.5 && voltage < 2.5 -
区间2:
[3.5, +∞)→voltage >= 3.5 -
逻辑或
||连接两个区间。
L4:DAC 模式指示
题目要求:
“DAC 输出固定电压(2.0V)时,L4 熄灭…跟随…时,L4 点亮” 11
代码实现:
C
ucled[3] = (voltage_mode == 0);
解析:
-
当
voltage_mode为 1 (固定模式) →(1==0)为假 → L4 熄灭。 -
当
voltage_mode为 0 (跟随模式) →(0==0)为真 → L4 点亮。
3. 核心知识点总结
-
标志位初始化的重要性: 全局变量如果不初始化,默认为 0。对于要求“上电默认开启/特定模式”的题目,必须手动赋值(如
bit voltage_mode = 1)。 -
PCF8591 控制字技巧: 记住
0x40是 DA 使能位。读 AD 时如果想保持 DA 输出,一定要加上这个值(如0x01 | 0x40或0x03 | 0x40)。 -
分离采集与显示:
-
采集 (
seg_proc): 处理数据,计算voltage_out。 -
显示 (
timer0serve): 负责刷新数码管和 LED。 -
这样逻辑分层清晰,不会因为显示延时影响数据计算。
-
-
按键消抖与状态机: 代码使用了
switch(key_down)结构,这是处理多按键功能最清晰的方式。
4. 你的代码评价
这份代码结构非常优秀,属于高分模板。
-
优点: 逻辑变量命名规范(
voltage_mode,led_flag),代码可读性强,完美利用了 C 语言的逻辑运算符简化代码(如 LED 部分)。 -
适用性: 直接可以作为蓝桥杯省赛、国赛的基础框架使用。