简介:这套设计面向STM32与嵌入式硬件开发者,提供基于STM32F103C8T6的自动量程转换数字电压表完整工程,解决0~200V直流电压多量程自动切换的硬件设计问题。资源共424个文件,包含Altium Designer的原理图、PCB设计文件(schdoc、pcbdoc)以及配套的pcblib、schlib封装库,还有设计规则检查报告(drc、html)和ECO日志等,便于查核设计流程,整体约490.55MB。已有6963人学习浏览。工程内已生成原理图库和PCB库,可直接复用;功能上覆盖200mV/2V/20V/200V四挡自动量程、OLED显示、超量程报警与复位按键,此外还附有设计调整说明,例如蜂鸣器电路建议由NPN改为PNP型,并注明当前仅验证到32V。这套设计可作为课程设计、毕业设计或电子竞赛的参考方案,帮助快速完成电压表硬件平台搭建与调试。 做这个小项目的时候,我其实是被手头那几块万用表逼的——测量不同电压档位时要反复拧旋钮,测个锂电池电压还要先猜个大概范围。想着反正手上有STM32最小系统板,干脆自己做一个能自动切换量程的数字电压表,顺便把原理图和PCB从头到尾走一遍。这个项目说到底就是:用STM32的ADC去读电压,通过继电器或模拟开关切换不同的分压比,让ADC永远工作在接近满量程的区间,从而提高测量精度。
整个项目做下来,最难的不是代码,而是模拟前端的分压网络设计和PCB布局布线。数字电路部分哪怕乱一点,功能基本还能跑;但模拟信号链路一不注意,测出来的数值就飘,或者小信号被噪声吃掉。这篇文章我会完整梳理从方案选型、原理图设计到PCB Layout、再到调试实测的整个流程,把关键参数的计算、元件选型逻辑和踩过的坑都交代清楚,希望能给想自己做仪器的朋友一点参考。
1. 项目整体设计与方案选型
1.1 为什么用STM32F103C8T6
做自动量程电压表,主控的选择其实很多:老牌51、PIC、AVR都可以,甚至纯模拟电路加比较器也能实现自动换挡。但用STM32F103C8T6有一个实打实的好处——片上自带12位ADC,采样速度最高能到1MHz,而且有多路通道,可以同时监控输入电压和分压后的电压。12位分辨率在3.3V参考电压下,理论分辨率约0.8mV,虽然比不上台式万用表的16位、24位ADC,但配合自动量程,做到三位半显示的精度绰绰有余。
另一个原因是成本和外设资源。F103C8T6在市面上价格很透明,而且有大量现成的库函数和例程可参考,调通一个ADC采集加GPIO控制,基本半天就够。它还带硬件SPI和I2C,如果后续想加OLED显示屏或者SD卡存储,直接就能用,不用再换主控。
选型时我还考虑过APM32这类国产替代芯片,实际测试过APM32F103C8T6可以直接跑STM32的工程,引脚兼容、寄存器兼容,点灯和ADC都没问题。但为了稳妥,PCB上我按STM32F103C8T6的封装来画,这样两种芯片都能焊上去用。
1.2 自动量程的实现方案:继电器还是模拟开关
量程切换的本质是改变输入信号的分压比。常用的方案有三种:
- 机械继电器切换:接触电阻小、通道隔离好、耐压高,缺点是体积大、切换慢、有寿命限制。适合测量高压或者追求信号完整性的场景。
- 模拟开关(如CD4051、DG408):切换速度快、体积小、无机械寿命问题,但存在导通电阻(几十欧姆)和漏电流,小信号测量时需要考虑影响。
- 数字电位器:可以实现连续量程,但精度受限于电位器的分辨率,而且耐压一般,不适合高压输入。
我最终选的是模拟开关+分压电阻网络的组合。原因很简单:这个项目的量程设计为±50V,模拟开关的导通电阻虽然存在,但分压电阻网络的阻值选得足够大(比如1MΩ级别),导通电阻(几十欧姆)相对分压电阻可以忽略不计,误差可以控制在0.01%以内。至于漏电流,选型号时注意选低漏电的CMOS模拟开关,比如DG408的最大漏电流在室温下是纳安级,对分压网络的影响微乎其微。
从成本角度讲,一个DG408(8通道模拟开关)比两个继电器便宜,而且能减少PCB面积,这对后续做手持设备很有帮助。
1.3 量程划分与分压网络设计
自动量程的核心是分压网络。我规划的测量范围是0-50V,分为三个固定档加一个直通档:
| 量程 | 输入范围 | 分压比 | 匹配电阻方案 |
|---|---|---|---|
| 档位1 | 0-5V | 1:1(直通) | 无需分压,直接进运放 |
| 档位2 | 0-20V | 1:4 | 1MΩ + 200kΩ分压,取200kΩ两端 |
| 档位3 | 0-50V | 1:10 | 1MΩ + 100kΩ分压,取100kΩ两端 |
分压电阻取值的原则是:等效输入阻抗要足够大,避免影响被测电路。1MΩ级别的输入阻抗对绝大多数电路来说都可以当作开路处理,但这个阻值会带来一个新的问题——后端ADC的输入阻抗不够高,直接接分压点会拉低电压,所以必须加电压跟随器做缓冲。
我在分压网络和ADC之间加了一级运放跟随器,用的是LMV358(轨到轨输出,单电源3.3V供电)。为什么不用LM358?因为LM358的输出摆幅到不了电源轨,3.3V供电时最高只能输出到约2.2V,这会压缩ADC的测量范围。而LMV358可以输出接近3.3V,这样才能充分利用12位ADC的满量程。
这里有个细节:分压电阻用了0.1%精度的精密电阻(1206封装,1MΩ和100kΩ),温漂系数25ppm/℃。如果只用普通的5%贴片电阻,分压比的误差会直接叠加到测量结果上,校准起来很麻烦。精密电阻单价虽然贵一点,但整板下来也就多几块钱,比起后期逐台校准的人工成本,完全是值得的。
1.4 保护电路:不能省的输入端防护
做电压表,输入端保护是重中之重。我见过不少DIY项目没加保护,一个不小心接到高压上,主控直接烧穿。这套设计里我加了三级保护:
第一级:自恢复保险丝(PPTC)。选用300mA、60V规格,串联在输入端。过流时保险丝阻抗增大,限制电流,故障排除后自动恢复。
第二级:TVS管。选用SMBJ24A(截至电压24V),跨接在输入端和地之间。TVS能吸收瞬态高压脉冲,把电压钳位在安全范围,防止静电放电或者误接高压造成永久损坏。
第三级:串联限流电阻。在保护电路和分压网络之间串一个10kΩ电阻,配合TVS管限制故障时流过TVS的电流,防止TVS本身过流烧毁。
这套保护的思路是:正常情况下不影响测量精度,异常情况下把损害控制在可更换的元件上,而不是直接烧主控。实际测试中,我故意短接过一次24V电源,只有保险丝和TVS受到了冲击,主控和ADC安然无恙。
2. 原理图设计详解
2.1 最小系统:晶振、复位、Boot引脚
STM32F103C8T6的最小系统网上资料很多,但有两个点我特别想强调:
晶振的负载电容计算。F103通常用8MHz晶振作为HSE时钟源,负载电容的取值要根据晶振厂商的数据手册来定,一般常见值是12-22pF。计算公式是:
CL = (C1 × C2) / (C1 + C2) + Cstray
其中Cstray是PCB走线和引脚引入的寄生电容,通常在3-6pF左右。假设目标负载电容CL=12pF,Cstray取5pF,C1和C2取相同值,则:
C1 = C2 = 2 × (CL - Cstray) = 2 × (12 - 5) = 14pF
实际焊装时我用了15pF,和计算值接近。如果电容值选得偏大或偏小,晶振可能起振困难或者频率偏差,表现就是程序跑着跑着时序不对。值得注意的是,如果直接使用内部RC振荡器(HSI),可以省掉晶振和电容,但内部RC的精度只有1%左右,做USB通信或者高精度时间基准会不够用,电压表这种应用对时间精度要求不高,要省成本也可以考虑。
复位电路。STM32的NRST引脚是低电平复位,典型接法是10kΩ上拉电阻加100nF下拉电容到地。这个RC时间常数约1ms,能够保证上电时复位信号稳定。有朋友直接用0欧导线把NRST接到高电平,虽然芯片也能跑,但偶尔会遇到上电时序不稳定导致的启动失败,尤其在做ADC采样时,复位不干净会带来第一次采样结果错误。
2.2 电源树设计:模拟和数字降压
整个板子的供电从USB的5V进来,经过AMS1117-3.3稳压到3.3V给主控和模拟电路使用。这里我犯过一个错误:一开始直接把USB 5V接到AMS1117输入,输出端只加了一个10μF钽电容,结果ADC采样值波动明显。后来在AMS1117的输出端并了一个0.1μF陶瓷电容和10μF钽电容,同时在输入端也加了10μF电容,纹波才降下来。
更关键的是,模拟部分(运放、参考电压)和数字部分(STM32)的3.3V电源要在PCB上做分割,通过0欧电阻单点连接。这样做的目的是防止数字电路的开关噪声通过电源平面耦合到模拟电路里。电源树结构如下:
USB 5V → 保险丝 → 稳压前滤波(100μF电解 + 0.1μF陶瓷) → AMS1117-3.3 → 3.3V数字(STM32供电) → 0欧电阻 → 3.3V模拟(运放、参考)当然,AMS1117的压差是1.1V,输入最低需要4.4V才能稳定输出3.3V,如果电源来自锂电池,电压可能跌到3.7V以下,这时AMS1117会失去稳压能力。如果后续要做电池供电版本,最好换成LDO(低压差线性稳压器),比如RT9013或XC6206系列,压差只有几十毫伏。
2.3 参考电压:决定精度的源头
STM32的内部参考电压(VREFINT)虽然使用方便,但它的初始精度只有±2%左右,温漂也明显,做高精度电压表不太够用。我选择外接一个2.5V的基准电压源——TL431,通过电阻分压得到精准的参考电压。
外接基准源的方式是:TL431输出2.5V,再经过一个精密电阻分压器获得1.65V作为ADC参考电压(VREF+引脚)。这样ADC的满量程对应1.65V,配合分压网络,可以精确计算输入电压。
什么情况可以用内部参考?如果你只做3位显示、精度要求不高、且环境温度变化不大,内部参考完全够用。但如果你希望达到0.5%以上的电压测量精度,建议认真考虑外部基准。
2.4 ADC输入链路:运放跟随器和RC滤波
从分压网络出来的电压(0-1.65V范围),经过运放跟随器缓冲后,还需要一级RC低通滤波再进ADC引脚。RC滤波参数的选择有讲究:
ADC输入端的等效电容(采样电容)大约是几pF到十几pF,如果信号源阻抗过高,采样瞬间会造成电压跌落,影响转换精度。STM32的数据手册建议:当ADC采样时间为1.5个时钟周期时,信号源阻抗不应超过约1.2kΩ;使用最长采样时间239.5个时钟周期时,允许信号源阻抗高达约50kΩ。所以我用了一个折中的方案:运放输出串联330Ω电阻,再接一个10nF电容到地,组成截止频率约为48kHz的低通滤波器,同时给ADC提供较低的信号源阻抗。这个截止频率远高于50Hz工频和其谐波,又能滤除大部分高频毛刺。
这里有个矛盾点:如果截止频率设太低,会把有用信号的高频成分滤掉,造成大电压跳变时ADC读数建立时间变长;如果设太高,又起不到滤波作用。我实测后,选择330Ω+10nF,建立时间约3.3μs,与ADC采样周期完美配合,读数稳定且响应快。
3. PCB布局与布线要点
3.1 板框与布局规划
PCB尺寸我定的是5cm×3cm的两层板。为什么这么小?因为目标是用作手持万用表的核心测量模块,而不是桌面仪器。双面板完全足够——底层做完整地平面,顶层走信号和电源。
布局顺序很关键:先布置模拟链路,再布数字部分,接口放板边。输入端(香蕉插头或接线端子)放在板子左侧,分压网络紧靠输入端,运放跟随器紧随其后,ADC引脚和主控放在板子右侧。这样信号流向清晰,从左到右依次经过保护电路→分压→缓冲→ADC,避免信号在板上绕来绕去。
地平面的完整性是个大学问。我踩过一个坑:在一版PCB中,为了走线方便,把底层的地平面挖断了好几处,结果ADC读数在测量小电压(比如几十毫伏)时跳动非常厉害。后来重新布线,保证底层地平面连续完整,只有必要的过孔打断,噪声明显改善。地平面就像信号的地基,地基不稳,上面的信号必然歪七扭八。
3.2 关键走线:模拟信号线、电源线、晶振走线
模拟信号线:从输入端到ADC引脚,这条路径上的线尽可能短、直,线宽不低于0.3mm(12mil),铺地包裹两侧。分压电阻和运放之间不要走数字信号线。
电源线:3.3V主干道走1mm宽,模拟数字共用点通过0欧电阻连接,模拟3.3V区域走0.5mm线宽。USB 5V进入后走1.5mm宽,尤其注意AMS1117的散热(它在这个设计里功耗不大,不需要大铜箔散热,但焊盘要开大孔方便焊接)。
晶振走线:晶振的两个引脚之间走线要尽量短,且不能有其它信号线穿过。晶振正下方不铺地(防止寄生电容),周围用地线围一圈,形成保护环。之前我在晶振下面铺了地平面,导致实际振荡频率偏了约0.3%,虽然程序没崩溃,但通信时序实测有偏差。
过孔数量:地平面上的过孔不是越多越好,但关键位置(模拟信号线的侧面、电源转换点)要打过孔连接顶层地上的旁路电容。过多过孔反而会割裂地平面,增加地阻抗。
3.3 铺铜与地平面分割
前面提到模拟和数字电源通过0欧电阻连接,那么PCB上的地平面是否也要分割?我的建议是:不分割地平面。如果你把模拟地和数字地物理分开,再在某一点连接,那个连接点很容易变成天线,反而引入更多噪声。我采用整块完整地平面,但通过元件布局来区分模拟区域和数字区域——模拟元件集中在左侧,数字元件在右侧,模拟信号不跨越数字区域,数字信号也不进入模拟区域。规则是:让回流电流路最短,模拟信号的回路电流不会经过数字电路区域。
在江科大等教学资料里,常能看到"模拟地数字地单点连接"的做法,但在两层板上实施时极易出错。最简单可靠的方式就是完整地平面加合理布局。
3.4 PCB走线规则速查
做过几版PCB后,我总结了一套自用的走线规则,很多来自实际操作中的教训,分享给你:
- 最小线宽:信号线0.3mm,电源线1mm,地线尽量铺铜不单独走线。
- 安全间距:信号线与信号线至少0.3mm,电源与地间距至少0.5mm,高压区域(输入端)与其他线路间距至少1mm。
- 差分信号:项目未用差分信号,但需要注意若未来扩展通信接口,差分走线要等长、紧耦合。
- 晶振走线:要短,且加地保护环,不与其他信号线平行敷设。
- 模拟信号过孔:尽量少过孔,一个过孔约增加0.5nH寄生电感,高频时压降明显。
- 丝印:电源正负极、量程档位、测试点标注清楚,方便后期调试。
打样回来后,用万用表测一下3.3V对地电阻,确认没有短路再焊主控。上电时先不焊主控,只焊电源部分,测输出电压正常后再焊核心芯片和模拟部分,这是DIY项目减少排故时间的基本操作。
4. 固件与自动量程控制逻辑
4.1 自动量程切换的状态机
有了硬件之后,软件的自动量程逻辑其实不难,核心是一个简单的状态机:
- 上电初始化:默认切到最大量程(1:10分压),防止上电瞬间被测电压过大损坏ADC。
- 首次采样:读ADC值,计算当前量程下的电压。
- 档位判断:
- 当前电压小于当前档位满量程的10%时,降档(切换到更小分压比),以提高小信号的分辨率。
- 当前电压大于当前档位满量程的90%时,升档(切换到更大分压比),防止ADC饱和。
- 如果ADC读数接近满量程(如超过4095×0.995),说明可能超过当前量程范围,立即切换到更高档位。
- 回滞区间设计:避免在临界点频繁切换,比如同一个电压在档位边缘时,上升和下降的切换阈值要错开。例如10%降档、12%升档的滞回窗口。实际经验是:滞回窗口设得偏大,档位切换稳定;设偏小,数码管会频繁闪跳。
- 切换延迟:切换量程后,等待5ms让分压网络和运放稳定,再做滤波采样,防止毛刺误判。
4.2 采样滤波与校准
STM32的12位ADC单次采样结果本身就带有一定的噪声,如果直接显示,最后一位会乱跳。我用的是"中值滤波+滑动平均"的组合:先取5次ADC原始值排序,取中间3个值做算术平均,再放入环形缓冲区做16点滑动平均。实测下来,显示稳定性肉眼可见地提高,最后一位不再闪烁。
校准环节我做了一个最简单的两点校准:用一个精准的直流源分别给5V和20V输入,记录ADC读数与实际电压的关系,拟合出ADC值到电压的线性变换。由于分压电阻精度较高,线性度很好,两点校准就够用。
这段经验特别值得分享:不要盲目相信ADC的VREF就是3.3V。实际板上AMS1117输出的3.3V和TL431基准的输出电压会有一定偏差,直接用理论公式计算会引入误差。通过软件校准,相当于把系统误差一次性补偿掉。我这边实际测出来的3.3V是3.312V,和标称差了0.36%,如果不校准,最终显示会明显偏高。
4.3 OLED显示与按键交互
板子上预留了OLED(I2C接口,SSD1306驱动)的排针位置,显示内容包含当前电压值、当前量程档位、以及ADC原始值(调试用)。电源键和量程手动切换键通过板载按键实现,长按1秒锁定当前档位,避免抖动,再长按恢复自动模式。
显示刷新率方面,我设置了10Hz的刷新率,同时每1秒完整更新一次主界面。10Hz刷新能满足日常观察需求,全程跑在最高刷新率并没有必要,反而可能导致OLED闪烁和功耗上升。
5. 实测数据与常见问题排查实录
5.1 与台式万用表对比测试
整机调通后,我用实验室的台式万用表(精度0.05%)作为基准,输入一组电压做了对比测试:
| 输入电压(台式表) | 本机读数 | 误差 | 当前量程 |
|---|---|---|---|
| 1.000V | 1.001V | +0.1% | 0-5V |
| 3.300V | 3.296V | -0.12% | 0-5V |
| 9.500V | 9.506V | +0.06% | 0-20V |
| 15.200V | 15.213V | +0.09% | 0-20V |
| 30.500V | 30.459V | -0.13% | 0-50V |
| 48.000V | 48.118V | +0.25% | 0-50V |
全量程误差控制在±0.25%以内,对三位半显示的DIY仪表来说,这个结果已经算不错了。误差主要来源是分压电阻的残余温漂和参考电压的温漂,想要进一步提升,就得换更高精度的电阻和基准源了。
5.2 典型问题排查记录的完整过程
这里记几个我调试时遇到的问题和排查思路:
问题一:ADC读数持续偏高约0.15V
排查过程:开始以为是分压电阻精度不够,但用万用表量分压点的电压是准的。接着查运放跟随器输出,发现输出电压比分压点高了约0.15V,低于电源轨,排除了饱和问题。查数据手册发现LMV358的输入失调电压(Vos)最大6mV,不至于产生这么大的偏差。
继续排查,发现运放输出直接接了3.3V电源(我用的是双电源方案,但板子上只接了单电源),运放正输入端的偏置电流没有泄放回路,导致输入电位被抬高。解决方法:在运放正输入端并联一个1MΩ电阻到地,给偏置电流提供回路。焊上这个电阻后,偏差消失。
问题二:档位切换瞬间显示跳动
模拟开关切换时,通道间的电容耦合会产生短暂的毛刺,如果程序在切换后立刻采样,会采到毛刺值。解决方法是:切换通道后延时5ms再做滤波,同时在模拟开关输出端加了一个100pF的电容,进一步吸收毛刺。另外我把滤波缓冲区清空后再重新填充,避免旧数据污染新读数。
问题三:小信号测量时读数不稳定
当输入电压只有几十毫伏时,读数跳得厉害。用示波器观察发现,输入端拾取到了约5mV的50Hz工频噪声。排查发现是PCB上输入端与数字地之间的寄生电容耦合所致。解决方法是:在输入端与模拟地之间加一个100nF电容直接旁路高频噪声,同时把分压网络的节点尽量远离数字区域。整改后,小信号稳定性明显改善。
问题四:上电后偶发程序跑飞
这个问题比较隐蔽,一开始怀疑是程序问题,后来用示波器查复位引脚,发现上电瞬间NRST引脚有毛刺,且3.3V电源上升沿很缓,导致主控在电压没稳定时就启动了。解决方法是:在3.3V输出端与地之间加上电复位延时电路(RC延时约100ms),确保待电源稳定后再启动主控。这其实和常规MCU应用中"电源监控复位"的思路一致。
5.3 一些焊接和调试的实操建议
焊接方面,STM32F103C8T6是LQFP48封装,0.5mm脚距,对新手来说不算难,但要注意焊盘对齐。如果担心焊接质量,可以先在PCB上刷一层薄薄的助焊剂,再放芯片,用拖焊法处理引脚。焊完后用放大镜检查引脚间是否有桥连,尤其是电源引脚和相邻引脚之间的短路。
调试时,我习惯先把电源部分、最小系统、ADC采样部分分开独立调试,最后再整体联调。具体顺序是:
- 焊电源部分,上电量3.3V、1.65V参考电压是否正常。
- 焊主控最小系统,刷一个LED闪烁程序验证系统时钟和复位正常。
- 焊运放跟随器,短接输入,测跟随器输出是否为0V。
- 焊分压网络和模拟开关,逐档验证分压比是否正确。
- 刷主程序,接入测试电源,逐步校准。
每次只改动一个环节,出现问题时能快速定位,是保证项目一次成功的法宝。
6. 后续扩展方向
项目核心已经跑通,如果还想继续玩下去,有几个方向可以做:一是换高分辨率ADC(如ADS1256,24位),把测量精度提升一个档次;二是加蓝牙模块把数据传到手机,做个简单的数据记录仪;三是重新做四层板,把模拟电源层和数字电源层分开,进一步降低噪声;四是设计成锂电池供电的手持设备,配合橡胶保护套。
我个人觉得最有意思的是加蓝牙模块——不用开电脑,手机上随时看电压波形,测电池放电曲线就方便多了。这个扩展在现有PCB上只需要预留UART排针就能实现。
做过这个项目后,我最大的体会是:仪表类项目,模拟前端和PCB设计决定精度上限,软件只做锦上添花。如果哪天做出来的电压表读数不准,别急着调代码,先去摸一摸分压电阻是否够精密、地平面是否完整、参考电压是否稳定。这些硬件层面的问题,靠写代码是绕不过去的。希望这篇文章能帮你在做自动量程电压表的路上少走几个弯路。
本文还有配套的精品资源,点击获取