简介:本资源面向电子类专业学生、单片机初学者及电机测试相关工程人员,提供一套基于51单片机与开尔文四线检测方式的电阻测量完整方案,重点解决电机绕组低阻值(约200毫欧)的精确测量问题。方案采用恒流源激励,测试电流0~50A可调,可由外部0~5V电压控制,并具备本地显示与数据上传功能,供电为AC220V,按键用于调整恒流源电流,不同电流对应误差大致在5%左右。压缩包共44个文件,约1016KB,包含C源码、头文件、Keil工程与HEX文件、Proteus仿真工程、原理图与PCB文档、流程图、元件清单表格及多张实物与截图,覆盖从电路设计到程序烧录的完整链路。目前已有184人学习下载。读者可据此复现仿真、理解开尔文测量原理、修改电机内阻参数并对照流程图梳理程序逻辑,适合课程设计、毕业设计或电机测试入门参考。
1. 开尔文四线制测电阻:为什么两根线测不准,四根线才能压到毫欧级
用普通万用表量一段铜线、一个采样电阻或者继电器触点,读数经常在几十毫欧到几百毫欧之间乱跳,你以为是表不准,其实多半是引线电阻和接触电阻在捣鬼。两根表笔的线阻、鳄鱼夹的接触电阻,加起来轻松超过 100 mΩ,而你要测的贴片采样电阻可能只有 10 mΩ,误差直接翻十倍。开尔文四线制就是冲着这个问题来的:把「流过电流的线」和「取电压的线」彻底分开,让电压采样回路几乎不流过电流,引线压降就不进入测量结果。这套方案用 51 单片机做主控,配合恒流源、差分放大和 ADC,再在 Proteus 里把原理图、流程图、仿真图跑通,最后落到 Keil 能编译的源代码,是一条从原理到仿真的完整链路。适合正在做电子测量课设、想搞懂四线制到底怎么落地、以及需要一份能直接复现的 51 单片机硬件设计的人。
2. 开尔文电路到底怎么消掉引线电阻:恒流源、四线接法和差分采样的分工
2.1 四线制消误差的物理本质
先把结论摆出来:开尔文测量的核心不是「更准的表」,而是「换一种接线拓扑」。两线制里,恒流源把电流 I 送进被测电阻 Rx,同时同一对线又去取 Rx 两端的电压。这对线上有引线电阻 r1、r2,实际测到的是 U = I·(Rx + r1 + r2),误差项 I·(r1+r2) 直接混进结果。
四线制把这根线拆成两组:一组叫电流线(Force),只负责把恒定电流灌进 Rx;另一组叫电压线(Sense),从 Rx 两端单独引出,接到高输入阻抗的差分放大器。因为差分输入阻抗通常在兆欧级,Sense 线上流过的电流只有纳安级,r1、r2 上的压降可以忽略,于是 U_sense ≈ I·Rx,引线电阻被物理隔离掉了。
这里有个容易被忽略的点:电压线必须接在 Rx 的焊盘内侧,也就是「电流线接点之内」。如果你把 Sense 线和 Force 线拧在同一个鳄鱼夹上,等于又变回两线制,开尔文就白做了。这是血泪经验,很多人仿真能过、实物翻车,就栽在这个接点上。
2.2 恒流源选型:为什么用运放加 MOS 而不是直接电阻分压
要测电阻,最稳的做法是「恒流测压」而不是「恒压测流」。恒流源让 I 固定,Rx 变化直接线性反映成电压,ADC 读起来简单,量程也好切。常见做法是用运放加一个调整管构成压控恒流源:
Vref ──► 运放同相端 运放输出 ──► MOS 栅极 MOS 源极 ──► 采样电阻 Rset ──► 地 MOS 源极 ──► 反馈回运放反相端 MOS 漏极 ──► 电流线 ──► Rx ──► 地运放强制 Rset 两端电压等于 Vref,于是 I = Vref / Rset,与 Rx 无关。选 Rset 时要注意功耗:如果 I 取 100 mA、Rset 取 10 Ω,Rset 上就耗 0.1 W,得用 1/4 W 以上的电阻,否则温漂会让恒流值慢慢跑偏。
对 51 单片机系统,恒流值一般取 10 mA 到 100 mA 之间。太小了 Sense 电压只有几百微伏,被噪声淹没;太大了 Rx 发热,阻值本身会变。我一般取 20 mA 配 100 Ω 量程,或者 100 mA 配 10 Ω 量程,用继电器或模拟开关切换 Rset。
2.3 差分放大与 ADC 量程匹配
Sense 电压进 ADC 前要放大。假设 I = 20 mA,Rx = 1 Ω,Sense 只有 20 mV,而 51 外挂的 ADC0809 或 TLC549 参考电压 5 V,直接读只有 1 个 LSB 的几十分之一,根本没法用。所以中间要加一级差分放大,增益取 50 到 100。
用 AD620 这类仪表放大器最省事,一个电阻 Rg 定增益:G = 1 + 49.4k / Rg。要 G = 100,Rg 取 499 Ω 左右。如果用普通运放搭三运放差分电路,注意四个电阻要配对到 0.1% 以内,否则共模抑制比会崩,读数随温度漂。
ADC 这边,51 单片机本身没有内置 ADC(STC12 系列有,但经典 8051 没有),常见做法是外挂 ADC0809 或 TLC549。ADC0809 是 8 位、8 通道,够用但分辨率只有 1/256;要测到毫欧级建议用 12 位的 TLC2543 或 ADS7816。参考电压用 TL431 稳到 2.5 V 或 4.096 V,比直接用 5 V 电源稳得多。
2.4 Proteus 里把恒流源和差分链路搭起来的最小步骤
在 Proteus 里复现这套电路,按下面顺序走,别一上来就全画完,容易连错:
第一步,放电源和地,加一个 DC 5V 给运放和单片机,再加一个 2.5V 参考给 ADC。
第二步,搭恒流源。运放选 LM358,MOS 选 IRF540,Rset 用 100 Ω,Vref 用一个电位器分压得到 2 V,这样 I = 20 mA。
第三步,放被测电阻 Rx,用 POT-HG 或 RES 都行,先设 1 Ω。电流线从 MOS 漏极接到 Rx 一端,Rx 另一端接地。
第四步,Sense 线从 Rx 两端引出,接 AD620 的 +IN 和 -IN,Rg 放 499 Ω,输出接 ADC 输入通道。
第五步,51 单片机最小系统:晶振 11.0592 MHz,复位电路 10 uF + 10 k,P0 口接 LCD1602 数据,P2 口接 ADC 控制线。
第六步,加 LCD1602 显示,RW 接地,RS、E 接 P2.0、P2.1。
搭完先别急着写代码,用 Proteus 的探针功能量一下 AD620 输出,确认 Rx = 1 Ω 时输出在 2 V 左右(20 mA × 1 Ω × 100 = 2 V),量程对上了再往下走。
3. 51 单片机侧的采样、换算与显示:从 ADC 读数到欧姆值的完整代码链路
3.1 ADC 驱动与采样时序
以 TLC549 为例,它是 8 位串行 ADC,三根线:CS、CLK、DATA。51 用软件模拟时序,注意 TLC549 要求 CS 拉低后先给一个时钟把前一次转换结果移出,再启动下一次。下面是最小驱动:
#include <reg52.h> #include <intrins.h> sbit CS = P2^2; sbit CLK = P2^3; sbit DOUT = P2^4; unsigned char adc_read(void) { unsigned char i, dat = 0; CS = 0; // 片选有效 _nop_(); for (i = 0; i < 8; i++) { // 移出上一次转换结果 CLK = 0; _nop_(); dat = (dat << 1) | DOUT; CLK = 1; // 上升沿移出 _nop_(); } CS = 1; // 拉高启动下一次转换 _nop_(); return dat; }逻辑说明:TLC549 在 CS 拉低后,每个 CLK 上升沿把数据移出,高位在前。循环 8 次得到一个字节。CS 拉高后芯片内部开始新的转换,下次调用时读到的就是新值。参数上,CLK 频率别超过 1.1 MHz,51 在 11.0592 MHz 下用nop() 延时刚好合适,太快会读到错位数据。
3.2 从 ADC 码值反推电阻值
设 ADC 参考电压 Vref = 2.5 V,8 位满量程 255,放大倍数 G = 100,恒流 I = 20 mA。ADC 码值 code 对应的 Sense 电压:
V_sense = code / 255 × Vref
再除以增益得到 Rx 两端真实压降:
V_Rx = V_sense / G
最后除以恒流得到电阻:
Rx = V_Rx / I = code × Vref / (255 × G × I)
代入数值:Rx = code × 2.5 / (255 × 100 × 0.02) = code × 2.5 / 510 ≈ code × 0.0049 Ω。
也就是说 code = 204 时 Rx ≈ 1 Ω。这个系数在代码里做成宏,换量程时只改 I 和 G 两个参数:
#define VREF 2.5f #define GAIN 100.0f #define I_CONST 0.02f float code_to_resistance(unsigned char code) { float v_sense = code / 255.0f * VREF; float v_rx = v_sense / GAIN; return v_rx / I_CONST; }注意用 float 而不是整数,51 上浮点慢但这里一次测量只算一次,不影响实时性。如果嫌慢,可以预先把系数算成定点数,用 long 乘再移位。
3.3 LCD1602 显示与量程自动切换
显示部分把欧姆值格式化成字符串,小于 1 Ω 显示毫欧,大于 1 Ω 显示欧姆:
void display_resistance(float r) { char buf[16]; if (r < 1.0f) sprintf(buf, "R=%.1f mOhm", r * 1000.0f); else sprintf(buf, "R=%.3f Ohm", r); lcd_show_string(0, 1, buf); }量程切换的思路:先按小电流测一次,如果 code 小于 20(信号太弱),切到大电流档再测;如果 code 大于 240(接近饱和),切回小电流档。切换靠 51 的 IO 控制继电器或 CD4051 模拟开关换 Rset。这里有个坑:切换瞬间恒流源会跳变,要延时 10 ms 等运放稳定再采样,否则读到的是过渡值。
3.4 流程图该怎么画才对应得上代码
流程图不是装饰,它要能一一对应代码分支。主流程是:初始化(LCD、ADC、IO)→ 选小量程 → 采样 → 判断 code 范围 → 超范围则切档重采 → 换算电阻 → 显示 → 延时 200 ms 循环。判断框画两个:code < 20 和 code > 240,分别指向「切大电流」和「切小电流」。这样画出来的流程图,别人照着就能把代码结构还原出来,而不是一张看不懂的框图。
4. 避坑与排查:仿真能跑、实物翻车的五个真实记录
4.1 现象:Proteus 仿真读数正常,焊出来偏差 30%
原因:仿真里导线电阻默认为 0,实物里杜邦线和鳄鱼夹的接触电阻真实存在,而 Sense 线接在了鳄鱼夹外侧,等于两线制。解决:把 Sense 线焊到 Rx 焊盘内侧,或者用四端开尔文夹,夹子内侧专门引出电压线。
4.2 现象:读数随温度缓慢漂移,半小时漂 5%
原因:Rset 采样电阻温漂大,普通碳膜电阻温度系数几百 ppm,恒流值跟着变。解决:Rset 换金属膜或康铜电阻,温度系数 50 ppm 以内;或者把 Rset 放到运放反馈环里,让运放强制其两端电压恒定,抵消一部分漂移。
4.3 现象:ADC 读数跳动十几个码,滤波也压不住
原因:恒流源和数字地共用一条地线,数字开关噪声串进模拟回路。解决:模拟地和数字地单点连接,ADC 和运放的地单独走线回到电源入口;ADC 参考电压加 0.1 uF 和 10 uF 去耦,紧贴芯片引脚。
4.4 现象:换量程后第一组数据总是错的
原因:继电器或模拟开关切换后,恒流源环路和 AD620 输入电容需要建立时间,代码里没延时直接采样。解决:切换后加 10 到 20 ms 延时,或者连续采样三次丢弃第一次,取后两次平均。
4.5 现象:小电阻测出来是负值
原因:AD620 的失调电压没调零,增益 100 倍后失调被放大,Rx 很小时 Sense 电压比失调还小。解决:AD620 的 5 脚加调零电位器,或者软件里先短接 Rx 采一次零点,后续测量减去这个偏移。软件调零更省事,但要注意零点也会随温度漂,最好每次上电或每隔几分钟重采一次。
5. 把精度再压一档:软件调零、多点校准和 51 上的定点优化
仿真跑通只是及格线,真要把毫欧级测稳,还得在软件上做两件事:调零和校准。上电时先把恒流源关掉或者把 Sense 输入短接,采 16 次取平均作为零点 offset,之后每次测量都减去它。这一步能消掉运放失调和 ADC 零点误差,成本几乎为零。
多点校准更狠一点:拿三个已知精密电阻(比如 0.1 Ω、1 Ω、10 Ω)各测一遍,记录 code 值,用最小二乘拟合出斜率和截距,把 code_to_resistance 里的固定系数换成拟合结果。这样连恒流值的绝对误差都能一起修掉,因为校准吸收了整个链路的增益误差。我一般用两点校准就够,三点更稳但费时间。
51 上跑浮点确实慢,一次换算大概几百微秒,对 200 ms 的刷新周期无所谓。但如果你想做快速扫描或者多通道轮询,可以把公式改成定点:Rx_mohm = code × K >> 10,K 是预先算好的整数系数,用 long 乘法加移位,速度能快十倍以上。K 的算法是把 0.0049 × 1000 × 1024 取整,得到 5020 左右,具体值按你的 Vref、G、I 重算。
最后一个习惯:每次改完硬件或换量程,先用一个已知电阻验证,别直接信读数。我吃过亏,量程切换代码写错,把 100 Ω 的电阻显示成 1 Ω,还以为是电阻坏了,查了一下午才发现是 Rset 切换的 IO 口定义反了。希望帮到你。
本文还有配套的精品资源,点击获取