Arduino电压表制作:从分压原理到OLED显示的完整实践

发布时间:2026/6/3 17:16:29

Arduino电压表制作:从分压原理到OLED显示的完整实践 1. 项目概述为什么我们需要一个Arduino电压表在捣鼓电子项目时测量电压就像电工的万用表、厨师的温度计是最基础也最频繁的需求。无论是调试一个自制的电源、监测电池的剩余电量还是检查太阳能板的输出你都需要知道“电压是多少”。直接用万用表当然方便但当你希望这个测量值能自动显示、记录甚至触发其他动作时就需要把它集成到你的嵌入式系统里。这就是本项目的核心价值将一个基础的测量功能变成一个智能、可集成的模块。Arduino UNO作为最流行的开源硬件平台其内置的ADC模数转换器引脚可以读取0-5V的模拟电压。但现实世界中的电压常常超出这个范围比如常见的12V蓄电池、24V工业电源甚至更高的电压。直接连接会瞬间烧毁Arduino的ADC引脚后果很严重。因此我们必须借助一个经典且可靠的电路——电压分压器来充当一个“安全降压变压器”。本项目将手把手带你实现一个0-50V直流电压测量装置。我们将从最根本的欧姆定律和分压原理讲起设计并计算分压电阻然后通过Arduino读取处理后的信号最终将精确的电压值实时显示在一块小巧的OLED屏幕上。整个过程不仅是一次代码和连线的练习更是一次对模拟电路基础、ADC工作原理以及嵌入式系统数据流处理的完整实践。无论你是刚接触Arduino的爱好者还是希望巩固基础知识的电子工程学生这个项目都能提供从理论到落地的清晰路径。2. 核心原理与电路设计解析2.1 电压分压器将高压“翻译”成低压的语言电压分压器是模拟电路中最基础的电路之一其核心原理直接源于欧姆定律。想象一下水流过两根粗细不同的水管在水压电压一定的情况下粗水管小电阻分担的水压小细水管大电阻分担的水压大。电压分压器就是利用两个串联电阻对输入电压进行按比例分配。其计算公式非常简单Vout Vin * (R2 / (R1 R2))。其中Vin是待测的高电压Vout是我们希望输入给Arduino的、不超过5V的安全电压。R1和R2就是两个串联的电阻Vout从R2两端取出。这个公式是整个项目的数学基石。我们的设计目标是当待测电压Vin达到最大值50V时Vout恰好为5VArduino ADC的满量程。这样ADC读取到的数值0-1023就能线性地反向推算出0-50V的原始电压。选择R110kΩR21kΩ代入公式验证Vout 50V * (1k / (10k 1k)) ≈ 50V * (1/11) ≈ 4.55V。等等这里和原文的5V有出入这是一个非常关键的点。注意计算复核与安全裕量的重要性原文中提到当Vin50V时Vout5V但根据公式计算若R110k R21k实际Vout约为4.55V。这并非错误而可能是一种隐含的“安全裕量”设计。让最大输入电压对应的输出略低于5V如4.55V可以提供一个缓冲区间防止因电阻精度、电压波动或计算误差导致Vout瞬间超过5V而损坏单片机。在实际工程中预留10%左右的裕量是良好的习惯。我们后续的程序校准也将基于这个实际比例50V / 4.55V ≈ 11进行。2.2 Arduino ADC的“世界观”从模拟量到数字量Arduino UNO的ADC引脚A0-A5能将0-5V的模拟电压转换为0-1023的整数数字值。这个过程可以理解为一把有1024个刻度的“尺子”去丈量0-5V的“长度”。每个刻度代表的电压值是5V / 1024 ≈ 0.00488V或4.88mV。当我们通过分压器将50V映射到约4.55V后ADC的每个刻度对应的实际待测电压就变成了50V / 1024 ≈ 0.0488V或48.8mV。这意味着我们的测量理论分辨率约为0.05V。对于大多数业余监测和调试场景这个精度已经足够。然而ADC的测量并非完美。存在偏移误差、增益误差和噪声。因此我们不能完全依赖理论计算。在最终的程序中我们会引入一个“校准系数”通过用已知精密的电压源如可调稳压电源测量几个点来修正这个比例系数从而获得更接近真实值的读数。2.3 元器件选型考量为什么是这些参数电阻选型R110kΩ R21kΩ阻值比例决定了分压比约1:11。这个比例在测量范围和ADC利用率之间取得了平衡。比例太大如R2过小则Vout过低浪费了ADC的量程降低分辨率比例太小如R2过大则R1需要极大容易引入噪声和阻抗匹配问题。电阻精度普通5%精度的碳膜电阻即可用于学习和一般应用。若追求更高精度应选用1%甚至0.1%精度的金属膜电阻这能直接从硬件上减少测量误差。电阻功率需要计算电阻的功耗。在最大电压50V时流经电阻的电流 I Vin / (R1R2) 50V / 11kΩ ≈ 4.55mA。R1上的功耗 P_R1 I² * R1 ≈ (0.00455A)² * 10000Ω ≈ 0.207W。R2上的功耗更小。因此普通的1/4W0.25W电阻完全满足要求且留有充足余量。OLED显示模块选型型号常见的有0.96寸或1.3寸的I2C接口OLED屏驱动芯片多为SSD1306。I2C接口仅需两根信号线SDA SCL极大节省了IO口。优点相比LCDOLED自发光、对比度高、视角广、响应快且功耗极低特别适合电池供电的便携设备。电压匹配模块工作电压通常为3.3V或5V。我们使用5V供电的版本直接与Arduino 5V引脚连接逻辑电平匹配无需电平转换。3. 硬件搭建与连接详解3.1 物料清单与工具准备除了核心元器件一些辅助工具和材料能让制作过程更顺利核心物料Arduino UNO开发板 x1I2C接口的0.96寸OLED显示屏SSD1306驱动 x110kΩ 电阻1/4W x11kΩ 电阻1/4W x1杜邦线公对公、公对母若干辅助工具与材料面包板 x1用于快速搭建和测试电路无需焊接。万用表 x1至关重要用于验证实际电压、校准系统是电子制作的“眼睛”。可调直流稳压电源可选但强烈推荐用于提供精确的、可调的电压源进行系统校准。待测电源如9V电池、12V适配器用于最终测试。3.2 分压电路连接步骤与要点在面包板上按照以下步骤搭建电路务必在通电前反复检查搭建分压器将10kΩ电阻R1的一端连接到待测电压的正极Vin。这个点我们将称之为“测量正极输入点”。将10kΩ电阻R1的另一端与1kΩ电阻R2的一端相连。这个连接点就是我们的信号输出点Vout稍后要连接到Arduino的A0引脚。将1kΩ电阻R2的另一端连接到待测电压的负极Vin-同时也是整个系统的地GND。务必确保Arduino的GND、OLED的GND和测量输入的负极最终都连接在一起共地是电路正常工作的基础。连接至Arduino将上述的信号输出点Vout用杜邦线连接到Arduino的模拟输入引脚 A0。将系统的地GND连接到Arduino的任意一个GND引脚。重要安全警告极性绝对禁止接反待测电压的正负极必须正确接入分压器。反接可能导致负电压输入ADC引脚即使电流很小也可能损坏芯片。先接线后上电在连接待测电源尤其是高压如50V之前确保所有连接特别是地线的连接牢固无误。养成“断电操作”的习惯。电压上限本电路设计用于直流电压。严禁测量市电220V交流即使是直流也请确保待测电压不超过50V的设计上限。如果想测量更高电压必须按比例增大电阻值并重新计算电阻功率。3.3 OLED显示屏与Arduino的连接I2C接口的连接非常简洁遵循标准的四线制OLED模块的 VCC-Arduino的 5V引脚。OLED模块的 GND-Arduino的 GND引脚与分压器共地。OLED模块的 SCL-Arduino的 A5引脚在UNO上A5也是I2C的时钟线SCL。OLED模块的 SDA-Arduino的 A4引脚在UNO上A4也是I2C的数据线SDA。有些OLED模块可能有额外的复位RST或直流DC引脚那是用于SPI接口的。对于I2C接口的四针模块通常只有以上四根线。连接后OLED屏幕可能会立即亮起显示乱码或空白这是正常的待程序上传后即可正常显示。4. 软件编程与代码深度剖析4.1 开发环境配置与库安装首先确保你已安装Arduino IDE。本项目需要两个第三方库来驱动OLEDAdafruit SSD1306库这是针对SSD1306驱动芯片的主控库。Adafruit GFX库这是一个图形库SSD1306库依赖于它来绘制图形和文字。安装方法在Arduino IDE中点击「工具」-「管理库…」在库管理器中分别搜索“Adafruit SSD1306”和“Adafruit GFX”选择安装即可。安装SSD1306库时通常会提示你一并安装依赖的GFX库按照提示操作即可。4.2 核心代码实现与逐行解读以下是完整的Arduino代码并附有详细注释// 引入必要的库 #include Wire.h // I2C通信库Arduino内置 #include Adafruit_GFX.h // 图形库 #include Adafruit_SSD1306.h // OLED驱动库 // 定义OLED屏幕参数0.96寸128x64像素常见型号 #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 // 如果屏幕有RESET引脚则接其编号否则为-1 #define SCREEN_ADDRESS 0x3C // I2C地址0x3C或0x3D常用0x3C // 初始化OLED对象 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, Wire, OLED_RESET); // 定义硬件连接引脚 const int voltageSensorPin A0; // 电压信号输入引脚 // 定义分压器参数 const float R1 10000.0; // 上臂电阻单位欧姆 const float R2 1000.0; // 下臂电阻单位欧姆 // 根据公式计算分压比Vout Vin * (R2/(R1R2)) // 所以 Vin Vout * ((R1R2)/R2) const float voltageDividerRatio (R1 R2) / R2; // 约等于 11.0 // 校准系数用于修正理论计算与实际电路的微小偏差 // 初始值为1.0校准后修改此值 float calibrationFactor 1.00; // 例如实测偏大2%则设为0.98 // Arduino ADC参考电压UNO默认为5V。若使用板载3.3V作参考则修改此处。 const float ADC_REFERENCE_VOLTAGE 5.0; // ADC分辨率UNO为10位即0-1023 const int ADC_RESOLUTION 1023; void setup() { // 初始化串口通信用于调试输出波特率9600 Serial.begin(9600); // 初始化OLED显示 if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { Serial.println(F(SSD1306分配失败)); for(;;); // 如果初始化失败程序在此处停止 } Serial.println(OLED初始化成功); // 清空屏幕缓冲区 display.clearDisplay(); // 设置默认文本颜色为白色 display.setTextColor(SSD1306_WHITE); // 显示欢迎信息 display.setTextSize(2); display.setCursor(10, 0); display.println(Voltmeter); display.setTextSize(1); display.setCursor(15, 30); display.println(Initializing...); display.display(); // 将缓冲区内容推送到屏幕显示 delay(2000); // 显示2秒 // 设置模拟输入引脚 pinMode(voltageSensorPin, INPUT); // 注意模拟输入引脚默认就是输入模式此处显式声明是良好习惯 // 清屏准备显示实时数据 display.clearDisplay(); } void loop() { // 步骤1读取模拟值并进行数字滤波 int sensorValue readAverageAnalog(voltageSensorPin, 10); // 读取10次取平均 // 步骤2将模拟值转换为分压后的电压即ADC引脚上的电压Vout float voltageAtADC (sensorValue * ADC_REFERENCE_VOLTAGE) / ADC_RESOLUTION; // 步骤3应用分压比和校准系数计算真实的待测电压Vin float measuredVoltage voltageAtADC * voltageDividerRatio * calibrationFactor; // 步骤4串口输出用于调试和校准 Serial.print(ADC读数: ); Serial.print(sensorValue); Serial.print( | 引脚电压: ); Serial.print(voltageAtADC, 3); // 显示3位小数 Serial.print(V | 测量电压: ); Serial.print(measuredVoltage, 2); // 显示2位小数 Serial.println(V); // 步骤5在OLED屏幕上显示结果 updateOLEDDisplay(measuredVoltage); // 控制刷新率每秒更新约5次200ms间隔 delay(200); } // 函数多次读取取平均值以减小随机噪声 int readAverageAnalog(int pin, int numReadings) { long sum 0; for (int i 0; i numReadings; i) { sum analogRead(pin); delay(1); // 短暂延时让ADC稳定 } return sum / numReadings; // 返回整数平均值 } // 函数更新OLED屏幕显示 void updateOLEDDisplay(float voltage) { display.clearDisplay(); // 显示标题 display.setTextSize(1); display.setCursor(0, 0); display.println(DC Voltmeter); // 绘制一条分隔线 display.drawFastHLine(0, 10, display.width(), SSD1306_WHITE); // 显示电压值使用大字体 display.setTextSize(3); display.setCursor(15, 20); display.print(voltage, 1); // 显示1位小数 display.setTextSize(2); display.print( V); // 显示量程和状态 display.setTextSize(1); display.setCursor(0, 55); display.print(Range: 0-50V); // 将缓冲区内容推送到屏幕 display.display(); }代码关键点解析数字滤波 (readAverageAnalog函数)analogRead()函数会引入随机噪声。通过连续读取10次然后取平均值可以有效地平滑数据使显示值更稳定避免最后一位数字不停跳动。这是提升测量显示体验的一个简单而有效的小技巧。电压计算流程sensorValue(0-1023) - 乘以ADC_REFERENCE_VOLTAGE/ADC_RESOLUTION- 得到voltageAtADC(0-5V)。voltageAtADC*voltageDividerRatio(约11) - 得到初步的measuredVoltage。最后乘以calibrationFactor进行软件校准。校准系数 (calibrationFactor)这是连接理论与实际的桥梁。在硬件焊接或插接中电阻的实际值、ADC的参考电压都可能与标称值有细微偏差。通过后续的校准步骤确定这个系数通常非常接近1如0.98或1.02可以显著提高测量精度。4.3 上传代码与初步测试在Arduino IDE中正确选择板卡Arduino Uno和端口。将代码粘贴进去点击上传。上传成功后打开串口监视器波特率设为9600你应该能看到不断滚动的电压数据。此时先不要连接外部待测电压。让测量输入端悬空或短路到地观察读数。理论上应接近0V但可能有一些毫伏级的漂移这是正常的噪声。观察OLED屏幕应该能看到标题和电压值接近0V显示。5. 系统校准与精度提升实战未经校准的测量就像一把没有归零的尺子。校准是使你的数字电压表变得可信的关键一步。5.1 校准前的准备工作你需要一个已知精确的电压源作为基准。最佳选择是一个数字可调稳压电源并用一个精度较高的万用表最好是四位半的来监测其输出电压。如果没有稳压电源可以使用几节全新的、电压稳定的电池如CR2032纽扣电池标称3.0V 18650锂电池充满约4.2V作为基准点。5.2 分步校准流程我们采用“两点校准法”通常选择量程内的高点和低点如0V和接近满量程的一个点。零点校准将测量输入端正负极短接即输入0V。观察串口监视器输出的“测量电压”值。理想应为0.00V但可能有±0.0xV的偏移。如果偏移是稳定的例如总是0.05V我们可以在计算measuredVoltage的公式中减去这个偏移量。修改计算行float measuredVoltage voltageAtADC * voltageDividerRatio * calibrationFactor - voltageOffset;并在变量定义区添加float voltageOffset 0.05; // 根据实测调整。对于本项目由于分压器在0V输入时输出就是0V且ADC的零点通常很准这一步偏移可能很小可以忽略。满度或高点校准这是提高精度的核心。准备一个已知的、精确的输入电压Vin_known。不要直接用50V为了安全建议使用一个中等电压例如用万用表精确测量一个9V电池或电源输出的12.00V。将这个已知电压Vin_known比如12.00V连接到测量输入端。用你的高精度万用表同时测量这个电压记录下最精确的值例如V_real 12.05V。观察串口监视器你的程序会显示一个测量值V_measured比如11.8V。计算校准系数calibrationFactor V_real / V_measured。例如calibrationFactor 12.05 / 11.8 ≈ 1.021。回到代码中修改float calibrationFactor 1.00;这一行为你计算出的新值float calibrationFactor 1.021;。重新上传代码。验证校准效果再次输入相同的已知电压Vin_known观察串口输出和OLED显示。现在显示的数值应该非常接近万用表测得的V_real值了。可以换用另一个已知电压如5V进行验证看测量误差是否在可接受范围内例如±0.1V。实操心得校准的哲学校准的本质是用一个更高级的“标尺”这里指高精度万用表去修正我们自制的“标尺”。即使你的电阻精度只有5%经过软件校准后在校准点附近的测量精度可以非常高。但要注意校准效果在校准点附近最好离校准点越远误差可能略微增大。因此如果你的测量范围很宽如0-50V并且对全量程精度要求高可以采用“多点校准”甚至建立查找表。但对于大多数应用单点校准特别是接近常用电压点已经能带来质的提升。6. 项目测试、优化与扩展思路6.1 完整功能测试现在用你的Arduino电压表去测量各种直流电源吧测试电池测量AA电池约1.5V、9V方块电池、手机充电宝输出5V、18650锂电池3.7V-4.2V。对比万用表读数评估精度。测试电源适配器测量路由器、笔记本等设备的电源适配器输出电压注意极性。你会发现很多标称12V的适配器空载时可能高达14V。稳定性测试长时间监测一个电压源如USB口的5V观察读数是否稳定。如果跳动较大可以尝试增加readAverageAnalog函数中的平均次数比如从10次增加到50次但会降低刷新率。6.2 常见问题排查速查表现象可能原因排查步骤与解决方案OLED屏幕不亮/白屏电源接反或接触不良I2C地址错误。1. 检查VCC和GND是否接对、接牢。2. 尝试更换I2C地址将代码中SCREEN_ADDRESS改为0x3D。3. 运行一个简单的I2C扫描程序确认设备地址。屏幕显示乱码或部分显示库不兼容或初始化失败内存不足。1. 确认安装了正确版本的Adafruit SSD1306和GFX库。2. 检查初始化是否成功代码中已有判断。3. 尝试减小textSize或显示内容释放内存。测量值始终为0分压电路未接通信号线未连接代码引脚定义错误。1. 用万用表测量“信号输出点”对地是否有电压。2. 检查A0引脚连接线。3. 检查代码中voltageSensorPin是否为A0。测量值异常偏高或固定不动分压电阻接错比例错误ADC引脚损坏共地问题。1. 确认R1和R2阻值及连接顺序正确。2. 测量ADC引脚电压是否确实在0-5V之间。3.确保Arduino、OLED、被测电源三者的“地GND”可靠连接在一起这是最常见的问题。读数跳动剧烈电路噪声电源干扰未使用软件滤波。1. 在分压器输出端A0引脚与地之间并联一个0.1uF-10uF的电容可极大滤除高频噪声。2. 确保使用稳定的电源为Arduino供电。3. 增加软件中的平均采样次数。测量值有固定偏差未校准电阻精度差ADC参考电压不准。1. 执行前述的校准流程。2. 使用精度更高的金属膜电阻1%。3. 可以尝试使用Arduino内部1.1V基准如果测量小电压但需修改代码中的ADC_REFERENCE_VOLTAGE常量。6.3 项目优化与扩展方向这个基础项目可以作为一个模块融入更大的系统或者从以下几个方面进行优化量程自动切换通过程序判断当前电压若低于某个阈值如5V则自动切换到一个由继电器或模拟开关控制的不同分压比电路从而提高低压段的测量分辨率。数据记录与上传增加一个SD卡模块将电压和时间戳记录到文件中制作成一个简易的数据记录仪。或者添加Wi-Fi/蓝牙模块将数据发送到手机或云端服务器。增加过压报警功能在代码中设置阈值如电池过充电压当测量值超过阈值时让OLED屏幕闪烁、蜂鸣器报警甚至控制继电器切断电路。制作成独立设备将Arduino、分压电路、OLED屏集成到一个小盒子里用9V电池供电并安装香蕉插座或探针作为输入接口做成一个便携式的数字电压表。测量交流电压注意这涉及市电有生命危险仅限有充分安全知识和隔离设备的高级爱好者尝试。原理上需要先将交流通过变压器降压、整流桥整流成直流再用本电路测量其平均值并通过计算换算为有效值RMS。必须使用隔离变压器和光耦等进行严格的电气隔离。通过这个项目你不仅得到了一个可用的电压表更重要的是走完了从电路原理分析、参数计算、硬件搭建、软件编程到系统校准的完整电子开发生命周期。下一次当你需要测量任何不超过50V的直流电压时你完全可以信赖自己亲手打造的这件工具。

相关新闻