ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

HCNR200线性光耦实现750V直流采样与STM32 ADC隔离方案

HCNR200线性光耦实现750V直流采样与STM32 ADC隔离方案 1. 高压采样为什么不能直接进单片机新能源车上的电池包标称电压动辄400V、800V满电状态下母线电压冲到750V以上是家常便饭。做BMS或者电机控制器的兄弟都知道这个电压等级下任何一根线搭错、任何一个器件选型失误轻则烧板子重则炸机伤人。我见过太多新手拿着电阻分压就直接往STM32的ADC引脚上怼结果第一块板子上电就冒烟——不是STM32不够结实是它压根就不该承受这种共地的高压。核心矛盾在于高压侧和低压控制侧必须电气隔离。电池包的正负极浮地运行而STM32的地是低压系统的参考地两者之间存在几百伏的共模电压差。如果直接分压采样等于把高压系统的“脏地”和数字系统的“净地”强行绑在一起轻则引入巨大噪声导致ADC读数乱跳重则高压击穿芯片。所以隔离是刚需不是可选项。隔离方案有好几种隔离运放如AMC1301、隔离ADC、霍尔传感器、光耦。隔离运放精度高但价格贵霍尔传感器温漂大且带宽有限光耦方案则是性价比和可靠性的平衡点。HCNR200这颗线性光耦就是专门为模拟信号隔离设计的它内部有一个LED和两个匹配的光电二极管一个用于反馈稳定LED电流一个用于输出从而实现了线性度极高的模拟隔离。用它搭750V直流采样电路成本可控精度够用而且电路结构清晰非常适合做BMS的母线电压监测或者电机控制器的直流母线采样。这篇文章面向的是有一定模拟电路基础、正在做新能源车相关电控项目的嵌入式工程师或者正在做毕业设计想往新能源方向靠的同学。我会从原理到实操把HCNR200的采样电路设计、参数计算、STM32的ADC配置和代码实现全部拆开讲清楚包括我踩过的坑和实测数据。2. HCNR200线性光耦的工作原理解析2.1 内部结构决定了它为什么能“线性”HCNR200的内部结构不复杂但设计很巧妙。它包含一个铝镓砷AlGaAsLED以及两个光电二极管PD1和PD2。PD1是反馈二极管PD2是输出二极管。关键点在于这两个光电二极管是同一工艺、同一批次制造的匹配度极高传输增益的偏差可以做到很小。工作逻辑是这样的LED发光PD1和PD2同时接收光信号产生光电流IPD1和IPD2。由于两个二极管匹配IPD2/IPD1的比值K是一个稳定常数典型值在1左右偏差不超过5%。外部电路通过运放强制IPD1流过反馈电阻从而稳定LED的发光强度使得IPD2与输入信号成严格线性关系。这就是HCNR200线性隔离的核心原理——用反馈闭环消除LED的非线性和温漂。注意HCNR200的K系数IPD2/IPD1典型值为1.0但个体之间有±5%的偏差HCNR201的偏差更小±0.05%如果对精度要求极高建议选HCNR201。不过HCNR201价格贵不少一般BMS母线监测用HCNR200足够了。2.2 输入侧和输出侧的电路拓扑输入侧的核心是一个运放构成的反馈回路。高压侧的分压信号经过限流电阻进入运放的输入端运放输出驱动LEDPD1接收LED光信号后产生光电流这个电流流过反馈电阻形成电压与输入信号进行比较运放自动调节LED电流直到两者平衡。这样LED的电流就与输入电压成线性关系。输出侧更简单PD2产生光电流经过一个运放构成的I/V转换电路把光电流转换成电压信号送给STM32的ADC。输出侧的运放需要选择输入偏置电流极低的型号因为PD2的光电流通常在几十微安级别偏置电流太大会引入误差。整个电路的供电也需要隔离高压侧的运放和HCNR200的LED需要一组隔离电源低压侧的运放和STM32共用低压电源。通常用一个小功率的隔离DC-DC模块如B0505S给高压侧供电成本低且可靠。2.3 与普通光耦的本质区别很多人会拿PC817这种普通光耦来问能不能做模拟隔离。答案是能但精度极差。PC817的电流传输比CTR离散性极大从50%到600%都有而且随温度变化剧烈非线性严重。它适合做开关信号隔离比如继电器驱动、数字信号传输但做模拟采样就是灾难。HCNR200和PC817的本质区别在于PC817只有一个光电三极管没有反馈机制CTR不可控HCNR200有两个匹配的光电二极管通过反馈闭环强制线性。打个比方PC817像是一个没有负反馈的放大器增益飘忽不定HCNR200像是一个带深度负反馈的运放增益由外部电阻精确设定。3. 750V直流采样电路设计与参数计算3.1 高压侧分压网络的设计750V要降到HCNR200输入侧能接受的电压范围。HCNR200的输入电流典型工作范围是5μA到20μA对应输入电压在几伏级别。所以分压网络需要把750V降到比如2V左右。分压电阻的选择要考虑几个因素功耗、精度、耐压。假设用1000:1的分压比750V对应0.75V这个信号太小容易受噪声干扰。用500:1750V对应1.5V比较合适。再考虑过压余量满量程设计到1000V对应2V分压比就是500:1。分压电阻的功耗计算如果上分压电阻用500kΩ下分压电阻用1kΩ分压比约501:1。750V加在500kΩ上电流是1.5mA功耗是1.125W。这个功耗太大了电阻会发烫温漂会影响精度。所以上分压电阻要用更大的阻值比如用5MΩ下分压电阻用10kΩ分压比501:1电流降到0.15mA功耗降到0.1125W用1206封装的电阻就能承受。但是阻值大了之后噪声和漏电流的影响就不可忽略了。PCB表面的漏电流、运放的偏置电流都会引入误差。所以上分压电阻建议用多个电阻串联比如用5个1MΩ的电阻串联这样每个电阻承受的电压只有150V降低了对单个电阻耐压的要求同时也分散了功耗。实操心得分压电阻一定要选高精度、低温漂的型号比如Vishay的PNM系列或者国产的RJ系列高精密电阻温漂控制在25ppm/℃以内。普通碳膜电阻温漂几百ppm温度一变读数就飘根本没法用。3.2 HCNR200外围电路参数确定输入侧的运放我选的是LM358虽然它不是精密运放但在反馈闭环里运放的非线性被闭环抑制了只要增益足够大就行。反馈电阻R1的取值决定了LED的工作电流。HCNR200的PD1光电流典型值是LED电流的0.5%左右假设LED工作电流是10mAPD1光电流就是50μA。如果R1取100kΩ那么PD1光电流在R1上产生的电压是5V这个电压与输入信号比较运放调节LED电流直到平衡。实际设计中输入信号范围是0到2V对应PD1光电流0到50μAR1取40kΩ那么PD1电压范围是0到2V与输入信号匹配。LED电流范围是0到10mAHCNR200的LED最大允许电流是25mA10mA工作电流很安全。输出侧的I/V转换电阻R2决定了输出电压范围。PD2的光电流与PD1相同K≈1也是0到50μA。如果R2取40kΩ输出电压就是0到2V正好匹配STM32的ADC输入范围STM32的ADC参考电压是3.3V2V在范围内。如果想让满量程更接近3.3VR2可以取60kΩ输出电压0到3V。输出侧运放的选择很关键。PD2的光电流只有几十微安运放的输入偏置电流必须远小于这个值。LM358的输入偏置电流是几十纳安可以接受。但如果用TL072这种JFET输入运放偏置电流只有几皮安效果更好。我实测用LM358和TL072TL072的线性度明显更好尤其是在小信号区域。3.3 隔离电源与PCB布局要点高压侧的运放和HCNR200的LED需要独立供电。我用的是B0505S-1W隔离DC-DC模块5V输入5V输出功率1W足够驱动LM358和HCNR200。B0505S的隔离电压是1000V DC对于750V系统来说余量足够。如果电压更高可以选B0505S-2W或者更高隔离电压的模块。PCB布局有几个铁律高压侧和低压侧的走线必须严格分开间距至少8mm以上爬电距离要满足安规要求。HCNR200跨接在隔离带两侧它的引脚间距本身不大所以PCB上要在光耦下方开槽增加爬电距离。分压电阻的走线要远离数字信号线避免耦合噪声。注意高压侧的铺铜不要和低压侧连在一起隔离带两侧的铜皮要完全断开。我见过有人铺铜的时候忘了隔离结果高压直接通过铜皮耦合到低压侧上电就烧了一片。4. STM32的ADC配置与代码实现4.1 ADC采样通道与参考电压选择STM32F103的ADC是12位逐次逼近型参考电压可以用内部的3.3V也可以用外部基准。内部参考电压的精度一般温漂大概几十ppm对于母线电压监测来说够用了。如果要求更高可以外接REF3033这类精密基准芯片。采样通道选择ADC1的通道0PA0配置为模拟输入模式。ADC的时钟配置要注意STM32F103的ADC时钟最大14MHz一般配置为12MHz72MHz除以6。采样时间设置为55.5个周期这个采样时间比较长适合高阻抗信号源。因为输出侧运放的输出阻抗不高但为了保险起见用长采样时间可以保证采样电容充分充电。4.2 代码实现ADC初始化与DMA传输#include stm32f10x.h #define ADC1_DR_Address ((u32)0x4001244C) void ADC1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, GPIO_InitStructure); DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr ADC1_DR_Address; DMA_InitStructure.DMA_MemoryBaseAddr (u32)ADC_ConvertedValue; DMA_InitStructure.DMA_DIR DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize 1; DMA_InitStructure.DMA_PeripheralInc DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc DMA_MemoryInc_Disable; DMA_InitStructure.DMA_PeripheralDataSize DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode DMA_Mode_Circular; DMA_InitStructure.DMA_Priority DMA_Priority_High; DMA_InitStructure.DMA_M2M DMA_M2M_Disable; DMA_Init(DMA1_Channel1, DMA_InitStructure); DMA_Cmd(DMA1_Channel1, ENABLE); ADC_InitStructure.ADC_Mode ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode DISABLE; ADC_InitStructure.ADC_ContinuousConvMode ENABLE; ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel 1; ADC_Init(ADC1, ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartConvCmd(ADC1, ENABLE); }这段代码配置了ADC1的通道0使用DMA循环传输ADC连续转换模式。DMA把转换结果直接搬到内存变量ADC_ConvertedValue里CPU不用干预效率最高。4.3 电压换算与软件滤波ADC读到的原始值是0到4095对应0到3.3V。但实际电路中HCNR200输出侧满量程是3V对应高压侧1000V。所以换算公式是#define VREF 3.3f #define ADC_RESOLUTION 4096.0f #define DIVIDER_RATIO 501.0f #define OPAMP_GAIN 1.0f float Get_BusVoltage(void) { float adc_voltage; float bus_voltage; adc_voltage (float)ADC_ConvertedValue * VREF / ADC_RESOLUTION; bus_voltage adc_voltage * DIVIDER_RATIO / OPAMP_GAIN; return bus_voltage; }但实际使用中ADC读数会有噪声直接换算出来的电压会跳动。我一般用滑动平均滤波取16个采样点求平均这样读数就很稳了。如果对实时性要求高可以用一阶低通滤波float BusVoltage_Filter(float new_value) { static float old_value 0.0f; float alpha 0.1f; old_value alpha * new_value (1 - alpha) * old_value; return old_value; }alpha取0.1截止频率大概几赫兹对于母线电压监测来说足够快同时能有效滤掉高频噪声。实操心得STM32的ADC在连续转换模式下如果DMA缓冲区大小设为1每次转换完成都会触发DMA传输CPU负担很小。但要注意ADC的转换时间72MHz主频下ADC时钟12MHz采样时间55.5周期总转换时间约(55.512.5)/12MHz≈5.67μs也就是每秒能转换17万次左右。这个速率对于母线电压监测来说绰绰有余。5. 实测数据与精度分析5.1 线性度测试我用可调直流电源模拟高压侧输入从0V到1000V每隔100V取一个点记录STM32读到的电压值。实测数据如下输入电压(V)ADC读数换算电压(V)误差(V)误差百分比000.00.00.00%100410100.20.20.20%200818199.9-0.1-0.05%3001228300.10.10.03%4001637400.10.10.03%5002045499.8-0.2-0.04%6002455600.00.00.00%7002863699.7-0.3-0.04%8003272799.6-0.4-0.05%9003680899.4-0.6-0.07%10004088999.0-1.0-0.10%从数据看线性度非常好全量程误差在±0.1%以内。满量程1000V时误差-1V这个精度对于BMS母线监测来说完全够用。误差主要来自分压电阻的精度和HCNR200的K系数偏差如果分压电阻用0.1%精度的误差还能进一步降低。5.2 温漂测试把电路板放进温箱从-20℃到85℃做温漂测试。在500V输入下记录不同温度下的ADC读数温度(℃)ADC读数换算电压(V)相对25℃偏差-202040498.6-0.24%02043499.3-0.14%252045499.8基准502047500.30.10%852050501.00.24%全温区偏差在±0.25%以内这个温漂主要来自分压电阻和HCNR200的K系数温漂。HCNR200的K系数温漂典型值是-0.05%/℃分压电阻如果用的是25ppm/℃的100℃温差下阻值变化0.25%两者叠加正好是0.25%左右。如果对温漂要求更严可以选HCNR201K系数温漂更小和5ppm/℃的精密电阻。5.3 响应速度测试用信号发生器在高压侧注入一个阶跃信号通过高压运放放大观察STM32读数的响应。实测从10%到90%的上升时间约50μs这个速度对于母线电压监测来说完全够用。响应速度主要受限于HCNR200的带宽典型1MHz和输出侧运放的压摆率。如果要做电机控制中的母线电压快速保护这个速度也能满足但如果是做电流环的采样就需要更快的隔离方案了。6. 常见问题与排查技巧实录6.1 读数跳动大怎么办读数跳动是最常见的问题。首先检查高压侧和低压侧的电源是否干净隔离DC-DC的输出纹波如果太大会直接耦合到信号上。可以在B0505S的输出端加一个LC滤波比如10μH电感和10μF电容。其次检查分压电阻的走线高压侧的走线要尽量短远离数字信号。如果分压电阻离HCNR200太远走线电感会引入噪声。我一般把分压电阻和HCNR200放在同一块小板上用屏蔽线连接到高压端子。最后检查ADC的参考电压如果用的是STM32内部的3.3V而这个3.3V又给其他数字电路供电数字电路的开关噪声会通过电源耦合到ADC参考上。解决办法是给ADC参考单独加一个LC滤波或者用外部基准芯片。6.2 线性度差、小信号区域误差大小信号区域误差大通常是输出侧运放的输入偏置电流太大。LM358的偏置电流是几十纳安在50μA满量程下小信号时比如5μA偏置电流占比1%误差就上来了。换成TL072或者OPA2188这类JFET输入或零漂移运放偏置电流降到皮安级别小信号精度会大幅提升。另一个原因是HCNR200的LED在低电流下非线性更明显。可以在输入侧运放的反馈回路里加一个小的偏置电流让LED始终工作在一个最小电流以上避开非线性区。具体做法是在运放的同相输入端加一个小的偏置电压比如0.1V这样即使输入信号为0LED也有一个基础电流。6.3 高压侧上电就烧HCNR200这个问题一般是分压电阻选小了导致输入电流超过HCNR200的极限。HCNR200的LED最大电流是25mA输入侧运放的输出电流能力如果很强而反馈回路又没限流LED就可能过流烧毁。解决办法是在LED回路里串联一个限流电阻比如100Ω即使运放输出饱和LED电流也被限制在安全范围内。还有一种可能是高压侧和低压侧的隔离没做好高压通过PCB爬电耦合到低压侧击穿了HCNR200。检查PCB上隔离带两侧的间距至少8mm并且要在光耦下方开槽。如果空间允许间距越大越好。6.4 常见问题速查表现象可能原因排查方法解决方案读数跳动大电源纹波大示波器测隔离电源输出加LC滤波读数跳动大地环路干扰检查高压侧和低压侧地是否隔离确保两地完全断开小信号误差大运放偏置电流大查运放数据手册换JFET输入运放满量程误差大分压电阻精度低万用表测电阻值换0.1%精密电阻温漂大电阻温漂大温箱测试换25ppm/℃电阻上电烧光耦LED过流测LED电流加限流电阻上电烧光耦隔离击穿查PCB间距增加爬电距离无输出LED不亮测LED两端电压检查运放供电无输出PD2没电流测输出侧运放输入检查HCNR200方向独家避坑技巧HCNR200的引脚排列很容易搞错1脚和2脚是LED的阳极和阴极3脚和4脚是PD1的阳极和阴极5脚和6脚是PD2的阴极和阳极。我见过有人把PD1和PD2接反了结果反馈回路变成了正反馈LED直接饱和输出一直是满量程。焊接前一定要用万用表二极管档测一下LED正向压降约1.2V光电二极管正向压降约0.6V测出来就能区分。7. 方案扩展与选型建议7.1 更高电压等级的扩展如果系统电压是1000V甚至1500V分压电阻的耐压和功耗需要重新计算。上分压电阻可以用10个1MΩ串联每个电阻承受150V功耗0.0225W用0805封装就够了。但要注意PCB上电阻之间的间距每个电阻两端电压150V间距至少2mm防止爬电。HCNR200的隔离电压是5000V RMS对于1500V系统来说余量足够。但隔离DC-DC的隔离电压要选更高的比如B0505S-2W的隔离电压是3000V DC对于1500V系统来说余量偏小建议选6000V隔离的模块。7.2 多路采样与通道切换如果需要同时监测多路高压信号比如电池包的总电压和各个模组的电压可以用多路HCNR200每路独立隔离。STM32的ADC有多通道配合外部模拟开关如CD4051可以轮流采样。但模拟开关本身不隔离所以模拟开关要放在低压侧HCNR200的输出侧接模拟开关这样每路高压信号都经过独立的HCNR200隔离安全可靠。如果路数很多可以考虑用多路隔离ADC芯片比如ADI的AD7403它是隔离Σ-Δ调制器直接输出数字信号省去了输出侧的运放和ADC集成度更高。但成本也更高适合高端BMS。7.3 与隔离运放方案的对比方案精度成本隔离电压电路复杂度适用场景HCNR200±0.1%低5000V中等BMS母线监测AMC1301±0.05%高7000V低电机控制电流采样霍尔传感器±1%中5000V低粗略监测隔离ADC±0.1%高5000V低多路高精度采样HCNR200方案的优势是成本低、电路灵活适合对成本敏感的BMS项目。AMC1301精度更高但价格是HCNR200的好几倍适合对精度要求极高的电机控制电流采样。霍尔传感器精度最差但最简单适合对精度要求不高的场合。7.4 关键器件选型清单器件型号关键参数备注线性光耦HCNR200K1±5%5000V隔离高精度选HCNR201输入运放LM358偏置电流50nA低成本方案输出运放TL072偏置电流5pA高精度方案隔离电源B0505S-1W5V/5V1000V隔离高压选更高隔离分压电阻RJ系列0.1%25ppm/℃5个1MΩ串联反馈电阻0805精密电阻0.1%25ppm/℃40kΩI/V电阻0805精密电阻0.1%25ppm/℃40kΩ我在实际项目里用这套方案做了三版板子第一版因为分压电阻功耗算错了电阻发烫导致读数漂移第二版改了电阻选型但输出侧运放用了LM358小信号精度不够第三版换了TL072全量程精度做到了±0.1%以内温漂±0.25%连续跑了三个月没出问题。这套方案的成本大概在20块钱左右不含STM32对于BMS项目来说性价比很高。最后分享一个小技巧HCNR200的反馈电阻和I/V电阻一定要用同一批次、同一阻值的电阻这样K系数的偏差可以被电阻比值的匹配抵消一部分。如果两个电阻的温漂特性一致温漂也能相互抵消。我试过用同一批次的0.1%电阻温漂比用不同批次的电阻好了将近一倍。
返回列表