做校准仪器和工业控制这块的人,多半都遇到过同一个尴尬:机械电位器拧了几百次之后开始接触不良,或者一个批次的电位器阻值离散到让你怀疑人生。后来我转向数字电位器,也就是可编程电阻,把“拧”这个动作变成了 SPI 写寄存器,一套系统下来,既省了面板空间,又让产线能自动跑校准流程。这篇想聊的是我用 AD5293BRUZ-20-RL7 这颗 20 kΩ 可编程电阻,搭配 PIC18LF46K42 单片机,在校准和工业应用里控制电阻值的整套思路。包括选型时怎么读参数、硬件上容易踩的坑、固件里电阻码怎么换算,以及最后现场调试时会遇到的漂移和干扰问题,适合正在做仪器仪表、ATE、老化测试和传感器模拟设备的工程师参考。
1. 校准和工业装置里,真正需要的是“能远程设置的电阻”
1.1 从一个实际调试场景说起
有次做一台多通道温度采集板的校准工装,需要模拟 PT100 热电阻在不同温度下的阻值。PT100 在 0°C 时正好 100 Ω,100°C 时大约 138.5 Ω,精度要求到 0.1 Ω 级别。最开始我用了精密绕线电阻加继电器切换,一块板子上堆了十几个继电器,体积大不说,切换瞬间还有触点抖动,采样板的分辨率又高,愣是把抖动全采进去了。
后来换成数字电位器方案,主控通过 SPI 直接把电阻值设过去,整个过程没有机械触点,重复性好,校准序列也能脚本化。那时我才意识到,所谓“可编程电阻”,本质就是把“电阻箱”变成“寄存器”,让你的软件可以在毫秒级内改变一个模拟节点的等效电阻,而且这个过程可以重复十万次都不带磨损的。
AD5293BRUZ-20-RL7 就是这个思路里的核心执行元件。后缀里的 -20 代表端到端电阻 20 kΩ,BRUZ 表示 TSSOP 封装,RL7 是卷带包装,适合量产贴片。1024 位的分辨率配合 ±1% 的端到端电阻精度,在校准级别应用里非常有吸引力。
1.2 三种可编程电阻形态的取舍
很多初学者会问,想实现“软件调电阻”,是不是只能买数字电位器?其实市面上有三类做法:
- 继电器切换精密电阻阵列:精度高、功率大,但体积大、速度慢、有机械寿命限制。
- 步进电机带着电刷滑电阻丝:噪声大,控制麻烦,适合大功率场合。
- 数字电位器(DigiPOT):体积小、无触点、速度快,适合小信号、低功率场景,但需要注意 wiper 电阻和电压范围限制。
数字电位器也不是没有缺点。它内部本质上是一串多晶硅电阻加上 MOS 开关,信号通路上会引入一定的导通电阻、电容和噪声。所以选型时不能只盯着“多少位分辨率”看,还要看端到端容差、wiper 导通电阻、温度系数、供电范围和逻辑接口电平。这些参数里任何一个没选对,到了现场调试都会变成棘手的难题。
2. AD5293 这颗料先看透:20 kΩ、1024 步、±1% 和那点 wiper 电阻
2.1 基本参数和它适合的电路位置
AD5293 是 ADI 的数字电位器系列里比较“讲究”的一颗,分辨率做到 1024 位,也就是 10 bit,端到端电阻可选 20 kΩ、50 kΩ 和 100 kΩ。我用的这颗 20 kΩ 版本,是因为在传感器模拟应用里,20 kΩ 配 1 kΩ 到 10 kΩ 级别的分压网络比较合适,功耗和噪声都能接受。
几个关键参数我做了个表格,方便快速对照:
| 参数 | 典型值/范围 | 说明 |
|---|---|---|
| 端到端电阻 R_AB | 20 kΩ | 型号 -20 对应 20 kΩ,另有 50 kΩ、100 kΩ |
| 分辨率 | 1024 位 | 对应 10 bit DAC 一样的抽头细分 |
| 端到端容差 | ±1% | 比普通数字电位器常见的 ±20% 好很多 |
| 工作电压 | VDD-VSS:5 V 至 30 V | 可使用单电源或 ±15 V 双电源 |
| 逻辑接口 | SPI 兼容 | 最高时钟可达数十 MHz 级 |
| 封装 | 14 引脚 TSSOP | 小体积,适合板级设计 |
| 非易失存储 | 无 | 上电后需要 MCU 重新配置 |
从电路位置上看,AD5293 可以接成电位器模式,也可以接成变阻器模式。电位器模式就是 A、B、W 三个端子都用,W 作为滑动端输出分压;变阻器模式则是把 A 或 B 空接一端,只用 W 到剩下那端之间的可变电阻,相当于一个两端的可编程电阻。校准工装里大多数情况用的是变阻器模式,因为我们需要的是“等效电阻”,不是“分压比”。
2.2 变阻器模式下的 wiper 电阻
变阻器模式必须理解 wiper 电阻。AD5293 内部每个抽头都是一对 MOS 开关,从抽头到 W 引脚之间会有几十欧姆的导通电阻,数据手册里通常叫 R_W。这个电阻会和目标电阻串联,导致你设置的值和实际量到的值有偏差。
举个例子,设置目标电阻为 10 kΩ,理想情况下 W 到 B 之间的等效电阻是:
R_WB = (D / 1024) × R_AB
D 是写入的抽头码,范围 0~1023。如果不考虑 R_W,当 D = 512 时,理论值是 10 kΩ。但实际量到的是:
R_WB = (D / 1024) × R_AB + R_W
多出来的 R_W 可能有三五十欧姆,对绝对电阻精度要求高的场合,这就是个不可忽略的偏差。后面我会讲怎么通过标定来消除这部分误差,但选型阶段心里要清楚:数字电位器适合做“可控误差量”,而不是“出厂就是精密电阻”。好在 AD5293 的端到端容差有 ±1%,配合外部标定,做到 0.1% 以内是可行的。
2.3 没有 NVM 不是缺陷,是一种安全考量
这颗料和同系列的 AD5292 相比,最大区别是没有内置非易失存储器。AD5292 可以把抽头位置存到芯片内部 NVM 里,下次上电自己恢复;AD5293 没有这个功能,每次上电后 RDAC 寄存器回到默认值,必须由外部 MCU 重新写入目标码。
很多人第一反应是“没 NVM 不方便”,但在工业校准设备里,这反而是个优点。带 NVM 的芯片上电瞬间会立即把上次保存的电阻值加载到端子上,如果上一次是高压或大电流状态,重新上电就可能产生危险的瞬态。用 AD5293 时,系统完全可以设计成:上电后所有模拟通道先处于安全默认状态,等 MCU 完成自检、确认通信正常,再按预先设定的时序把电阻写进去。整个过程是可控的,不会出现“裸奔”的意外状态。
3. 主控选型:为什么是 PIC18LF46K42 而不是先用 Arduino
3.1 PIC18LF46K42 外设和接口的匹配度
驱动 AD5293 这种 SPI 数字电位器,一颗 8 位单片机完全够用,但关键要看接口数量、电源域和模拟外设。PIC18LF46K42 属于 Microchip 的 K42 系列,工作电压 1.8 V 到 3.6 V,属于低功耗型号,同时片上带两个 MSSP 模块,可以配置成 SPI 或 I2C,拿其中一个专门给 AD5293 用,剩下的还可以接外部 Flash 或传感器,非常从容。
我选它的另一个原因是温度范围。校准设备经常要在老化房里连轴跑,环境温度可能到 70°C 甚至更高,芯片工作温度范围必须覆盖 -40°C 到 +125°C,PIC18LF46K42 是标准工业级,这点比很多开发板主控靠谱。
片上的 Flash 有 64 KB,RAM 有 4 KB,EEPROM 有 1 KB。如果要做多组校准参数存储,1 KB EEPROM 虽说不算大,但存几十个电阻值和标定系数完全够用,而且不占用 Flash 空间。对校准设备来说,这个存储规模刚刚好。
3.2 内核独立外设 CIP 能分担不少活
K42 系列最大的特色是“内核独立外设”,也就是内核 DSP、CIP 等不需要 CPU 全程参与的外设。PIC18LF46K42 上最有用的是 12 位 ADC with Computation,它内部带了硬件累加器、滤波器和设定点比较器。这意味着你可以让 ADC 连续采样某个模拟节点,在硬件层面做平均或阈值比较,结果超过设定范围时直接触发中断或事件,CPU 只需要在事件发生时处理,而不是一直轮询。
这个特性在闭环校正里非常好用。我们可以让 AD5293 输出一个电阻值,然后用已知参考电阻做分压,让 ADC 持续采样分压点,判断实际电阻是否落在允许误差范围。因为滤波和比较都在外设里做,CPU 可以去处理通信协议或显示,系统实时性高很多,代码也更简洁。
3.3 用 MCC 生成驱动代码,省掉一半手写工作量
Microchip 的 MPLAB X 集成开发环境搭配 XC8 编译器,有一款图形化配置工具 MCC(MPLAB Code Configurator)。新建工程后,可以直接在界面里勾选 SPI 模块、设定引脚、配置时钟,甚至把 EUSART 串口和 ADC 也一起生成代码。对于 AD5293 这种外设,核心驱动就是几个字节的 SPI 写操作,MCC 生成之后稍作封装就能用。
实际开发中我通常会这样分配资源:
| 资源 | 用途 |
|---|---|
| MSSP1 | SPI 驱动 AD5293 |
| Timer0 或 Timer2 | 控制上电加载和重试定时 |
| ADCC | 采集自校准分压点 |
| EUSART1 | 和上位机通信或输出调试日志 |
| EEPROM | 保存标定参数和设备序列号 |
整个项目里,单片机不需要跑复杂的操作系统,也不需要浮点运算,一颗 8 位机就能把控制、通信、校准全部做完。
4. 原理图和 PCB 上的关键细节,照着画就能少踩一半坑
4.1 供电树和逻辑电平的处理
AD5293 的模拟电源范围比较宽,可以用单电源 5 V,也可以用正负电源,比如 ±15 V。具体选哪种,取决于你的信号链电压范围。如果 AD5293 只是用来给运放做增益配置,信号幅度在 ±10 V 以内,那用 ±15 V 供电比较稳,端子上的电压摆幅不会受限;如果只是做低电平传感器模拟,5 V 单电源就足够,功耗和成本都低。
PIC18LF46K42 最大供电电压是 3.6 V,所以通常由 3.3 V 电源供电。这时要注意 AD5293 的数字输入引脚阈值。如果 AD5293 由 5 V 供电,而 MCU 输出高电平只有 3.3 V,严格来说要看数据手册里 VIH 的规格判断是否满足。保险做法是给 AD5293 数字接口单独供电,或者在 SPI 线上加电平转换芯片,又或者用 3.3 V 兼容型号直接对接。不要抱着“反正数字芯片都能配”的心态,现场莫名丢数据十有八九是电平不匹配。
4.2 SPI 接线:SYNC 这根线很关键
AD5293 用 SPI 接口,传统三线是 SCLK、SDI 和 SYNC,部分型号还有 SDO 用于读回。SYNC 在芯片里承担帧同步的作用,相当于片选信号,要在整个数据帧传送期间保持低电平,传送结束后拉高,芯片在 SYNC 上升沿锁存数据。这个细节和很多普通 SPI 从机不太一样,普通从机往往靠片选下降沿锁存地址,而 AD5293 更强调帧结束时的上升沿。
原理图上,SYNC 不能随便接一个普通 GPIO 就完事。如果 SYNC 线上有毛刺,或者在 MCU 配置 GPIO 的一瞬间出现电平跳变,芯片就可能把不完整的数据当成命令执行。我在实际电路里会在 SYNC、SCLK 和 SDI 上各串联一个 10 Ω 到 33 Ω 的电阻,放在靠近 MCU 引脚的地方,用来抑制反射。如果 MCU 和 AD5293 之间连接线比较长,比如板对板甚至线缆连接,最好再加续流电阻和 TVS 管。
4.3 端子侧的保护与缓冲
AD5293 的 A、B、W 端子不是无限耐压的,它们只能在 VDD 和 VSS 之间正常工作,一旦外部信号超出电源轨,芯片内部的 ESD 二极管会导通,轻则测量不准,重则损坏。在设计校准设备时,端子外部可能接的是被测设备的模拟输入或信号源,这时候最好采取措施:
- 在 A、B、W 三个端子上各加一个二极管钳位,防止超出电源轨。
- 必要时串联电阻限制事故电流。
- 如果需要更强的输出驱动能力,在 W 端后面接一个运算放大器做缓冲。
这里特别要提醒的是,数字电位器不适合直接当作大功率可调电阻用。20 kΩ 的器件,内部每个抽头能承受的电流通常只有几毫安,超过就可能把 MOS 开关烧掉。想控制大电流负载,正确做法是用 AD5293 设置比较电路的参考电压或增益,再去驱动外部功率管。
4.4 PCB 布局的接地策略
AD5293 本身是混合信号器件,内部既有电阻网络又有数字移位寄存器。PCB 布局上不要让 SPI 数字线横穿模拟信号区域,尤其是 A、B、W 端子接到精密的采样前端时,数字跳变会通过寄生电容耦合到模拟通路,造成毛刺。
常规做法是模拟地和数字地在 PCB 上单点连接,AD5293 的模拟地引脚和数字地引脚都接到统一的接地平面,但模拟元件放在同一区域,SPI 线走在另一侧,避免平行走线。去耦电容要靠近电源引脚放,一般 0.1 µF 并联 10 µF,所有电容的接地端尽量就近打过孔,减小回流路径。
5. 固件侧那点事:SPI 帧、电阻码换算和上电加载
5.1 用 MCC 快速生成 SPI 初始化
在 MPLAB X 里配置 MCC 时,选择 MSSP1 为 SPI 模式,设置主模式、时钟频率和极性。AD5293 的 SPI 时序要求高位在前,空闲时钟电平具体看手册,通常选择模式 0 或模式 2 中的一个,初始化完成后先写一个读寄存器命令验证通信。
MCC 生成的大概是这样一段代码:
// MCC 生成后通常不需要再手写底层,直接调用 SPI1_Open(SPI1_DEFAULT);然后我们可以把整个写电阻的操作封装成一个函数:
// 发送一帧数据到 AD5293,高位在前 static void ad5293_send_frame(uint16_t frame) { AD5293_SYNC_SetLow(); // 帧开始 (void)SPI1_ExchangeByte((uint8_t)(frame >> 8)); // 高字节 (void)SPI1_ExchangeByte((uint8_t)(frame & 0x00FF)); // 低字节 AD5293_SYNC_SetHigh(); // 帧结束,锁存 }头文件里要包含 MCC 生成的引脚定义头文件和 SPI 驱动头文件。SYNC 脚用普通 GPIO 即可,不需要硬件片选外设,因为我们要精确控制帧结束的上升沿,GPIO 操作更直接。
5.2 写抽头码的封装:命令位先查手册再填
AD5293 的 SPI 帧由命令字段和 10 位数据字段组成。不同批次或者同系列的 AD5291/AD5292/AD5293 在寄存器位段定义上会有差异,尤其是带 NVM 的 AD5292 会多出几个 NVM 相关命令,AD5293 没有这些功能,所以千万不要直接照抄 AD5292 的驱动代码。
我把写 RDAC 寄存器的命令宏单独放一个头文件里,方便根据手册对表修改:
// 这个宏必须按你手上 AD5293 数据手册里的命令定义来写。 // 下面的值是示意,不能直接当成所有型号通用。 #define AD5293_CMD_WR_RDAC (0x01u << 10) void ad5293_write_code(uint16_t code) { uint16_t frame; if (code > 1023u) { code = 1023u; } frame = (uint16_t)(AD5293_CMD_WR_RDAC | (code & 0x03FFu)); ad5293_send_frame(frame); }这段代码的价值在于把帧组装、写入、保护都封装好了,即使命令宏需要修正,也只动一行定义,不会影响上层逻辑。我自己第一次调这块的时候,就是因为在网上抄了一份别的型号的驱动,命令位对不上,结果读回的数据永远是乱的,后来对着数据手册的寄存器表逐位改才解决。
5.3 从目标电阻值到抽头码的换算
如果应用是变阻器模式,即 B 和 W 之间作为可调电阻,那么理论换算公式是:
R_WB = (D / 1024) × R_AB + R_W
反过来,知道目标电阻 R_target 之后:
D = ((R_target - R_W) / R_AB) × 1024
由于 R_W 和 R_AB 的实际值都有偏差,直接套理论公式只能得到一个逼近值。代码里可以先做一次线性预置,剩下的交给标定修正。比如:
#define AD5293_R_AB 20000.0 // 名义 20 kΩ #define AD5293_R_W 50.0 // 近似 wiper 电阻,取手册典型值 uint16_t resistance_to_code(double target_res) { double code_f; int32_t code; if (target_res < AD5293_R_W) { target_res = AD5293_R_W; } if (target_res > AD5293_R_AB + AD5293_R_W) { target_res = AD5293_R_AB + AD5293_R_W; } code_f = (target_res - AD5293_R_W) * 1024.0 / AD5293_R_AB; code = (int32_t)(code_f + 0.5); if (code < 0) code = 0; if (code > 1023) code = 1023; return (uint16_t)code; }注意这里的 R_W 是近似的,真正精确的做法是通过标定得到每颗芯片的实际参数,后面我会展开讲。
5.4 上电加载流程:先安全,后准确
因为 AD5293 没有 NVM,上电后 RDAC 寄存器默认值不一定是我们要的最终值。如果它恰好默认到中位,也就是约 10 kΩ,而上电瞬间被测设备已经检测到这个电阻,可能会短暂进入一个错误状态。解决方法是在硬件上增加一个外部模拟开关或者 MOSFET,在 MCU 初始化完成前断开 AD5293 的端子输出,等写入了正确的抽头码之后再接通。
软件流程建议这样:
- 上电后,MCU 先初始化时钟、GPIO 和 SPI。
- 初始化 AD5293 到安全码,比如 0 或 1023,由应用决定哪个更安全。
- 读取存储在 EEPROM 里的目标电阻配置。
- 调用 ad5293_write_code() 写入目标抽头码。
- 如果需要回读,则发送读寄存器命令,和写入值比对。
- 开启模拟通道输出,使 AD5293 参与电路工作。
整个过程控制在几毫秒内完成,不会让系统长期暴露在错误电阻下。
6. 精度不是靠运气:标定与闭环补偿的实操做法
6.1 误差源究竟有哪些
很多工程师把“1024 位分辨率”误理解为“精度能达到 1/1024”,实际上 AD5293 的分辨率只是分了多少格,每一格对应电阻值的绝对精度还受下面这些因素影响:
| 误差来源 | 典型量级 | 影响 |
|---|---|---|
| 端到端容差 R_AB | ±1%(名义 20 kΩ) | 全量程比例偏差 |
| wiper 电阻 R_W | 几十欧姆 | 低阻端偏差明显 |
| 温度漂移 | 几十 ppm/°C | 随温度变化 |
| INL/DNL | 小于 1 LSB 级 | 抽头间偏差 |
| 自热效应 | 由流过电流决定 | 大电流时阻值漂移 |
想要做到“标称值本身准确”,必须标定。数字电位器再准也是半导体电阻网络,环境温度、焊接应力、引脚应力都会让实际参数偏离数据手册。
6.2 一台 DMM 就够用的标定流程
最简单的标定思路是选几个关键抽头码,用六位半万用表实测电阻,然后把“目标电阻 → 抽头码”的映射关系保存成表。
步骤如下:
- 将 AD5293 配置成变阻器模式,B 和 W 之间接精密万用表。
- 从抽头码 0 开始,每隔 64 码测一个点,总共测 17 个点左右,覆盖全量程。
- 记录每个抽头码对应的实测电阻值。
- 在 MCU 里用线性插值计算任意目标电阻对应的抽头码。
线性插值的算法很简单,比如目标电阻落在实测点 (d0, r0) 和 (d1, r1) 之间,则:
D = d0 + (R_target - r0) × (d1 - d0) / (r1 - r0)
这个插值表可以存在 EEPROM 里,每台设备的表由产线写入。实际使用中我发现,用 17 个点的插值已经能把大部分非线性吃掉,AD5293 的积分非线性本来就做得不错,剩下的小偏差不会超过几个 LSB。
6.3 用板载 ADC 做闭环校正
如果设备长期运行,还想自动发现电阻漂移,可以利用 PIC18LF46K42 的 12 位 ADC。具体做法是在 AD5293 旁边放两个精密固定电阻,和 AD5293 的 W 端构成一个分压器。MCU 通过 ADC 采样分压点电压,反推出当前实际电阻和期望值的偏差。
这里给一个简化示例:
// 假设分压网络: VCC --- R_FIXED --- W(AD5293) --- GND // Vw 就是 ADC 采样点 // 反推 AD5293 实际电阻: R_measured = Vw / (VCC - Vw) * R_FIXED double measure_ad5293_resistance(uint16_t adc_value, double r_fixed) { double v_ratio; // adc_value 对应 12 位 v_ratio = (double)adc_value / 4095.0; // 这里默认 VCC 为 ADC 参考电压,如果参考不同,需要按实际电压比修正 return v_ratio * r_fixed / (1.0 - v_ratio); }实测时,VCC 的稳定性直接影响测量结果,所以参考电源要选高精度基准,或者把 VCC 当作已知量参与计算。ADC 的 12 位分辨率在校准时已经足够,因为我们要识别的是偏差方向和小范围波动,而不是替代六位半电表。
7. 工业现场稳定性:几个我遇到过的问题和规避方法
7.1 SPI 被干扰后的表现和数据完整性问题
工业现场最怕的是电机、继电器和变频器产生的电磁干扰。AD5293 的 SPI 线如果走线过长,又没有屏蔽,SCLK 上一旦出现额外跳变,寄存器数据就会错位,结果电阻值瞬间跳到另一个位置。这个故障很隐蔽,因为从外面看设备没有明显异常,只有被校设备偶尔失准。
应对办法有几层:
- 硬件上,SPI 线串接电阻,必要时降低 SPI 时钟频率,不要一味追求高速。
- 布局上,SPI 线远离继电器和功率走线,最好用地线包住。
- 软件上,每次写入后发读回命令,把读到的抽头码和写入值比对,不一致就重新写,连续失败则上报故障。
AD5293 有 SDO 引脚可以读回寄存器,虽然多一根线,但非常值得。哪怕不实时校验,每一次关键切换动作之后做一次回读校验,都能把大部分通信故障挡在出厂之前。
7.2 瞬态和阶梯跳变:被忽视的“切换噪声”
数字电位器和机械电位器不同,机械电位器是连续滑动,数字电位器是离散跳变。如果直接把抽头码从 100 改成 900,电阻会瞬间从大约 2 kΩ 跳到 18 kΩ,这个阶跃会在模拟电路里产生一个瞬态。
在对瞬态敏感的应用里,最好是软件做斜坡切换,也就是把目标码拆成若干小步,每隔几百微秒走一步。比如从 100 到 900,可以每次加 10,中间加一点延迟,让模拟节点有时间稳定。这个功能和机械电位器“慢慢拧过去”效果类似,但数字化之后重复性更好。
7.3 端子过压、ESD 和温度降额
AD5293 的端子最高耐压受 VDD 和 VSS 限制,一旦外部误接更高电压,很容易烧。产线上经常有操作人员热插拔信号线,哪怕只是一个瞬间的静电放电,也可能打坏内部开关。板级设计时,在端子上并一个双向 TVS 管,或者用电阻限流,花不了多少钱,但能省掉不少返修成本。
温度方面,如果设备工作在高温环境,电阻网络的温度系数会直接反映到输出电阻上。AD5293 的温漂不是特别大,但和精密固定电阻比还是有差距。做高精度设计时,可以把 AD5293 放在恒温区域内,或者在 MCU 里加温度补偿表。PIC18LF46K42 内部有温度传感器,读取温度然后查表修正抽头码,这个做法听起来土,实测效果却比想象中好。
最后再分享一个实操小技巧:画 PCB 时,最好在 AD5293 旁边预留一组三针的测试焊盘,分别引出 A、B、W 三个端子。调试时直接用万用表探针测量实际电阻,不用再从过孔或者芯片引脚上刮漆包线。这个小焊盘看起来不起眼,却能让标定流程里的测量效率提升一大截。做设备和仪器的人都知道,省下来的调试时间,到最后都是真真切切的成本。