
1. 项目概述为什么用树莓派Pico做电压表如果你手头正好有一块闲置的树莓派Pico又或者你对嵌入式测量设备感兴趣那么用Pico自制一个电压表绝对是一个能让你深入理解模数转换和嵌入式系统的好项目。这不仅仅是一个简单的“玩具”而是一个能实际测量0-3.3V直流电压的实用工具。市面上几十块钱就能买到一个不错的数字万用表为什么还要自己动手做原因很简单知其然更要知其所以然。通过这个项目你能亲手打通从模拟信号到数字显示的完整链路理解ADC模数转换器的分辨率、采样率、参考电压这些关键参数的实际意义而不仅仅是书本上的概念。树莓派Pico的核心RP2040微控制器内置了一个12位的ADC模块这为我们提供了硬件基础。这个项目适合所有对电子制作和嵌入式编程感兴趣的爱好者无论你是刚接触MicroPython的新手还是想深入了解RP2040 ADC特性的开发者。最终你将得到一个通过USB供电、在OLED屏幕上实时显示电压值、精度足以应对大多数低压电路调试需求的小设备。接下来我会带你从原理到焊接从代码到校准完整走一遍这个项目的实现过程。2. 核心硬件选型与电路设计思路2.1 主控与ADC为什么是树莓派Pico选择树莓派Pico作为核心主要基于三点考量性价比、易用性和ADC性能。RP2040芯片内置了3个ADC通道GP26, GP27, GP28分辨率是12位。这意味着它可以将0到3.3V的输入电压量化为0到40952^12 - 1之间的一个数字。理论上的电压分辨率是 3.3V / 4095 ≈ 0.0008V也就是0.8mV。这个精度对于测量电池电压、传感器输出、分压电路节点电压等场景已经足够。注意这里的3.3V是RP2040的ADC参考电压VREF它直接取自芯片的3.3V电源引脚。因此电源的稳定性直接决定了测量精度。如果3.3V电源有波动测量值就会漂移。这是所有以电源电压为参考的ADC的共性问题。相较于使用外置ADC芯片的方案使用内置ADC省去了额外的硬件和SPI/I2C通信代码让项目更简洁特别适合入门。Pico的MicroPython固件对ADC的支持也非常友好几行代码就能启动采样极大地降低了软件门槛。2.2 输入保护与信号调理电路设计直接将待测电压接到Pico的GPIO上是危险的。如果电压超过3.3V可能会永久损坏芯片。因此一个可靠的输入保护电路是必须的。我们的设计目标是安全第一并尽量减小对被测电路的影响。我采用的经典方案是“电阻分压钳位保护”。电路虽小但每一部分都有其作用输入分压网络针对高于3.3V的测量虽然Pico的ADC只能直接测0-3.3V但通过分压电阻我们可以扩展量程。例如使用一个9:1的分压比90kΩ和10kΩ串联就可以将0-33V的待测电压降到0-3.3V范围内。计算关系是ADC测得的电压 待测电压 * (R2 / (R1 R2))。选择兆欧级的大电阻可以减小对被测电路的分流影响。电压钳位保护即使在设计为测量3.3V以下的档位意外接入高压的风险依然存在。我在ADC输入引脚前并联了两个反向串联的肖特基二极管如BAT54S到地和3.3V。当输入电压低于-0.3V或高于3.6V时二极管会导通将电压钳位在安全范围从而保护GPIO引脚。肖特基二极管的选择是因为其导通压降低约0.3V反应速度快。RC低通滤波在ADC输入引脚处对地连接一个0.1uF的陶瓷电容。这个电容的作用是滤除高频噪声。模拟信号线上很容易耦合进各种开关噪声导致ADC采样值跳动。这个小电容可以与信号源阻抗构成一个低通滤波器平滑信号得到更稳定的读数。时间常数τ R * C要远小于你的采样周期避免造成信号延迟。2.3 显示模块选型OLED vs LCD为了直观显示电压值一个显示模块必不可少。我强烈推荐使用0.96英寸的I2C接口OLED屏幕而不是1602字符LCD。原因如下功耗与对比度OLED是自发光黑色像素不耗电在显示简单数据时功耗极低且对比度超高可视角度广。接口与占用I2C接口仅需两根数据线SDA, SCL加上电源和地总共4根线比LCD的并行接口或SPI接口节省大量GPIO。图形能力OLED是像素点阵可以显示自定义图形、绘制简单的波形或电池图标可玩性更高。常见的SSD1306驱动芯片有成熟的MicroPython库支持。对于这个电压表项目显示实时电压值、最大值、最小值、甚至是简单的条形图OLED都能轻松胜任。2.4 供电方案考量树莓派Pico可以通过USB接口供电非常方便。这意味着你的整个电压表只需要一根USB线连接电脑、充电宝或手机充电器即可工作。但这里有一个重要的实操细节如果你使用电脑USB供电并测量同一台电脑上其他USB设备的电压可能会因为共地原因引入测量误差或风险。最佳实践是使用一个独立的电源适配器或充电宝为Pico供电确保被测电路与测量系统的地是隔离的或者至少你清楚它们之间的地线关系。3. 软件架构与MicroPython代码实现3.1 开发环境搭建与库管理首先你需要给树莓派Pico刷入最新的MicroPython固件。这个过程很简单按住Pico上的BOOTSEL按钮通过USB连接到电脑它会作为一个U盘出现然后将下载的.uf2固件文件拖进去即可。之后你可以使用Thonny、Mu Editor或VS Code with Pico-Go插件作为开发环境。我个人习惯用Thonny因为它对MicroPython的设备连接和文件管理非常直观。接下来是库文件。我们需要两个ssd1306.py用于驱动OLED屏幕。你可以从MicroPython的官方库或开源社区轻松找到。machine和time这是MicroPython的内置库用于控制硬件和延时。将ssd1306.py文件通过IDE上传到Pico的根目录下这样在主程序中就可以直接import了。3.2 ADC采样与数据处理核心代码解析测量的核心在于ADC的读取和数据的处理。下面是一个功能核心段的代码拆解import machine import time # 初始化ADC使用GP26通道对应物理引脚31 adc machine.ADC(26) # 初始化I2C和OLED (假设I2C0, SDAGP0, SCLGP1) i2c machine.I2C(0, sdamachine.Pin(0), sclmachine.Pin(1)) oled SSD1306_I2C(128, 64, i2c) # ADC参考电压通常是Pico的3.3V VREF 3.3 # ADC分辨率 12位 4096 ADC_RESOLUTION 4096 def read_voltage(samples100): 读取电压值通过多次采样取平均来抑制噪声 sum_adc 0 for _ in range(samples): sum_adc adc.read_u16() # 读取16位数值但RP2040 ADC实际有效位为12位 time.sleep_us(10) # 短暂延时避免采样过快 average_adc sum_adc / samples # 将ADC值转换为电压。注意read_u16()返回0-65535对应0-3.3V需换算。 voltage (average_adc / 65535) * VREF return voltage def display_voltage(v): oled.fill(0) # 清屏 oled.text(Voltage Meter, 0, 0) oled.text(Value:, 0, 16) # 格式化显示保留3位小数 oled.text({:.3f} V.format(v), 0, 32) # 可以添加一个简单的条形图 bar_length int((v / VREF) * 100) # 假设满量程3.3V对应100像素长度 oled.fill_rect(0, 50, bar_length, 10, 1) # 绘制矩形条 oled.show()代码要点解析多次采样平均read_voltage函数中的samples参数默认为100。单次ADC采样容易受到噪声干扰通过采集上百个点然后取算术平均可以有效地平滑随机噪声得到更稳定的读数。这是软件滤波最基本有效的方法。read_u16()返回值处理MicroPython的ADC.read_u16()方法返回一个0-65535之间的整数尽管硬件是12位ADC。这是因为API设计为了统一。所以转换电压时分母是65535而不是4095。这是一个常见的困惑点。延时的重要性time.sleep_us(10)这行代码很关键。ADC转换需要时间连续无间隔地读取可能会导致内部电路未准备好反而引入误差。一个微秒级的短延时能保证每次采样都是有效的。3.3 显示界面与用户交互设计一个友好的界面能提升使用体验。除了显示实时电压我们还可以增加一些实用功能最大值/最小值保持在循环中记录并显示自启动以来测到的最高和最低电压对于观察电压波动非常有用。单位自动切换当电压小于1V时自动以毫伏mV显示提高可读性。简单的波形趋势利用OLED的像素绘图功能在屏幕下方划出一块区域将最近的电压值以点图形式连接起来形成简单的实时趋势图可以直观看到电压变化。这些功能的添加会让你的电压表从“能用”变得“好用”也是编程练习的好机会。4. 系统校准与精度提升实战4.1 参考电压的校准解决最大的误差源如前所述ADC的参考电压VREF直接取自3.3V电源线。这个电压并非精确的3.300V它可能因负载、温度、USB电源质量而在3.25V到3.35V之间波动。使用一个不准确的VREF值进行计算会产生系统性的比例误差。校准就是设法得到一个更接近真实的VREF值。校准方法需要一块已知准确的电表作为参考准备一个稳定且精确的电压源。最经济的方法是使用一个新的1.5V干电池或一颗满电的3.7V锂离子电池电压约4.2V并用你信任的高精度数字万用表如Fluke或至少三位半的表测量其精确电压记为V_actual例如1.543V。将这个已知电压接入你的Pico电压表输入电路如果电压超过3.3V请确保使用了正确的分压电路。在你的代码中让Pico电压表读取并计算出一个原始的ADC值未经VREF换算的比值。通常我们计算比值ratio average_adc / 65535。此时我们知道V_actual ratio * VREF_true。因此可以反推出真实的参考电压VREF_true V_actual / ratio。将计算出的VREF_true替换代码中固定的VREF 3.3。经过此校准后你的电压表在测量该量程附近的电压时精度会大幅提升。实操心得校准点最好选择在你常用的量程中间。例如你主要测0-3.3V那么用1.5V左右的电压校准效果最好。如果条件允许可以在两个点如1V和2.5V进行校准然后采用线性拟合的方式得到更优的VREF这可以补偿ADC可能存在的微小非线性。4.2 软件滤波算法进阶除了简单的算术平均还可以引入更高级的软件滤波来应对不同场景移动平均滤波维护一个固定长度的队列每次新采样值进入最老的采样值排出始终计算队列的平均值。这对实时显示很友好能平滑变化但又不至于延迟太大。中值滤波连续采样N次如5次然后取这N个值的中位数作为输出。这种方法对脉冲噪声偶尔出现的尖峰干扰有奇效。在电气噪声复杂的环境中结合平均滤波和中值滤波效果出众。# 一个简单的移动平均滤波示例 class MovingAverage: def __init__(self, size): self.size size self.queue [] def add(self, value): self.queue.append(value) if len(self.queue) self.size: self.queue.pop(0) def get_avg(self): return sum(self.queue) / len(self.queue) if self.queue else 0 # 在主循环中使用 filter MovingAverage(20) raw_voltage read_voltage(samples5) # 先小样本快速读取 filter.add(raw_voltage) display_voltage(filter.get_avg()) # 显示经过移动平均的值4.3 输入阻抗的影响与应对你的电压表接入电路时相当于在测量点并联了一个电阻即你的分压电阻网络。这个并联电阻就是电压表的输入阻抗。如果输入阻抗不够高它会从被测电路中汲取电流导致被测点的电压被“拉低”产生测量误差。如何提高输入阻抗使用大阻值分压电阻例如用1MΩ和100kΩ串联分压比相同其输入阻抗约为1.1MΩ远高于使用10kΩ和1kΩ组合的11kΩ。但注意电阻值越大热噪声可能越大且对PCB漏电流更敏感。使用电压跟随器运算放大器这是专业仪表的做法。在输入前端加入一个单位增益的运放缓冲器如TLV341。运放具有极高的输入阻抗可达GΩ级别和极低的输出阻抗可以完美地将高阻抗的待测信号转换为低阻抗信号送给ADC分压电路几乎不从前端电路汲取电流。这对于测量高内阻的信号源如某些传感器至关重要。对于大多数低压数字电路调试采用兆欧级的分压电阻已经能提供足够高的输入阻抗避免影响电路工作。但在测量诸如干电池开路电压这种要求极高输入阻抗的场景时就需要考虑运放缓冲方案了。5. 组装调试与常见问题排查5.1 焊接与布局注意事项建议使用一块小型洞洞板或定制简单的PCB来组装所有元件而不是直接用杜邦线连接。长期使用中杜邦线容易接触不良引入噪声。电源去耦在Pico的3.3V和GND引脚附近焊接一个10uF的钽电容和一个0.1uF的陶瓷电容用于滤除电源噪声这对ADC稳定性至关重要。信号走线ADC输入走线要尽量短并远离数字信号线如I2C、电源线。如果走线较长可以考虑用屏蔽线或双绞线。接地确保所有地线GND良好连接形成“星型接地”或单点接地避免地线环路引入干扰。5.2 典型问题与解决方案速查表问题现象可能原因排查步骤与解决方案读数跳动大不稳定1. 电源噪声大2. 输入信号噪声大3. 软件采样次数少1. 检查电源改用电池或优质USB电源供电。2. 在ADC输入引脚增加RC滤波如1kΩ 0.1uF。3. 增加read_voltage()函数中的samples参数值如从100增至500。测量值始终为0或接近01. 输入信号线断路2. ADC通道配置错误3. 分压电阻值错误或短路1. 用万用表通断档检查输入线路。2. 确认代码中machine.ADC()初始化引脚号正确GP26对应物理引脚31。3. 检查分压电阻焊接测量分压点电压是否正常。测量值恒定在最大值3.3V1. 输入引脚对VCC短路2. ADC引脚损坏3. 外部电压超过3.3V且无分压1. 检查PCB或连线是否有短路。2. 换一个ADC通道如GP27测试。3. 确认待测电压范围若超过3.3V必须使用分压电路。OLED屏幕不显示1. I2C地址错误2. 电源或接线错误3. 库文件未上传1. 运行i2c.scan()查看发现的I2C设备地址通常SSD1306是0x3C。2. 确认VCC、GND、SDA、SCL四根线连接正确牢固。3. 确认ssd1306.py文件已上传至Pico。测量值存在固定偏差1. ADC参考电压不准确未校准2. 分压电阻精度不够1. 执行本章节4.1所述的参考电压校准流程。2. 使用精度为1%或更高的金属膜电阻进行分压。5.3 从原型到成品外壳与功能扩展当电路和代码都稳定工作后可以考虑给它一个“家”。3D打印一个小巧的外壳将Pico、OLED屏幕和输入接线柱固定起来一个像模像样的自制仪表就诞生了。你还可以扩展更多功能多量程切换通过一个旋转开关或数字电位器切换不同的分压电阻网络实现自动量程或手动选择量程如0-3.3V, 0-10V, 0-30V。数据记录将测量到的电压以固定时间间隔写入Pico的Flash存储中形成简单的数据记录仪。上位机通信通过USB串口将实时电压数据发送到电脑用Python脚本绘制曲线或进行更复杂的分析。这个基于树莓派Pico的电压表项目其价值远不止于测量电压本身。它是一把钥匙带你深入嵌入式系统模拟前端的设计、软件滤波算法的应用、测量仪表的校准原理。每一次调试和优化都是对“精度”和“稳定性”这两个工程核心概念的切身理解。当你亲手做出的设备能稳定、相对准确地显示电压时那种成就感是购买成品无法比拟的。