先交代一下我为什么折腾这个东西。做电子DIY这几年桌面上攒了一堆电容电阻电感大部分是拆机件标称值只能当参考。想测容值感值普通万用表只能测个大概稍微准一点的LCR电桥成品动辄几百上千对学生党来说确实肉疼。正好手头还有几片吃灰的STC89C51就盘算着能不能用51加上几颗常见运放自己做一台能测R、L、C三件套的测试仪顺便把阻抗测量原理彻底搞明白。这篇文章就是我整个从零设计、画板、写码到调试的记录包括关键参数计算、PCB布线时的取舍以及几个踩过的坑希望能给想动手做仪表的朋友少走点弯路。整机方案用的是很经典的“串联分压矢量计算”思路。信号源输出正弦波经过一个已知精度的采样电阻和被测元件串联然后同时测量元件上的电压、采样电阻上的电压以及两者之间的相位差单片机算出阻抗的模和幅角再分离出实部电阻和虚部电抗最后换算成R、L、C。这套办法对硬件要求不高51完全跑得动而且能顺带显示Q值、ESR这些参数可玩性比单纯测容值高不少。1. 设计思路与测量原理解析1.1 常见的RLC测量方案对比先说清楚为什么选这个方案。市面上LCR表常见的原理有三种电桥法、谐振法、伏安法。电桥法最经典通过调节已知电阻/电容让电桥平衡精度可以做得非常高但需要高精度可调参考元件自动平衡电桥还需要复杂反馈环路DIY成本不低。谐振法适合测高Q值器件通过扫频寻找谐振点对信号源频率稳定度和幅度稳定度要求苛刻测量范围也比较窄。伏安法就是给被测元件施加已知交流信号测它两端电压和流过它的电流通过二者关系算阻抗。这个方法电路结构直观对单片机算力要求低只需要准确测量两个电压幅度和一个相位差最适合51这种性能不算强的平台。我在伏安法里选了“串联分压”的变体采样电阻Rr和被测阻抗Zx串联电压源统一加在这条串联支路上。因为Rr已知电流的大小可以通过Rr的电压反推所以Zx的模值就是Rr乘以电压比。剩下的关键就是测相位差有了模值和相位角复数阻抗的实部、虚部就全部出来了。整体精度能达到什么水平呢我实测下来电阻误差在1%左右电容误差大约3%电感误差约5%跟廉价商品LCR表处于同一量级。这个精度对日常选料、判断元件好坏完全够了。1.2 阻抗参数的数学分解把被测元件看成复数阻抗 (Z_x R jX)其中R是等效串联电阻X是电抗。电抗为正时呈感性电抗为负时呈容性。测量时采样电阻Rr两端电压Ur和电流I同相被测件两端电压Uz与I的夹角就是阻抗角φ。于是有[ |Z_x| \frac{U_z}{U_r} \times R_r ][ \varphi 2\pi f \cdot \Delta t ]其中Δt是Uz与Ur两个正弦波之间的时间差也就是相位差换算成的时间。再通过三角函数分离[ R |Z_x| \cos\varphi ] [ X |Z_x| \sin\varphi ]之后根据X的正负和测试频率f换算若 (X 0)呈感性(L \dfrac{X}{2\pi f})若 (X 0)呈容性(C \dfrac{1}{2\pi f |X|})举个例子我用1kHz频率测一个标称100nF的电容如果算出来 (|Z_x| 1.61k\Omega)相位角 (-87.7^\circ)那么 (R 1.61k \times \cos(-87.7^\circ) \approx 64.6\Omega)(X 1.61k \times \sin(-87.7^\circ) \approx -1609\Omega)容值 (C \approx 98.9nF)。这就是整套软件计算的底层逻辑。需要注意这里默认使用串联等效模型。对电容来说ESR就是串联等效电阻R对电感来说绕线铜阻和高频损耗都归入R。实际测量小容量电容、大电阻时串联模型和并联模型差异明显软件里可以加一个串并联换算的选项后面第五节我再细说。2. 硬件电路设计与关键器件选型2.1 系统模块划分整机硬件可以分成六块正弦信号源、串联测量回路、真有效值转换、相位检测、主控与显示、电源。模块划分和主要器件如下表模块核心器件说明正弦信号源OP07 CD4066文氏桥振荡器输出100Hz/1kHz/10kHz三档串联测量回路高精度电阻阵列 继电器通过切换采样电阻改变量程真有效值转换AD736 × 2将Uz和Ur转换为直流电平ADC采样ADS111516位I2C接口ADC分时采集两路直流相位检测LM393 × 2将正弦波整形为方波送入单片机测沿差主控显示STC89C51 LCD1602控制量程切换、计算、显示这里有个容易被新手忽略的点STC89C51本身没有内置ADC所以必须外接。我选了ADS111516位分辨率I2C接口模块便宜而且精度够用。如果想省几块钱也可以换TLC1543但那是10位SPI接口读数跳动会明显一些测量分辨率下降不少。2.2 文氏桥正弦波发生器三档频率用CD4066切出来正弦信号源是整台仪器的“心脏”。一开始我想过用51产生PWM再滤波但STC89C51的PWM频率不高滤波后波形阶梯感明显失真会影响有效值测量精度。最后还是用了文氏桥振荡器电路简单、波形质量好而且运放用普通的OP07就能工作。文氏桥振荡器的正反馈网络由两个电阻和两个电容构成选频电路振荡频率由公式决定[ f \frac{1}{2\pi R C} ]我选 (R 16k\Omega)、(C 10nF)算出来[ f \frac{1}{2\pi \times 16k \times 10n} \approx 995Hz ]接近1kHz够用。为了实现多档测试频率我把电容做成了三组100nF对应100Hz10nF对应1kHz1nF对应10kHz用CD4066模拟开关切换公共端。这样电阻不用动只换电容频率切换就完成了。频率越高对DUT的电容小电感越敏感频率越低测大电容越有利。文氏桥起振后输出幅度容易漂必须在负反馈环路里加稳幅。最省事的方法是在反馈电阻两端并联两个反接的1N4148利用二极管导通电阻随幅度变化来压缩增益。这个方案会带来轻微削波失真但对AD736的真有效值测量影响不大实测下来比不加稳幅时稳定得多。一个关键心得是文氏桥的两个R要选同批次温漂小的金属膜电阻两个C也要配对否则振荡波形贪官——不会畸变——应该说波形会明显不对称直接影响相位测量。振荡器输出再经过一级OP07缓冲带载能力就够了。如果需要校准输出幅度可以在缓冲器反馈电阻里串一个10kΩ多圈电位器。2.3 串联测量回路与量程切换被测元件Zx和采样电阻Rr串联Rr的取值决定了不同量程。我设计了四档10Ω、1kΩ、100kΩ、10MΩ。为什么要分这么多档因为伏安法测量要求采样电阻和被测阻抗不能差太多。理想情况下两者同数量级这样Uz和Ur的电压都不至于太小或太大。如果被测元件是1Ω的小电阻你用10MΩ采样电阻那Uz只有总电压的千万分之一根本测不准反过来测10MΩ大电阻时用10Ω采样电阻电流太小Ur也测不到。判断量程是否合适的软件逻辑很简单读Uz和Ur如果Uz/Ur 8说明DUT阻抗比当前采样电阻大很多需要换更大一档如果Uz/Ur 0.125说明DUT阻抗太小需要换更小一档。程序会自动循环调整直到比值落在合理区间。档位切换我一开始想用CD4066模拟开关后来发现低阻档位根本没法用。CD4066的导通电阻大约几十到几百欧10Ω档的采样电阻都在这个量级开关自身电阻就把精度毁了。最终10Ω和1kΩ档用小型5V继电器切换100kΩ和10MΩ档用CD4066实际效果很好。继电器线圈驱动用ULN2003P1口输出高低电平控制线圈两端记得并续流二极管这个细节画PCB时必须注意。采样电阻本身是精度的根基必须用1%甚至0.1%精度的金属膜电阻。我实际用了0.1%的25ppm低温漂电阻成本也就几块钱一颗性价比很高。千万别用普通碳膜电阻温度一漂读数就跟着飘。2.4 真有效值转换与ADC采样有了Uz和Ur的交流电压还需要把它们变成单片机能够读取的直流电平。二极管整流加滤波是最省钱的方案但二极管压降非线性严重小信号下误差大对波形失真也敏感。我直接用AD736真有效值转换芯片输入交流输出直流直流电平就是有效值。AD736外围电路非常少输入侧用10μF电容隔直输出侧接一个低通电容用于平滑。它带宽足够覆盖100Hz到10kHz响应时间约10ms实际使用中等几十毫秒再读数比较稳妥。我做了两路AD736分别对应Uz和Ur输出经过CD4052多路开关送给ADS1115。ADS1115的PGA增益可以设置我用的是±4.096V量程16位分辨率下每个LSB约0.125mV对AD736输出的直流电平来说绰绰有余。它挂在STC89C51的P1.0SDA和P1.1SCL上用GPIO模拟I2C协议读取。模拟I2C在51上虽然慢一点但一次ADC转换也就几十毫秒整机刷新速度完全够用。读数稳定性方面我做了每通道连续采样16次去掉最大最小再平均ADC噪声基本能被压下去。2.5 相位差检测电路相位差是整个方案里最容易翻车的地方。我的做法是把Uz和Ur各自送入一个LM393比较器整形为同频方波再把两路方波接入51的外部中断INT0和INT1用定时器0测量两路上升沿的时间差。LM393本身是开漏输出要接上拉电阻。比较器输入端直接与正弦信号相连时如果信号在零电平附近有噪声输出会来回抖动导致计时错误。解决办法是加一点正反馈形成迟滞窗口我在比较器同相端和输出端之间接了一个1MΩ反馈电阻配合输入端的10kΩ电阻迟滞大约几十毫伏实测基本不会再误触发。比较器输出方波的上升沿才是单片机测量的关键。由于51的中断响应有延迟测出来的时间差会差几个微秒。在1kHz下这对应不到2度的相位误差可以接受10kHz误差会放大到约10度所以10kHz档更适合定性判断阻抗类型而不是追求精确的L值。如果后续想提高精度可以把过零比较后的方波经过RC低通变成占空比相关的直流电压再用ADC读取那个方案抗干扰更强但需要额外校准我没有在初版里做。2.6 整机电源方案整机使用单5V供电音频级运放需要负电源我加了ICL7660电荷泵产生-5V。电路总共需要5V数字、5V模拟、-5V模拟三路。数字和模拟的5V在入口处用电感或0Ω电阻分道避免数字噪声从电源串进模拟电路。电源滤波我在每个IC的电源引脚就近放了0.1μF陶瓷电容在总输入端放了一个470μF电解电容。ADS1115的参考电压直接吃模拟5V虽然不如独立基准精确但AD736输出的直流电平和ADC是共地的测量比值时参考误差会被抵消大半所以对最终精度影响不大。3. PCB布线关键点与实战布线图解析3.1 布局分区与地线处理PCB布线这部分其实比硬件设计更影响最终精度。我第一次画板就是随便布结果测小电感时读数乱跳后来重画才明白模拟电路和数字电路必须分区地线更要讲究。我的板子是双面1.6mm FR4整体布局从左到右大致是电源输入与ICL7660在左上角文氏桥振荡器在左中DUT测试端子在板子中上侧继电器和采样电阻阵列紧挨测试端子AD736和比较器在右侧STC89C51和LCD1602在右下。底层大范围铺地数字地和模拟地在电源入口处通过一个0Ω电阻单点汇合。为什么必须单点接地因为数字电路的电平跳变会在地线上产生高频噪声电流如果模拟地和数字地大面积直接连通这些噪声就顺着地平面窜进文氏桥和AD736最终体现为读数抖动。单点汇合后模拟电流和数字电流在地平面上的公共路径被缩短到最低。3.2 关键信号走线的具体约束以下几条走线我在布线图里做了严格处理你们画板时可以直接参考DUT端到继电器到采样电阻的走线这部分走的是整个测量回路的主信号走线要短、要粗建议至少40mil以上。走线电阻虽然只有几十毫欧但在测低阻值时会对10Ω档造成可感知的误差。文氏桥的RC网络R和C紧挨着运放摆放两个R对称、两个C对称避免走线长度不同带来寄生参数偏差。振荡输出到缓冲器的走线不要穿越数字区域。LM393输入线来自AD736前级的信号线属于高阻输入容易拾取干扰走线要短而且两侧尽量用地线包住。如果板子空间允许比较器输入位置可以加一个100Ω串联电阻配合对地电容做低通滤掉高频噪声。继电器控制线从ULN2003到继电器的驱动线是脉冲电流不能和模拟采样线平行走长距离否则开关瞬间会通过寄生电容耦合噪声。去耦电容每个IC电源脚旁的0.1μF电容必须紧靠芯片走线先过电容再到电源脚。ICL7660的飞跨电容C1和C2也要尽量靠近芯片否则负压输出纹波会变大。3.3 布线区域速查表下面是我画完布线图后的分区速查表方便在任何EDA工具里复现区域关键器件布线要点电源区5V输入、ICL7660、稳压电容走线短粗电容靠近IC振荡区OP07、R/C网络、CD4066对称布局远离数字线测量区DUT端子、继电器、采样电阻主回路走线短粗包地采样区AD736、CD4052、ADS1115输入滤波电容靠近芯片比较区LM393 × 2上拉电阻靠近输出脚数字区STC89C51、晶振、LCD晶振紧贴单片机铺地隔离实际打样后按这个布局做出来的板子模拟区几乎没有受到数字部分干扰。小信号测量时屏幕读数稳定只有最后一位偶尔跳动这对DIY来说完全能接受。4. 软件设计从51裸机到测量算法4.1 主程序框架与状态机软件部分用Keil C51开发整个程序围绕一个状态机转。主循环状态依次是量程选择、信号稳定等待、ADC采样、相位测量、参数计算、结果显示。状态机的好处是逻辑清晰方便以后扩展数据输出功能。主循环示意如下void main() { LCD_Init(); ADC_Init(); Timer0_Init(); EA 1; while (1) { Range_Select(); // 自动量程 Delay_ms(200); // 等待AD736输出稳定 uz Read_ADC(CH_UZ); // 读DUT电压对应的有效值 ur Read_ADC(CH_UR); // 读采样电阻电压对应的有效值 phase Measure_Phase(); // 测量相位差时间 Calc_RLC(uz, ur, phase); // 复数运算 Display_Result(); // 刷新LCD } }这个循环看起来简单但每个函数背后都有不少细节下面分节展开。4.2 自动量程的实现逻辑自动量程函数通过控制继电器的开关组合选择采样电阻。程序首先把档位置为1kΩ测一次Uz和Ur然后根据电压比值决定是否换挡。void Range_Select(void) { unsigned char range 2; // 默认1kΩ档 unsigned int ratio; do { Set_Range(range); Delay_ms(200); uz Read_ADC(CH_UZ); ur Read_ADC(CH_UR); ratio (unsigned int)(uz * 10 / (ur 1)); if (ratio 80 range 4) range; // 换更大采样电阻 else if (ratio 2 range 1) range--; // 换更小采样电阻 else break; // 档位合适 } while (1); }注意ratio这里放大了10倍来比较也就是Uz/Ur 8时切大档位Uz/Ur 0.2时切小档位。每次切换后必须延时200ms继电器机械动作需要时间而且触点稳定也需要几毫秒千万不要切完立刻采样否则会读到抖动期间的错误电压。低阻档位和高阻档位的采样电阻差了1000倍会导致信号源负载明显变化。实际中我遇到的问题是切换到10MΩ档时信号源经过高阻串联后AD736输入信号很小有效值转换可能不准确。所以10MΩ档主要用于粗略判断元件是否短路、开路精度比其他档位差一些这在软件说明里也标注了。4.3 相位差测量与代码实现相位差测量是整个软件里我最谨慎的部分。我用了两个外部中断INT0接Uz整形后的方波INT1接Ur整形后的方波。定时器0专门用来计时。具体测量思路是先等Uz上升沿触发INT0在中断里启动定时器0再等Ur上升沿触发INT1在中断里读取定时器0的值就是t1然后在下一个周期反向测一次等Ur上升沿触发INT1启动定时器0等Uz上升沿触发INT0停止并读取t2。void INT0_Isr() interrupt 0 { if (phase_state 0) { TH0 0; TL0 0; TR0 1; phase_state 1; } else if (phase_state 3) { t2 (TH0 * 256 TL0); TR0 0; phase_state 4; } } void INT1_Isr() interrupt 2 { if (phase_state 1) { t1 (TH0 * 256 TL0); TR0 0; phase_state 2; } else if (phase_state 2) { TH0 0; TL0 0; TR0 1; phase_state 3; } }定时器0工作在1T模式还是12T模式要提前想清楚。STC89C51工作在12T模式12MHz晶振下计数器每1μs加一。1kHz信号的周期是1000μs定时器16位最大值65535完全不会溢出。拿到t1和t2后比较大小确定超前滞后关系。如果t1 t2说明Uz上升沿先到也就是电压超前电流元件感性相位角取正φ 2π × t1 / T。如果t2 t1说明电流超前电压元件容性φ -2π × t2 / T。T是信号的周期计数值1kHz下等于1000。这个逻辑的前提是两个比较器、两条信号路径的传输延迟基本一致。实际中LM393的翻转速度、光耦如果用了会不一致但都在微秒量级对1kHz影响很小。如果换到10kHz档需要把周期计数换成100误差比例会明显上升所以10kHz档我更多用来做元件类别的粗略判断。4.4 参数计算与串并联换算计算函数把之前测到的Uz、Ur、t1/t2转成R、L、C并显示。STC89C51的浮点运算很慢但每秒刷新一两次还可以接受代码直接用了float。void Calc_RLC(unsigned int uz_adc, unsigned int ur_adc, unsigned int t1, unsigned int t2) { float uz_v, ur_v, z, phi, r_esr, x, freq; uz_v uz_adc * 4.096 / 32768.0; ur_v ur_adc * 4.096 / 32768.0; z sample_resistor * uz_v / (ur_v 0.001f); if (t1 t2) { phi 2 * 3.14159 * t1 / period_ticks; } else { phi -2 * 3.14159 * t2 / period_ticks; } r_esr z * cos(phi); x z * sin(phi); freq 1000.0f; if (x 0) { inductance x / (2 * 3.14159 * freq); capacitance 0; } else { capacitance 1.0f / (2 * 3.14159 * freq * (-x)); inductance 0; } }这个函数里的sample_resistor是当前量程电阻值period_ticks是当前频率下一个周期的定时器计数freq是当前测试频率三者在切换档位或频率时同步更新。关于串并联模型对小电容、大电阻直接使用串联模型会低估容值因为高阻并联分量影响变大。我在显示界面做了转换如果计算出的Q值小于0.05也就是X远大于R就按并联等效模型重新计算一份Cp和Rp显示。[ C_p \frac{C_s}{1 (1/Q)^2} ] [ R_p R_s \cdot (1 Q^2) ]这个功能对检测电解电容的漏电阻特别有用。实测一个470μF电解电容串联模型下ESR约0.3Ω、容值约465μF切换到并联模型后漏电阻显示为数十千欧一眼就能看出电容是不是老化了。4.5 校准与误差修正校准是整个DIY项目里最能提升精度的一步。我做了两类校准开路校准和短路校准。开路校准时DUT端子悬空这时仪器读到的不是真正的“零”而是电路板寄生电容、继电器触点电容、AD736失调等的综合影响记为Yopen。短路校准时DUT端子直接短接读到的Zshort包含测试线电阻、继电器接触电阻和寄生电感。实际测量时先用测量值减去短路阻抗做串联修正再用导纳减掉开路导纳做并联修正。这一步要在复数域做程序里维护两个校准复数变量计算时叠加。一个容易踩的坑是开路校准在10MΩ档做短路校准在10Ω档做两个校准条件下寄生参数的频率特性不同。所以校准必须按频率分别保存100Hz、1kHz、10kHz三组切换频率后自动加载对应的校准数据。我第一次没分开保存结果10kHz档读小电感偏差很大找了好久才发现是校准数据串档了。校准之后再用几个高精度电阻做两点校准修正AD736的非线性。我在程序里实现了简单的增益偏差修正系数测量已知电阻后反推修正值写入EEPROM这样每次开机就不用重新校准了。STC89C51虽然没有EEPROM但可以用程序存储区的IAP功能模拟实现起来不复杂。5. 实测、调试与避坑记录5.1 通电调试步骤整机焊好后不要急着插DUT测量按照“电源→振荡→比较器→ADC→整机”的顺序逐级检查。第一步检查电源上电后测5V、-5VICL7660输出应该在-5V附近纹波小于50mV。如果纹波大多半是飞跨电容离芯片太远。第二步看振荡器用示波器探文氏桥输出应该看到干净的正弦波幅度约1VRMS。如果不起振检查稳幅二极管是否焊反如果波形半边削顶稳幅二极管动作太早在反馈电阻上并联一个几百欧电阻降低增益。第三步看比较器两个比较器输出应该是频率一致、存在相位差的方波。用示波器双通道同时看把两个方波调到同一屏上应该能直接看出哪个超前哪个滞后。如果方波边缘有抖动说明迟滞电阻没起作用检查1MΩ反馈电阻和输入串联电阻是否接在正确位置。第四步看ADC在单片机程序里临时加一段直接把四路电压原始值打印到LCD的调试代码确认每路读数都随信号变化。如果读数一直为0大概率是模拟I2C地址不对或者SDA/SCL接反。5.2 实测数据对比下面是整机调试完成后用几个手上元件做的实测对比测试频率1kHz参考值是优利德UT61E万用表和一台朋友那借来的二手电桥给的被测元件标称/参考值本机实测相对误差金属膜电阻19.98kΩ10.02kΩ0.4%金属膜电阻247.5Ω47.8Ω0.6%CBB电容0.1μF0.098μF-2.0%瓷片电容10nF10.3nF3.0%电解电容470μF455μF-3.2%色环电感100μH104μH4.0%工字电感1mH0.96mH-4.0%从数据看电阻档最准因为两个AD736通道虽然各自有非线性但做比值时误差被抵消了一部分。电容和电感的误差主要来自相位测量和时间测量1kHz下几个微秒的误差就能带来好几度的相角偏差这基本就是精度瓶颈。关于读数跳动在测10nF小电容时读数偶尔有1到2个字跳动主要是因为测试线在桌面上移动导致寄生电容变化。DUT端子附近不要用手碰手靠近都会让读数明显变化。5.3 常见问题与排查速查现象可能原因处理方法开机LCD无显示对比度电位器没调好调LCD背面电位器到屏幕出现方块振荡器无输出运放供电异常或稳幅二极管反接测OP07电源脚核对二极管方向ADC读数恒为0I2C地址配置错误检查ADS1115的ADDR引脚接地配置相位测量剧烈跳动比较器迟滞不足增大反馈电阻/调整输入分压继电器切换后读数异常没有等待触点稳定延长切换后延时到200ms以上测电感值偏大没有扣除测试线寄生电感做短路校准在复数域扣除测电容值偏小没有扣除开路寄生电容做开路校准按频率分别保存10kHz档误差大中断响应延迟占比变大该档仅做定性判断或改用占空比测相位方案如果在实际调试中遇到“相位差计算出来始终是同一个方向”的情况先别怀疑硬件多半是判断超前滞后时t1和t2的符号搞反了把t1 t2和t1 t2的处理逻辑对调一下就行。最后再分享一个实际使用中的小技巧。DUT测试端子那两根线一定要短、要对称我用的是香蕉插座加双绞线做的开尔文夹夹子线靠得太近或者摆成一个大环测小电感时读数会随夹子位置变化而飘动。原因很简单测试线本身构成了一个可变电感也参与了测量。后来我把测试线固定长度、固定绞距再上机测试稳定性明显改善。这种细节看起来不起眼但对RLC测量来说比换一颗更高精度的采样电阻影响还大。从零开始做这台RLC测试仪我最大的体会是测量类仪器设计的核心并不在单片机有多强而在模拟链路的每一个环节是否被认真对待。文氏桥的波形质量、采样电阻的精度、比较器的迟滞、地线的回流路径任何一处偷懒都会直接展现在最终读数上。如果你照着这个方案画板复刻建议先不要追求一次成功分模块调试会更顺手。等这台入门款跑通了后续还可以加一键自动频率扫描、USB串口输出数据曲线甚至把换挡方式改成电子开关做全自动量程51的底子虽然老但把外围电路玩明白了一样能做出很有价值的工具。