ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

USB转4-20mA/±10V隔离模块设计:基于GP8630N的DIY方案

USB转4-20mA/±10V隔离模块设计:基于GP8630N的DIY方案 搞工控和数据采集这块的朋友应该都有过这种经历现场需要电脑直接输出一个4-20mA电流环或者±10V电压信号用来模拟变送器、驱动执行器、校准仪表甚至给PLC/DCS跑半实物仿真。买成品隔离模块一个通道动辄几百块功能还不一定顺手自己用开发板搭又牵扯隔离、电源、精度一堆事最后体积和成本都不好看。我这次分享的就是自己从零做的一个USB转4-20mA/±10V隔离模块。核心方案是用国产GP8630N这颗16位DAC芯片加上一颗几块钱的隔离器和一块1W隔离电源把电脑USB口的指令变成真正带隔离的模拟输出。整套核心元件成本控制在15元左右第一批打样PCB加进去也就不到20元PCB文件也已经丢到立创开源广场了。实验室自动化、变送器校准、阀门定位器驱动、PLC模拟量测试这些场景都很适合参考这套设计。文章不聊虚的直接把需求拆解、器件选型、电路计算、固件协议、调试踩坑都摊开讲照着做基本能复现。1. 项目方案选型:为什么是隔离模块,为什么用GP8630N1.1 需求拆解:USB控制模拟输出的典型场景日常工作中我会遇到两类需求。一类是要给现场的变送器或者数显仪表送一个可调的4-20mA信号这是仪表校准的基础操作信号源必须稳定、纹波小。另一类是给伺服驱动器、比例阀这些执行机构提供±10V速度给定或位置给定如果用PLC程序里临时改曲线调试效率极低。这两种信号有一个共同特点:都是工业级的模拟量接口直接跟现场电源、电机、阀门揉在一起地电位差往往很夸张一不小心就会把USB口甚至笔记本主板烧掉。所以模块必须带电气隔离。隔离的作用说白了就是切断两侧的地环路让电脑侧的地和现场信号侧的地各过各的中间的通信和电源全部通过磁/光隔离传递。这是工业现场的安全红线不能省。另外一个实际需求是体积要小、协议要简单。上位机发一串指令模块输出对应的电流或电压不需要高刷新率也不需要几MHz的采样核心指标是16bit分辨率和±0.1%以内的线性度。这么看下来USB转串口单片机DAC的结构就是最顺手的选择。1.2 为什么是GP8630N而不是其他DAC对DAC的选型我一开始其实对比过三个方案第一类是用PWM滤波做模拟输出。单片机输出PWM经过RC滤波成直流电压。这个方案成本极低但PWM滤波后的纹波很难压到1mV以内16位分辨率完全无从谈起。精密控制场景基本不靠谱。第二类是常规SPI接口的外置DAC比如MCP4921、DAC8552这类。性能不错但SPI因为有MISO方向在需要隔离的场合会多出信号线而且还得额外配基准源成本和面积都上去了。第三类就是我最后选的GP8630N。这颗芯片是I2C接口的16位数模转换器内置输出放大器可以不需要外部基准源直接输出0-5V。它的输入侧只需要SDA、SCL两根线而且实际使用中只需要单向写数据——单片机写GP8630N收没有回读的必要。这就让隔离变得非常轻松两颗光耦或者一片双通道数字隔离器就能搞定。价格在3-4元一颗性价比极高。GP8630N输出0-5V还不是最终要的4-20mA和±10V。后面需要通过运放电路做电压-电流变换和电平移位放大这正好是模拟电路里最经典的两种结构做起来不复杂但计算要仔细。1.3 隔离方案与电源架构怎么定隔离部分的方案决定了整个模块的可靠性。一开始我其实想过用隔离运放直接把0-5V模拟电压隔离过去比如ISO124这种经典器件单个价格几十元还需要双路电源体积也大完全不符合15元的成本目标。后来想明白了一件事:先模拟隔离不如先数字化再隔离。GP8630N和单片机之间就是两根I2C线把它当作一个只写不读的从设备就可以用单向数字隔离器把SDA和SCL隔离过去。所有精度相关的转换都在隔离侧完成这种“先隔离数字信号、再本地转换模拟输出”的架构在工业卡板上其实非常常见。我最后选了ISO7721双通道数字隔离器一片搞定SDA和SCL比用两颗光耦还省事速率和稳定性也更好。电源隔离用的是B0505S-1W5V输入、5V输出隔离耐压一千伏以上。单片机这边直接USB取电模拟输出侧靠B0505S供电。两侧地严格分开PCB上做开槽处理。成本账算下来大概是这样的器件型号单价(约)说明USB转串口CH340N1.5元SOP8封装内置晶振主控MCUSTC8G1K081.2元8脚内置I2C16位DACGP8630N3.5元I2C接口输出0-5V数字隔离器ISO77213.0元双通道隔离电源B0505S-1W2.5元5V转5V运放OPA333等1.8元用于电流/电压调理阻容及接口件-2.0元按常用阻值估算PCB(拼板均摊)5片起打5.0元嘉立创打样均摊单板BOM大约15-20元和商品模块的几百元比便宜一个数量级。2. 硬件电路设计:从USB到0-5V再到4-20mA/±10V2.1 USB转串口与主控选型USB侧我用的是CH340N没有选FT231X、CP2102N这些老面孔。原因很简单CH340N是SOP8封装芯片内部自带晶振外围只需要两颗104电容焊接面积小成本1块多Windows和Linux下都有免驱方案。FT231X虽然驱动生态好、抗干扰强但一颗芯片就要10元以上在这个项目里没必要。我也会在文末提一下如果要求宽温工业级或者特殊认证可以替换FT231XPCB封装兼容的话改动很小。CH340N的TXD、RXD直接接到单片机串口。这里注意接线要交叉CH340N的TXD接MCU的RXDRXD接MCU的TXD。有的朋友抄板子不看方向焊完才发现TXD对TXD怎么都不出数据。主控用STC8G1K08SOP8封装8引脚自带硬件I2C、串口、1KB RAM、8KB Flash1块多钱的芯片干这点活得心应手。如果你手头有STM8S003或者新唐的八脚芯片也都能替换只要I2C主模式和串口都能正常跑就行。不过要注意STC8G1K08的IO口默认是高阻输入上电后如果不初始化IO口是浮空的GP8630N的SDA线会乱跳。固件里第一步就是把I2C两个引脚配置成推挽输出并需要外接4.7k上拉电阻到3.3V或5V。2.2 GP8630N的驱动电路与I2C时序GP8630N的接线非常简单VDD接5VGND接地SDA、SCL接单片机IO口各串一个4.7k上拉电阻VOUT输出0-5V模拟电压它是标准I2C从设备7位地址根据数据手册是0x48器件地址带最后一位置0后是0x90写地址。写入时主机先发送START再发送器件写地址0x90然后连续发送16位数据的高字节、低字节。GP8630N内部有锁存器16位数据全部到位后输出立刻更新到对应的电压值。换算关系按数据手册是:[ V_{out} \frac{code}{65536} \times 5V ]也就是说写入code0x800032768理论上输出约2.5V。写入code0xFFFF接近满量程5V。实际调试时我建议把I2C的SCL时钟频率控制在100kHz以内不要追求400kHz高速模式。GP8630N内部对I2C时序的容限没有单片机那么宽尤其隔离器自身还有几十纳秒的传输延迟SCL太快容易丢数据。我自己的代码里配置SCL大约80kHz实测几千次连续写入没有一次出错。2.3 4-20mA电流环输出电路计算GP8630N输出的0-5V要先变成4-20mA电流。我用的是最经典的“运放三极管”恒流源结构没有用XTR111这种专用芯片又省下好几块钱。电路思路是这样的运放同相输入端接DAC输出电压 (V_{DAC})反相输入端接采样电阻 (R_s) 上端的电压运放输出驱动NPN三极管基极三极管发射极接 (R_s) 到隔离地。当整个环路稳定时反相输入端电压基本等于同相输入端电压所以流过 (R_s) 的电流为[ I_{out} \approx \frac{V_{DAC}}{R_s} ]负载串接在外部电源和NPN三极管集电极之间输出的是灌电流方向。要满足4-20mA输出我取 (R_s125\Omega)那么需要DAC输出4mA对应0.5V20mA对应2.5V也就是说GP8630N只需要输出0.5V到2.5V这一段而不是全程0-5V。这样好处是留出了0-0.5V和2.5V-5V的裕量软件上可以针对具体器件做校准偏移调整。DAC码值和电流的关系可以写成[ code \frac{(I - 4mA)}{16mA} \times 32768 6554 ]也就是电流0-20mA映射到DAC 0x199A到0x8000附近。如果用户要0-20mA只需把起点映射改成0mA对应0V即可。三极管选择上不要用8050这种小功率管子建议用S8050也行但最好是D882或者MJE13003这一类因为电流环输出侧可能外接24V甚至更高电压三极管CE压降需要扛得住。R_s电阻要用低温漂的最好0.1%精度金属膜电阻否则温度变化时电流漂移会超出仪表校准要求。2.4 ±10V电压输出电路计算从0-5V变到±10V不是简单放大2倍而是需要一个“放大加平移”的操作数学关系如下[ V_{out} 4 \times V_{DAC} - 10V ]我看有的朋友用加法器硬凑调半天也调不对其实就是没有先列这个关系式。有了公式电路结构就很清晰反相放大结构里同时做增益和偏置。标准反相加法器电路[ V_{out} -\left( \frac{V_{DAC}}{R_1} \frac{V_{ref}}{R_2} \right) \times R_f ]我想要 (V_{out} 4V_{DAC} - 10V)取负数后变成 (-4V_{DAC} 10V)。取参考电压 (V_{ref} -5V)则[ V_{out} -\left( \frac{V_{DAC}}{R_1} \frac{-5V}{R_2} \right) \times R_f -\frac{R_f}{R_1}V_{DAC} \frac{R_f}{R_2} \times 5V ]令 (\frac{R_f}{R_1}4)(\frac{R_f}{R_2}\times 5V10V)得到 (\frac{R_f}{R_2}2)。选R110kΩR220kΩRf40kΩ就行。PCB文件里这三个电阻都标注得很清楚。-5V参考电压我建议不要用稳压管分压稳定性太差。更可靠的做法是用一个运放构成的增益为-2的反相放大把隔离侧的-5V电源转成-10V不对这里需要一个稳定的-2.5V或-5V参考。更好的是用TL431或ADR3412这类2.5V基准再加一级反相器生成-2.5V或者直接用-5V电源经精密电阻分压加运放缓冲。实际电路里我直接用隔离侧B0505S输出的5V经过一个2.5V基准TL431生成2.5V再通过反相器得到-2.5V接入R2。这样精度完全够用。但要注意运放输出±10V供电不能只给5V运放电源至少要±12V以上。我的做法是在隔离侧加一级电荷泵和升压用MC34063从5V升到12V再用ICL7660电荷泵得到-12V给运放供电。这里消耗的功率不大因为电压输出端驱动能力只要几个mA就够主要驱动外部仪表输入阻抗通常是10k以上所以升压电路压力很小。2.5 隔离接口与PCB设计要点数字隔离器ISO7721有A通道和B通道我拿A通道做SCLB通道做SDA方向都是从单片机侧向模拟输出侧。注意ISO7721的两个通道是独立的单向通道不能用错方向芯片侧标注了输入和输出引脚PCB上一定按照丝印来不要靠猜。电源隔离用B0505S输入5V输出5V。B0505S的输出功率只有1W算下来给GP8630N、运放、基准供电勉强够但给运放±12V升压一定要量一下功耗别让后级把隔离电源拉垮。我之前第一版就是在运放输出级加了较大负载电阻导致B0505S过热输出电压掉到4.2VDAC满量程对不上了。PCB布局上必须做“物理隔离”我通常会在板子中间留一条空地线上的走线全部走两侧不跨地切割。两侧地之间至少要开1mm以上的槽争取达到爬电距离要求。GP8630N和运放放在隔离侧CH340N和主控放在USB侧。4-20mA电流环的走线按照常见线宽电流对照表30mil的1oz铜箔大概能走1A电流20mA信号完全没压力但我仍然会加宽到40mil减少压降。靠外侧的电流回路线单独走不要和信号线平行长距离走否则叠加的噪声会直接反映到输出电流纹波上。板子上要留测试点DAC输出电压、GND_ISO、VCC_ISO、运放各输出点最好用小焊盘引出。否则调试时万用表探针没地方扎只能怼芯片引脚很容易短路。3. 固件与上位机协议设计3.1 下位机程序逻辑固件逻辑不复杂核心是串口收帧、解析命令、写DAC但是帧格式一定要设计严谨否则后面做上位机、调现场时会很痛苦。我用的协议帧格式如下字节含义说明0帧头10xAA1帧头20x552通道0x01:电压输出, 0x02:电流输出3数据高字节DAC高位4数据低字节DAC低位5校验和前面5字节累加和取低8位为什么要帧头用两个字节0xAA 0x55因为0xAA和0x55二进制交替特性不同能有效防止串口噪声误触发。串口没有专门的中断处理复杂协议只要收满6字节就解析一次。同时加一个帧超时保护如果收到第一个字节后50ms内没有收满一帧就直接清空缓冲区防止半个帧卡死状态机。核心的一段I2C写DAC的代码大概是这样void gp8630n_write(uint16_t code) { I2C_Start(); I2C_SendByte(0x90); // GP8630N写地址 I2C_WaitAck(); I2C_SendByte((code 8) 0xFF); I2C_WaitAck(); I2C_SendByte(code 0xFF); I2C_WaitAck(); I2C_Stop(); delay_us(10); // 等待内部锁存稳定 }写完DAC后我会把当前的code值回存到一个全局变量同时用串口向上位机回发一帧“写成功”的应答。这样上位机可以确认指令是否真的执行了。这个在生产测试里非常有用不然电脑端发了指令模块没动根本不知道是串口没通还是DAC没写进去。3.2 上位机与驱动调试上位机我用Python写了一个简短的串口控制脚本依赖pyserial。第一版只是为了功能验证没做界面直接在命令行传通道和电压值。核心代码就这样import serial, sys port serial.Serial(COM3, 115200, timeout0.2) channel int(sys.argv[1]) # 1: voltage, 2: current volt float(sys.argv[2]) # desired voltage or mA value code int(volt / 5.0 * 65535) if channel 2: code int(((volt - 4) / 16.0) * 32768 6554) frame bytes([0xAA, 0x55, channel, (code 8) 0xFF, code 0xFF, 0]) frame frame[:-1] bytes([sum(frame[:5]) 0xFF]) port.write(frame) resp port.read(6) print(resp:, resp.hex()) port.close()实际用下来115200波特率下一条指令从发送到模块输出更新延迟在几毫秒以内手动校准完全够用。调试过程中如果电脑不识别模块第一件事是看设备管理器里有没有出现COM口设备没有就检查USB线是不是只接了电源线、CH340N焊功、MCU是否供电。如果出现了“USB-SERIAL CH340”但打不开端口多半是驱动冲突卸载设备后重新插拔让系统重新枚举。再不行就用USBlyzer抓包看一下枚举过程确认设备描述符对不对。USB枚举过程说白了就是设备插上后主机发出复位、读设备描述符、分配地址、读配置描述符这一整套流程如果卡在某一阶段通常是D上拉电阻或者时钟的问题。CH340N内置了上拉和晶振只要焊接没问题基本秒认。4. 实际操作过程与调试记录4.1 焊接与上电检查步骤PCB回来后别急着把所有芯片都焊上去我习惯分阶段焊接、分阶段测试第一步只焊USB座、CH340N、主控MCU、LDO以及配套的电容电阻。上电后确认电脑能识别USB串口MCU能不能通过串口发hello。第二步焊GP8630N和数字隔离器先不焊B0505S此时电源可以从外部稳压电源临时供5V到隔离侧。上电后写一个固定code量GP8630N输出脚有没有对应的直流电压。这一步如果没输出问题基本锁定在I2C时序或者地址配置上跟后级无关。第三步再焊B0505S、运放、三极管和输出端子。焊完之后先量隔离电源输出是否5V再量运放供电是否±12V。都正常后才能开始整机联调。焊接顺序的经验是由小到大、由电源到信号、由数字到模拟。越靠数字逻辑的越先焊越靠模拟输出的越后焊调起来心里有谱。4.2 从USB到DAC的联调记录GP8630N联调时我做了这样一组测试通过上位机分别写入code 0x0000、0x4000、0x8000、0xC000、0xFFFF然后用万用表量DAC的VOUT引脚。实测数据记录如下写入code理论输出电压实测电压0x00000V0.002V0x40001.25V1.251V0x80002.5V2.498V0xC0003.75V3.751V0xFFFF5V4.998V最大偏差不到2mV一致性已经很好。如果你量出来偏差特别大先检查上拉电阻阻值和电源电压GP8630N的满量程是跟着供电电压走的5V如果偏到4.9V满量程就会跟着掉到4.9V。4.3 电流环和电压环的调试与校准电流环调试我直接用了100Ω精密电阻作为负载串在24V电源和模块电流输出端之间。公式上如果有 (I_{out}10mA)电阻上压降应该是1V。写入对应code后用万用表串联测电流同时测电阻两端电压两边对得上就说明电路是通的。最常见的坑是运放输出没有足够的驱动电压去推动三极管基极导致电流跟不上设定值。因为3.3V供电的单片机或者某些运放输出摆幅不够会限制三极管基极电压。所以这里运放供电要用隔离侧5V如果不是轨到轨输出运放5V供电下最高输出就只有3.5V左右三极管发射极电阻上的电压就会被限制在2.8V附近换算成电流就是22.4mA夏天温度再一高就容易超标。我最后换了OPA333这类轨到轨输出运放5V供电下输出能到4.99V电流环最高可以到接近40mA裕量很足。电压环调试时给DAC写入不同code用万用表测输出端子。0x0000应该对应-10V0x8000对应0V0xFFFF对应接近10V。如果输出范围不对称比如正边到9.6V就顶住了先查运放正电源有没有降到12V以下负边到不了-10V查负压电荷泵的输出电压。我第一版用的ICL7660电荷泵负载能力大概20mA结果运放偏置加上去之后负压掉到-10.8V满量程输出差了0.35V后来加大了后级滤波器电容才稳住。4.4 PCB打样与后期改动经验这次打样用的是嘉立创5片5块钱四层板其实没必要两面双层板就够。初次打样建议多做V割拼板或者邮票孔拼板板子小单片打样不方便贴标签和调试。如果用到铜柱固定记得添加非金属化螺丝孔孔径3.2mm板边留够安全距离不要为了省面积把螺丝孔怼到走线堆里。板子回来后我习惯先拿万用表量一遍电源对地阻抗确认没有短路再上电。有一次就是因为USB座旁边的电容焊反导致所有电一上就烫。检测点在调试时真的是救命PCB上每个电源节点都留了一个小焊盘比什么高级仪器都好使。5. 常见问题与排查方法现象可能原因排查步骤电脑不识别USB设备CH340N虚焊、USB线只能充电、驱动异常检查VCC和GND换线设备管理器卸载驱动重插COM口存在但发指令无反应TXD/RXD接反、波特率不对、MCU未运行量MCU工作电压用示波器看TXD是否有波形GP8630N输出固定不变I2C地址写错、上拉电阻缺失、隔离器方向错先断开隔离器直接飞线测GP8630N确认0x90地址电流环输出始终为0三极管接反、负载没接、运放供电不足测三极管各脚电压确认外部24V环路已经闭合电流值比设定略低采样电阻Rs偏大或者三极管β不够换0.1%精度电阻换达林顿管或者加大基极驱动±10V正边提前削顶运放正电源不够高、输出级负载太重量运放VCC是否±12V减小负载电流模块输出跳动两侧地没隔离干净、电源纹波大检查PCB开槽B0505S输出加10uF电容隔离电源模块发烫后级功耗超标、B0505S负载过大分级量电流超过1W就换2W隔离模块最后再说一个我自己踩过的大坑第一次做电压输出级的时候我为了节省成本直接用B0505S的5V给运放供电想着输出±10V我用T型电阻网络分压不就行了结果带载能力一塌糊涂只要外部负载阻抗低于10k输出就直接被拉变形。后来老老实实加了MC34063升压和电荷泵负压输出级供电变成±12V问题才彻底解决。做模拟输出模块电源架构一定不能将就后级电路垮掉前面的DAC再准也没用。如果你也想打样试试PCB文件我放在立创开源广场了直接搜“USB转4-20mA 隔离模块”就能找到。板子很小手焊难度不高全程一把烙铁就能搞定。后续我打算再扩展两路同步输出和Modbus-RTU协议把这小模块接到SCADA系统里当虚拟仪表用扩展空间还挺大。
返回列表