1. 高压采样为什么不能直接进单片机
新能源车上的电池包电压动辄400V、800V,哪怕只是做一次简单的电压监测,你也不能把高压母线的分压点直接怼到STM32的ADC引脚上。原因很直接:STM32的ADC输入范围通常被VDDA限制在3.3V以内,而高压侧的地和低压控制侧的地之间存在巨大的共模电压差。一旦两侧地线直接连通,轻则ADC读数乱跳,重则芯片当场冒烟,甚至把调试用的电脑一起带走。
我在早期做BMS采样板的时候就吃过这个亏。当时图省事,用电阻分压后直接接STM32的ADC,台架上低压测试一切正常,装车后一上高压,ADC读数直接饱和,芯片发热,最后查出来是高压侧和低压侧共地导致的地环路问题。从那以后,凡是涉及高压采样的场景,隔离是绕不过去的第一步。
这个项目要解决的问题就是:如何用HCNR200线性光耦搭建一个750V直流采样电路,把高压侧的电压信号线性地、安全地传递到低压侧,再交给STM32的ADC进行采集。整套方案适合做新能源车高压检测、储能BMS电压监测、工业直流母线监控的工程师参考,也适合正在做相关毕业设计的学生直接抄作业。核心关键词就几个:HCNR200、STM32、光耦隔离、ADC采样、直流采样。
2. 整体方案设计与器件选型逻辑
2.1 为什么选HCNR200而不是普通光耦
普通光耦比如PC817,它的电流传输比CTR离散性非常大,同一批次不同个体之间可能差一倍以上,而且CTR随温度漂移严重。你用它传个开关信号没问题,但用来传模拟量,线性度根本没法保证。HCNR200不一样,它是专门为模拟信号隔离设计的线性光耦,内部有一个发光二极管LED和两个匹配的光电二极管PD1、PD2。PD1在输入侧做反馈,PD2在输出侧做接收,两个PD的工艺匹配度极高,典型线性度可以做到0.01%级别。
它的工作原理可以这样理解:输入侧的运放强制PD1的光电流等于输入电流,LED的发光强度由这个闭环控制。因为PD2和PD1是匹配的,PD2产生的光电流就和输入电流成固定比例关系。输出侧再用一个运放把PD2的光电流转换成电压,整个传输过程就实现了线性隔离。说白了,HCNR200不是靠LED本身的线性,而是靠两个匹配PD加负反馈来保证线性度,这是它和普通光耦的本质区别。
选型时需要注意几个参数。HCNR200的输入电流典型值在5mA到20mA之间,太小了信噪比差,太大了LED老化快。带宽方面,配合合适的运放可以做到1MHz以上,对于直流母线电压监测这种低频信号绰绰有余。隔离电压方面,HCNR200本身是3750Vrms的隔离等级,但实际能扛多高电压还要看PCB爬电距离和隔离带设计。
2.2 750V量程的分压与隔离架构
750V直流要进HCNR200,第一步肯定是分压。分压电阻的选择有几个硬约束:耐压、功耗、精度、温漂。我一般用多颗高阻值电阻串联,而不是用一颗大电阻。原因有两个:一是单颗电阻的耐压有限,0805封装通常只有150V到200V,1206也就200V左右,750V必须串联分担;二是串联后单颗电阻上的功耗降低,温升小,阻值漂移也小。
具体分压比怎么算?假设我们希望在额定750V时,分压点输出给HCNR200输入侧的电流在10mA左右。HCNR200输入侧是一个运放虚地,分压点实际上是通过输入电阻Rin接到运放的反相输入端,运放强制该点电压等于同相端电压。所以分压电阻串的总阻值决定了输入电流。
我常用的方案是:高压侧分压电阻串总阻值取1MΩ左右,由10颗100kΩ/0.5W的电阻串联组成。750V除以1MΩ等于0.75mA,这个电流太小了,HCNR200需要5mA以上。所以实际电路里不是直接用分压点驱动HCNR200,而是分压后经过一个运放缓冲,再通过输入电阻驱动HCNR200。或者更常见的做法是分压电阻串总阻值取小一些,比如150kΩ,750V除以150kΩ等于5mA,刚好在HCNR200的合理工作区间。
但150kΩ上承受750V,功耗是750²/150k = 3.75W,这个功耗太大了,电阻会烫得厉害。所以实际方案是分压串用大阻值,比如1MΩ,然后在分压点后面加一个高压运放做缓冲,再用小电阻驱动HCNR200。或者用两级分压:第一级1MΩ分压到7.5V左右,第二级再用运放缓冲后驱动光耦。我这次采用的方案是第一种,分压串1MΩ,分压点约0.75V(相对于高压侧地),然后经过一个高压运放OPA454做电压跟随,再通过1kΩ输入电阻驱动HCNR200,输入电流约0.75mA。等等,0.75mA还是太小。
重新算一下。HCNR200的输入电流IF典型推荐值是5mA到15mA。如果分压点电压是0.75V,输入电阻Rin = 0.75V / 5mA = 150Ω。但这样运放输出电流要5mA,OPA454可以做到。不过0.75V的分压点电压太小了,容易受噪声干扰。更好的做法是让分压点电压高一些,比如7.5V,这样信噪比更好。分压串总阻值1MΩ,750V时分压点7.5V,电流0.75mA。然后运放缓冲后,通过1.5kΩ电阻驱动HCNR200,输入电流5mA。这样运放只需要提供5mA,分压串只消耗0.75mA,功耗0.56W,可以接受。
所以最终分压方案:10颗100kΩ/0.5W电阻串联,总阻值1MΩ,分压比100:1,750V对应7.5V。分压点接高压运放电压跟随器,运放输出通过1.5kΩ电阻接HCNR200的输入侧。
2.3 低压侧ADC接口与STM32资源分配
低压侧HCNR200的输出是PD2的光电流,需要经过一个运放转换成电压。典型电路是运放反相输入端接PD2,同相端接地,反馈电阻Rf将光电流转换成电压。HCNR200的传输比K3(PD2电流与PD1电流之比)典型值是1,所以PD2电流约等于PD1电流,也就是5mA。如果Rf取1kΩ,输出电压就是5V,超过了STM32的3.3V ADC范围。所以Rf需要调整,让满量程输出电压在3.0V左右,留一点余量。
假设满量程750V对应PD2电流5mA,要输出3.0V,Rf = 3.0V / 5mA = 600Ω。取标准值604Ω或者用两个电阻并联。这样750V对应3.0V,STM32的12位ADC在3.3V参考下,分辨率是3.3V/4096 = 0.806mV,对应电压分辨率0.806mV / 3.0V * 750V = 0.2V。也就是说每0.2V母线电压变化,ADC读数变化1个LSB。对于750V量程来说,这个分辨率足够做电压监测了。
STM32这边我选的是STM32F103C8T6,ADC1的通道0(PA0)。为什么选这个型号?便宜、资料多、ADC性能够用。12位ADC,采样率最高1MHz,对于直流电压监测完全过剩。实际使用中我一般配置成连续转换模式,用DMA搬运数据,然后在软件里做滑动平均滤波。这样CPU占用极低,读数也稳定。
ADC参考电压直接用VDDA,也就是3.3V。这里有个细节:STM32的VDDA和VDD之间要加磁珠或者电感隔离,VDDA上要并10uF和100nF电容,否则ADC读数会被数字电路的噪声干扰。我在PCB布局时会把VDDA的滤波电容尽量靠近芯片引脚,磁珠放在VDD到VDDA的路径上。
3. HCNR200外围电路细节与参数计算
3.1 输入侧运放电路的设计要点
HCNR200输入侧的运放不是随便选一个就行。它需要满足几个条件:输入偏置电流小、带宽足够、能够驱动LED。我选的是OPA2376,双运放,轨到轨输入输出,增益带宽积10MHz,输入偏置电流只有0.2pA。为什么偏置电流要小?因为HCNR200输入侧运放的反相输入端是虚地,如果运放偏置电流大,这个电流会直接叠加到输入电流上,造成误差。0.2pA的偏置电流相对于5mA的输入电流,误差可以忽略。
电路连接是这样的:分压点电压经过电压跟随器后,通过输入电阻Rin接到运放的反相输入端。运放的同相输入端接高压侧地。运放的输出接HCNR200的LED阳极,LED阴极通过一个限流电阻接地。等等,这里需要仔细说一下HCNR200的引脚。HCNR200是8脚封装,1脚和2脚是LED的阳极和阴极,3脚和4脚是PD1的阴极和阳极,5脚和6脚是PD2的阳极和阴极,7脚和8脚是空脚或者内部屏蔽。
输入侧电路:运放输出接LED阳极(1脚),LED阴极(2脚)接一个电阻Rled到地。PD1的阳极(4脚)接运放的反相输入端,PD1的阴极(3脚)接高压侧地。运放的同相输入端接高压侧地。这样运放会强制PD1的阳极电压等于地电位,PD1的光电流从阳极流向阴极,也就是从运放反相输入端流向地。运放输出通过LED和Rled到地,形成闭环。
输入电流IF的计算:IF = (Vref - Vf) / Rled,其中Vf是LED正向压降,约1.6V。但实际电路中,运放输出会自动调整到让PD1电流等于输入电流。输入电流Iin = Vin / Rin,其中Vin是分压点电压。因为PD1电流等于Iin,而LED电流IF和PD1电流IPD1的关系是IPD1 = K1 * IF,K1典型值0.5%。所以IF = Iin / K1 = Iin / 0.005 = 200 * Iin。如果Iin = 5mA,IF = 1A?这不对。
我重新查一下HCNR200的数据手册。HCNR200的传输比K1 = IPD1 / IF,典型值是0.5%,也就是说IF = 5mA时,IPD1 = 25uA。K3 = IPD2 / IPD1,典型值是1。所以如果我们要IPD1 = 5mA,IF需要1A,这显然不可能。所以实际设计中,输入电流Iin不是5mA,而是几十微安级别。
重新计算:HCNR200的IF推荐范围是1mA到20mA,对应IPD1是5uA到100uA。所以输入电流Iin应该在5uA到100uA之间。如果分压点电压7.5V,要得到50uA输入电流,Rin = 7.5V / 50uA = 150kΩ。这样运放只需要提供50uA,分压串电流0.75mA,功耗0.56W。输出侧PD2电流也是50uA,要输出3.0V,Rf = 3.0V / 50uA = 60kΩ。这个阻值合理。
所以修正后的参数:分压串1MΩ,分压点7.5V,Rin = 150kΩ,Iin = 50uA,IF约10mA(因为K1=0.5%,IPD1=50uA,IF=50uA/0.005=10mA)。LED电流10mA,Rled = (运放输出电压 - Vf) / IF。运放输出电压由闭环决定,大约在2V到3V之间,Vf约1.6V,Rled = (2.5V - 1.6V) / 10mA = 90Ω。取100Ω标准值。
3.2 输出侧运放与ADC接口电路
输出侧运放我选的是OPA2376的另一个通道。PD2的阳极(5脚)接运放的反相输入端,PD2的阴极(6脚)接低压侧地。运放的同相输入端接低压侧地。反馈电阻Rf接在运放输出和反相输入端之间。这样PD2的光电流从阳极流向阴极,也就是从运放反相输入端流向地,运放输出会升高,通过Rf提供电流来平衡。输出电压Vout = IPD2 * Rf。
IPD2 = K3 * IPD1 = 1 * 50uA = 50uA。Rf = 60kΩ,Vout = 50uA * 60kΩ = 3.0V。完美。但60kΩ不是标准值,可以用62kΩ或者两个30kΩ串联。我用的是62kΩ,Vout = 50uA * 62kΩ = 3.1V,稍微超了一点,但STM32的ADC可以承受3.3V,没问题。如果想精确一点,可以在Rf上并联一个微调电阻。
输出侧运放的输出直接接STM32的ADC引脚PA0。中间可以加一个RC低通滤波,比如1kΩ电阻和100nF电容,截止频率1.6kHz,对于直流信号来说足够。这个RC滤波的作用是滤掉高频噪声,防止ADC采样时混入开关噪声。注意ADC引脚的保护,可以在引脚上并一个3.3V的TVS管,防止意外过压。
3.3 隔离带与PCB布局的硬性要求
高压隔离电路,PCB布局是生死攸关的事。HCNR200本身提供3750Vrms的隔离,但如果你PCB上高压侧和低压侧的走线挨得太近,爬电距离不够,隔离电压就形同虚设。我一般要求高压侧和低压侧之间的PCB开槽,槽宽至少2mm,槽内不铺铜。如果空间允许,开槽宽度做到4mm以上更稳妥。
爬电距离的计算:对于750V直流,按照IEC 60664-1的标准,污染等级2、材料组IIIa的情况下,爬电距离要求大约是8mm。但这是针对基本绝缘的要求,如果要做加强绝缘,距离要翻倍。实际做车规产品,我一般留12mm以上的爬电距离,开槽宽度4mm,槽两侧的铜皮到槽边缘至少4mm。
HCNR200芯片本身跨接在隔离带两侧,它的8个引脚中,1到4脚在高压侧,5到8脚在低压侧。PCB上芯片下面要开槽,槽从芯片中间穿过,把1到4脚和5到8脚完全隔开。芯片下面的槽宽至少1.5mm,因为芯片本体宽度有限,槽太宽了芯片没法焊接。实际做法是在芯片下方开一个1.5mm到2mm的槽,槽的长度超出芯片两侧各2mm。
高压侧的走线要加粗,因为分压电阻串上有750V,走线太细了容易尖端放电。我一般用1mm以上的线宽,并且走线之间保持足够的间距。分压电阻串的每个电阻之间要留足够的爬电距离,0805封装电阻的焊盘间距只有1mm左右,750V分压后每个电阻承受75V,1mm间距对于75V来说够了,但为了保险,我一般用1206封装,焊盘间距更大。
低压侧的走线就按普通信号线处理,但要注意ADC输入线要远离数字信号线,特别是时钟线和PWM线。如果实在避不开,中间加地线屏蔽。VDDA的滤波电容要靠近芯片,磁珠要选高频阻抗高的,比如1kΩ@100MHz。
4. STM32端ADC采集与软件滤波实现
4.1 ADC初始化与DMA配置
STM32F103的ADC配置我一般用CubeMX生成初始化代码,然后手动调整几个关键参数。ADC时钟不能超过14MHz,我一般配置成12MHz(72MHz除以6)。采样时间选239.5个周期,这是最长的采样时间,适合高阻抗信号源。虽然我们的输出侧运放输出阻抗很低,但采样时间长一点没坏处,读数更稳。
DMA配置成循环模式,缓冲区大小64,ADC连续转换模式。这样ADC一直在转换,DMA自动把数据搬到缓冲区,CPU只需要定期读取缓冲区做滤波就行。代码大概长这样:
// ADC初始化结构体 ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; // DMA配置 DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 64; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 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_Init(DMA1_Channel1, &DMA_InitStructure); DMA_Cmd(DMA1_Channel1, ENABLE); // ADC配置 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); // 配置通道0,采样时间239.5周期 ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); // 使能DMA请求 ADC_DMACmd(ADC1, ENABLE); // 使能ADC ADC_Cmd(ADC1, ENABLE); // ADC校准 ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); // 启动ADC转换 ADC_SoftwareStartConvCmd(ADC1, ENABLE);这段代码的关键点:DMA循环模式让ADC数据自动搬运,不需要CPU干预。ADC校准不能省,否则读数偏差可能达到几十个LSB。采样时间选最长,确保采样电容充分充电。
4.2 滑动平均滤波与电压换算
ADC原始数据噪声比较大,直接读会看到读数在几十个LSB范围内跳动。我一般用滑动平均滤波,窗口大小取32或者64。窗口越大,读数越稳,但响应越慢。对于直流母线电压监测,响应慢一点没关系,我取64。
#define FILTER_WINDOW 64 uint16_t adc_buffer[FILTER_WINDOW]; uint32_t adc_sum = 0; uint16_t adc_filtered = 0; uint8_t adc_index = 0; // 在定时器中断里定期调用,比如1ms一次 void adc_filter_task(void) { adc_sum -= adc_buffer[adc_index]; adc_sum += adc_buffer[adc_index]; adc_filtered = adc_sum / FILTER_WINDOW; adc_index++; if(adc_index >= FILTER_WINDOW) { adc_index = 0; } }等等,上面这个滑动平均的写法有问题。正确的滑动平均应该是每次用新数据替换最老的数据,然后重新求和。我重新写一下:
uint16_t adc_buffer[FILTER_WINDOW]; uint32_t adc_sum = 0; uint16_t adc_filtered = 0; uint8_t adc_index = 0; void adc_filter_update(uint16_t new_sample) { adc_sum -= adc_buffer[adc_index]; adc_buffer[adc_index] = new_sample; adc_sum += new_sample; adc_index++; if(adc_index >= FILTER_WINDOW) { adc_index = 0; } adc_filtered = adc_sum / FILTER_WINDOW; }这个写法每次减去最老的样本,加上最新的样本,然后求平均。效率很高,不需要每次重新遍历整个数组。
电压换算:ADC值转电压,Vadc = adc_filtered * 3.3V / 4096。然后根据分压比和隔离传输比反推母线电压。分压比是100:1,隔离传输比是1:1(因为K3=1,Rf和Rin的关系已经包含在电路里了)。所以母线电压Vbus = Vadc * 100。但实际电路中,Rin=150kΩ,Rf=62kΩ,传输比不是1:1。准确的计算是:Vbus = Vadc * (R1_total / R2) * (Rin / Rf) * (1 / K3)。其中R1_total是分压串总阻值1MΩ,R2是分压点对地电阻,但我们的分压点后面接的是运放跟随器,所以分压比就是1MΩ / 10kΩ?不对,分压串是10颗100kΩ串联,分压点取最下面一颗电阻上的电压,所以分压比是1MΩ / 100kΩ = 10:1?也不对。
我重新理一下分压电路。10颗100kΩ电阻串联,总阻值1MΩ。最下面一颗电阻接地,分压点取最下面一颗电阻的上端。那么分压比是1MΩ / 100kΩ = 10:1。750V输入,分压点电压是75V。这不对,75V太高了,运放受不了。
所以分压比要重新设计。如果分压点电压要7.5V,那么分压比是100:1。10颗100kΩ串联,总阻值1MΩ,最下面一颗电阻应该是10kΩ,上面9颗是100kΩ,总阻值910kΩ。分压比 = (910k + 10k) / 10k = 92:1。750V / 92 = 8.15V。差不多。
或者更简单的做法:用9颗100kΩ和1颗10kΩ串联,总阻值910kΩ。分压点取10kΩ上的电压,分压比91:1。750V对应8.24V。然后运放跟随,Rin=150kΩ,Iin = 8.24V / 150kΩ = 55uA。IPD1 = 55uA,IF = 55uA / 0.005 = 11mA。Rled = (2.5V - 1.6V) / 11mA = 82Ω,取82Ω标准值。输出侧IPD2 = 55uA,Rf = 3.0V / 55uA = 54.5kΩ,取56kΩ。Vout = 55uA * 56kΩ = 3.08V。母线电压Vbus = Vadc * (910k+10k)/10k * (150k/56k) = Vadc * 92 * 2.68 = Vadc * 246.6。如果Vadc = 3.08V,Vbus = 3.08 * 246.6 = 759.5V。接近750V,误差1.3%,可以通过软件校准修正。
4.3 校准与温漂补偿的实操经验
理论计算和实际电路总有偏差,校准是必须的。我一般用两点校准:在低压侧输入已知电压,比如100V和700V,记录ADC读数,然后计算斜率和截距。校准公式:Vbus = k * adc_filtered + b。k和b通过两点校准得到。
温漂方面,HCNR200的传输比随温度变化大约在-0.1%/°C左右,分压电阻的温漂取决于电阻类型。金属膜电阻温漂50ppm/°C,100°C温升对应0.5%的阻值变化。整体温漂可能在1%到2%之间。如果应用场景温度变化大,比如车规-40°C到85°C,温漂补偿就很有必要。
我的做法是在HCNR200附近放一个NTC热敏电阻,用STM32的另一个ADC通道采集温度,然后在软件里做查表补偿。补偿表通过高低温箱标定得到,每个温度点记录一组k和b值,实际运行时根据温度插值。这个做法比较费时间,但精度可以做到0.5%以内。
如果不想做复杂的温漂补偿,可以选低温漂电阻,比如Vishay的PTF系列,温漂5ppm/°C,价格贵一点但省事。HCNR200本身也可以选HCNR201,温漂指标更好一些,但价格更贵。
5. 调试过程中踩过的坑与排查技巧
5.1 常见问题速查表
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| ADC读数始终为0 | HCNR200输入侧LED不亮 | 测LED两端电压,正常约1.6V | 检查运放供电,检查Rled是否焊接 |
| ADC读数饱和到4095 | 输出侧运放饱和 | 测运放输出电压,正常应小于3.3V | 减小Rf,或检查PD2是否接反 |
| 读数跳动大 | 滤波不足或地环路 | 示波器看ADC引脚波形 | 增加滤波窗口,检查地线布局 |
| 读数随温度漂移 | HCNR200或电阻温漂 | 高低温箱测试 | 软件补偿或换低温漂器件 |
| 高压侧加电后低压侧芯片损坏 | 隔离带爬电距离不够 | 检查PCB开槽和间距 | 重新设计PCB,增加爬电距离 |
| 线性度差 | HCNR200工作电流不在推荐范围 | 测IF和IPD1 | 调整Rin和Rled,使IF在5-15mA |
5.2 我踩过的三个典型坑
第一个坑是输入侧运放自激振荡。当时用的运放是LM358,带宽只有1MHz,压摆率0.5V/us,驱动LED时输出波形有振荡。后来换成OPA2376,带宽10MHz,压摆率2V/us,振荡消失。教训是:HCNR200输入侧运放不要用低速运放,至少选5MHz以上带宽的。
第二个坑是输出侧运放的反馈电阻太大,导致响应慢。一开始Rf用了1MΩ,输出侧运放的输入电容和反馈电阻形成的时间常数太大,阶跃响应要几十毫秒才稳定。后来把Rf降到56kΩ,响应时间降到1ms以内。教训是:Rf不要超过100kΩ,否则带宽不够。
第三个坑是PCB隔离带开槽太窄。第一版PCB开槽只有1mm,高压测试到500V时低压侧芯片就挂了。后来开槽加到4mm,爬电距离做到12mm,750V测试没问题。教训是:隔离带开槽宽度至少2mm,爬电距离至少8mm,车规应用翻倍。
5.3 示波器与万用表配合调试的技巧
调试这种隔离电路,万用表测静态工作点,示波器看动态响应。我一般先用万用表测各点直流电压:分压点电压、运放输出电压、HCNR200各引脚电压、ADC引脚电压。这些电压和理论值对比,偏差大的地方就是问题所在。
示波器主要看两个地方:一是ADC引脚的纹波,正常应该在几个mV以内,如果看到几十mV的开关噪声,说明滤波不够或者地线布局有问题;二是输入侧运放输出,看有没有振荡,正常应该是干净的直流。
还有一个技巧:用信号发生器在高压侧注入一个低频正弦波,比如1Hz、1Vpp,然后看低压侧ADC读数是否跟随。这样可以测试整个通道的线性度和带宽。如果正弦波变形了,说明线性度不好;如果幅度衰减了,说明带宽不够。
6. 这个方案还能怎么扩展
这套750V直流采样电路的核心思路可以扩展到很多场景。比如把分压电阻串改成电流传感器加电阻,就可以做电流隔离采样。把HCNR200换成HCNR201,温漂指标更好,适合高精度应用。把STM32换成带16位ADC的型号,比如STM32F373,分辨率可以提高到0.05V。
软件方面,可以加一个CAN或者UART接口,把电压数据上传给上位机。也可以加一个OLED显示屏,做本地显示。如果做BMS,可以把多路采样电路并联,用STM32的多通道ADC轮流采集,实现多节电池电压监测。
隔离电源方面,高压侧运放需要供电,可以用一个隔离DC-DC模块,比如B0505S,从低压侧5V隔离出高压侧5V。这样整个高压侧电路就完全浮地,安全性更好。B0505S的隔离电压是1000V,对于750V系统够了,如果要更高耐压,可以选B0505S-1W或者更高规格的。
最后分享一个小技巧:HCNR200的PD1和PD2之间有一个内部屏蔽层,引脚7和8。这个屏蔽层可以接到高压侧地或者低压侧地,看哪个噪声大就接哪边。我一般接低压侧地,因为低压侧地通常更干净。如果噪声还是大,可以在屏蔽层上并一个100nF电容到地。
这个电路我前后做了三版,第一版隔离带不够烧了芯片,第二版运放选型不对振荡,第三版才稳定。现在这套方案在750V直流母线上连续跑了半年,读数稳定在±0.5%以内,温漂在可接受范围内。如果你也在做类似的高压采样项目,希望这些经验能帮你少走点弯路。