
做无刷电机FOC控制最让人头疼的往往不是电机转不起来而是电流采样这一环反复出问题。以前做低压驱动板我一直用外部运放搭电流检测增益电阻要一个个配对差分走线怕被PWM干扰每个采样通道还要单独调偏置。第一版板子调了将近两周波形还是带着开关毛刺。后来把方案换成STM32G4芯片里直接集成了3个运放运放输出还能在芯片内部直接送进ADC整个电流采样链路才真正干净下来。这篇内容就围绕STM32G4的OPAMP和无刷电机电流采样电路展开适合正在做直流无刷驱动、想用FOC但被采样精度困扰的朋友也适合那些准备从STM32F103老方案切换到G4系列、想弄清楚片上运放到底怎么用的人。1. 电流采样方案先选型单电阻、双电阻、三电阻的账要算清楚1.1 为什么无刷电机控制非采相电流不可无刷电机的FOC控制核心就是要把三相电流解算到旋转坐标系下形成电流环、速度环、位置环的级联结构。你哪怕只做方波六步换向也需要知道当前相的电流大小来做限流保护否则MOS管说烧就烧。堵转、母线短路、上管直通这些故障的电流上升速度都在微秒级靠软件里的延时去扛根本不现实。而做FOC时电流环的采样质量直接决定力矩波动和噪声。很多朋友第一次跑FOC发现电机低速时有哒哒声八成不是算法问题而是电流波形上有毛刺和零点漂移电流环在跟着错误的反馈值做调节。正因为如此采样电路不是“放个电阻随便量一下”它需要满足带宽、精度、抗干扰三方面的要求。这里要纠正一个常见误区很多人以为只关心相电流的“有效值”事实恰恰相反FOC关心的是瞬时电流波形。你要在每一个PWM周期里捕捉电流值所以采样电路必须真实还原电流在每个开关周期的变化不能把它当成简单的直流信号处理。1.2 单电阻、双电阻、三电阻三条路线的取舍电流采样拓扑直接决定你需要几个运放、几个ADC通道以及PWM时序怎么配合。下面是三套方案的实际对比方案分流电阻数量需要运放通道第三相电流获取方式优点缺点单电阻1个1路重构成本低、硬件极简单低调制区采样窗口缺失需要插入无效开关矢量双电阻2个2路KCL推导硬件成本中等软件调校适中某一相电流很小或接近零时误差放大三电阻3个3路直接测量精度最高每相独立采样硬件复杂需要3路运放和3个ADC通道单电阻采样在低成本的电动工具、小功率BLDC里非常常见因为成本压力大。但它的麻烦在于当PWM占空比接近边界时低侧MOS导通时间太短ADC根本没有足够的采样窗口。解决这个问题的标准做法是单电阻重构算法在PWM周期里插入额外的零矢量这会改变输出线电压属于拿算法复杂度和谐波换成本。双电阻方案是很多工业伺服驱动里的折中方案因为三相电流之和为零知道了任意两相就能推第三相。但它有个隐藏问题当某一相电流过零交叉时那一路采样结果的信噪比很低用这一点数据去推算第三相误差会明显放大。所以双电阻的软件里通常要判断哪一路在零附近然后动态切换推算关系。三电阻方案最直接每相分流电阻单独采样。STM32G4的片上OPAMP数量正好对应这个需求——一片芯片搞定三路电流采样不需要在外面再接三四个运放。这也是我在这篇文章里重点展开的方案。1.3 采样窗口的时序分析采样点为什么要放在PWM中心低端三电阻采样母线电流通过电机绕组、再经过低侧MOS管流到分流电阻再到地。采样发生的瞬间必须在低侧MOS接通、绕组电流完全流过采样电阻的时候。但MOS管开通和关断不是理想的栅极驱动有上升沿和下降沿二极管反向恢复还会产生振荡尖峰。死区时间内如果直接采样读到的不是电流值而是这个开关过程的瞬态电压噪声。正确的时间窗口是在PWM周期中间、低侧MOS已经稳定导通、续流二极管已经完全截止的时候。标准做法是把ADC采样触发信号对齐到PWM定时器的周期中断也就是载波的峰值或谷值位置。这样采样点就落在低侧导通区间的正中央既躲开了开关振铃又留出了电流建立时间。如果你的MCU没有这个同步机制做FOC会非常痛苦因为你得用软件去猜测当前PWM状态采样触发点始终漂移。STM32G4的思路正好是为这个场景优化的片上OPAMP输入接采样电阻输出直接送ADCADC触发源又能被TIM1、TIM8或HRTIM的TRGO信号精确控制。采样时机、模拟链路、数字转换三件事在硬件层面就串起来了这也是我转头用G4的最直接原因。2. 用内部运放替代外部运放省下的不止是几个元器件2.1 外部运放方案的隐性代价先看看传统的外部运放方案到底贵在哪。除了运放芯片本身的BOM成本你还得考虑增益电阻需要高精度和低温漂0.1%精度电阻比普通电阻贵不少差分走线要远离功率地运放的电源去耦不能省如果你需要双极性采样还要再加一个参考电压芯片或者电阻分压缓冲电路。这些还不算最要命的最要命的是运放带宽和压摆率不匹配。有些朋友选了通用运放GBW只有几十kHz用来放大几十kHz的PWM信号出来的波形已经严重畸变。还有些用了宽带运放但配套的反馈电阻选得太大反馈节点电容让环路提前衰减实际带宽根本达不到数据手册标称值。我在LTspice里做过一个简单仿真同样的电流信号用GBW为10MHz和100MHz的两种运放分别放大输出波形在上升沿的差异肉眼可见。这就说明外部运放方案不是“随便选个型号就行”你需要为电机电流场景做带宽、压摆率、噪声、失调电压的综合评估。每一个额外器件的引入都意味着一个可能出故障的环节。2.2 STM32G4内部OPAMP的核心价值STM32G4内部集成了3个部分型号有4个运放支持独立模式和PGA模式。PGA模式下内部电阻网络已经把增益设定好了你不需要在外面配电阻省掉了增益精度和温漂两个大坑。另一个关键点是内部连接。G4的OPAMP输出能直接在芯片内部路由到ADC输入通道中间不需要经过引脚、走线和外部抗混叠电阻。PCB走线引起的寄生电容和耦合噪声在这一步直接消失。对于高频开关电路来说这个优势非常大。G4的OPAMP还支持启动校准。通过内部DAC和比较器芯片可以测量并修调每个运放的输入失调电压校准结果存在寄存器里。这个功能对电流采样太关键了因为低侧分流电阻的电压往往只有几毫伏到几十毫伏运放自身哪怕几毫伏的失调都会造成零点漂移。2.3 内部运放的局限性别拿螺丝刀当镊子用内部运放不是万能的。它最大的限制是增益选项有限PGA模式通常只能选跟随器、2、4、8、16、32倍这几档不能像外部运放那样用电阻任意设定1.5倍、2.7倍。如果你需要的放大倍数刚好在中间就得重新选分流电阻阻值把整个设计一起调整。第二个限制是通道数量固定。G4最多也就3到4个运放如果项目里既要三路电流采样又要一路母线电压检测那我还得额外想办法或者把其中一路电流改成双电阻方案来释放运放通道。第三个限制是输出摆幅。虽然号称轨对轨但靠近电源轨和地轨的地方精度还是会下降。如果分流电阻选得过大或者增益设置过高输出电压可能顶到饱和区附近ADC读数在顶端变得非线性。所以设计时最好让额定工作点落在输出范围的20%到80%区间内。看清这些限制才能在方案设计一开始就做对。用内部运放不是为了省那么几颗芯片而是要让模拟链路尽可能短、可预测、少调试。3. 看懂G4内部OPAMP的工作方式PGA模式、输入连接和输出路由3.1 PGA模式到底是怎么一回事PGA模式相当于芯片内部把运放接成了一个固定增益的同相放大器。G4的内部电阻网络是有实际制造精度的它比外部贴片电阻的匹配性更好因为同样的工艺、同样的温度漂移方向误差会被抵消。要注意的是PGA模式下运放的同相输入通常接到外部引脚你需要把分流电阻的电压信号引到这个引脚反相输入和反馈网络在芯片内部已经连好了。这就带来一个设计习惯的转变你不需要再考虑反馈电阻怎么接只需要关心输入信号的地参考点和走线防护。我刚开始用G4时踩过一个坑以为PGA模式下所有引脚都用上了其实有些型号的OPAMP有内部输入矩阵可以灵活选择同相输入来自引脚还是内部DAC。用CubeMX配置时选中了多个输入源代码生成后发现运放输出完全不对。这个问题的根源在于我把输入源的选择当成可以随便切换的开关其实G4的OPAMP输入多路复用需要配寄存器而且某些组合在特定型号上是不支持的。3.2 运放输出如何路由到ADCG4的OPAMP输出有两条路径一条是外部引脚可以接到示波器或者外部电路另一条是内部连线直接送到ADC的某个通道。设计电流采样时优先用内部路径。为什么因为外部的任何一段走线都是一个天线。三相逆变器和电机线缆本身就是强干扰源几厘米长的采样线就会拾取开关噪声。如果让运放输出引到引脚再绕一圈回到ADC引脚等于把好不容易净化过的信号又暴露在污染环境里。走内部路径就等于跳过这部分。但内部路径不是“全自动”的你要在CubeMX的ADC配置里选择正确的通道编号而且不同OPAMP所对应的ADC通道不同得结合具体型号的数据手册来确认。G431和G474的映射就有差异换型号时必须重新查。3.3 校准机制上电后第一步就该做的事情G4的每个OPAMP都带校准逻辑。校准过程会利用内部比较器和DAC去测量当前失调然后生成一组修调值写入寄存器。这相当于给每个运放做一次出厂测试后的现场自校准。校准有几点要注意。第一校准需要在OPAMP还没有真正工作在线性放大状态时执行所以要放在启动序列的最前面。第二每个运放都要分别校准不能只校准一个就当全部完成。第三校准完成后如果需要重新配置增益档位建议再校准一次因为失调补偿可能和增益设置有关。我在代码里一般这样写HAL_OPAMP_CalibrationStart(hopamp1); HAL_OPAMP_CalibrationEnd(hopamp1); HAL_OPAMP_Start(hopamp1);每次上电后都执行不要跳过。有些优化编译选项会把这段代码优化掉如果你发现运放输出跟预期差了一个固定偏移去反汇编里看看到底有没有调用校准。4. 手把手配置STM32G4从CubeMX到初始化代码4.1 CubeMX里的关键配置项打开STM32CubeMX选择G4系列型号先打开OPAMP1、OPAMP2、OPAMP3。每个OPAMP的mode选择PGA模式这时增益选项会变成2、4、8、16、32这些离散值。以三电阻采样为例分流电阻用10mΩ额定相电流20A那分流电压就是200mV。想让ADC在满量程附近用好大部分量程可以把增益设成8倍输出就是1.6V。如果电机峰值电流到40A输出也才3.2V贴近3.3V参考但还有余量这个方案很稳。输入引脚的选择也要注意。OPAMP的同相输入引脚一般都有好位置比如PA0、PA1、PA2附近但为了避免和主功能冲突我通常把三相采样引脚分配到ADC和OPAMP共用的一组IO上比如PA0、PA1、PA2配合ADC1的通道IN1、IN2、IN3这样引脚安排最紧凑。ADC部分把采样时间设置得尽量长一些。G4的ADC采样时间可选项很多从1.5周期到810.5周期都有。内部OPAMP输出驱动的内部走线肯定比外部走线容性小但为了稳定我把采样时间设为45周期以上转换时间多几微秒对整个FOC的控制周期影响不大。4.2 初始化代码的启动顺序CubeMX生成的代码默认已经调用了MX_OPAMP1_Init()、MX_OPAMP2_Init()、MX_OPAMP3_Init()但这些只是配置寄存器并没有真正把运放启动起来。你必须在主循环初始化阶段显式调用校准和启动函数。推荐的顺序是MX_GPIO_Init(); MX_OPAMP1_Init(); MX_OPAMP2_Init(); MX_OPAMP3_Init(); MX_ADC1_Init(); MX_TIM1_Init(); HAL_OPAMP_CalibrationStart(hopamp1); HAL_OPAMP_CalibrationEnd(hopamp1); HAL_OPAMP_Start(hopamp1); HAL_OPAMP_CalibrationStart(hopamp2); HAL_OPAMP_CalibrationEnd(hopamp2); HAL_OPAMP_Start(hopamp2); HAL_OPAMP_CalibrationStart(hopamp3); HAL_OPAMP_CalibrationEnd(hopamp3); HAL_OPAMP_Start(hopamp3); HAL_ADCEx_Calibration_Start(hadc1);这里有个容易被忽略的细节OPAMP的校准要在ADC校准之前还是之后我的习惯是OPAMP先启动ADC再校准。因为ADC校准是校准ADC本身的失调OPAMP输出必须稳定在一个可复现的状态ADC校准算法才不会被外部源的随机波动干扰。4.3 PWM触发ADC的时序配置FOC电流采样要求采样点对齐到PWM周期中间。我用TIM1作为PWM发生器把TRGO事件配置成Update事件或者用OCxREF的触发源送到ADC的注入组转换。注入组转换触发后会自动把三路ADC通道依次转换完不需要CPU在中断里逐个读取。CubeMX中的配置方法是ADC1的injected conversion组选择Trigger为Timer 1 Trigger Out并且在TIM1的Trigger Output (TRGO)那里选择Update Event。这样每一个PWM周期都会在定时器更新时触发一次注入转换。注意PWM的模式。如果使用边沿对齐模式更新事件在计数值到达周期值的时刻那其实就是PWM周期的中心点。如果使用中心对齐模式更新事件在计数到0和周期值的时刻都有反而是底部和顶部都在过零处需要再通过重复计数器或触发两路来筛选其中一个。实践里很多人用边沿对齐模式配合更新事件触发这样触发点正好是PWM周期中间。5. 输入滤波与硬件布局这里最容易翻车却极少有人细讲5.1 RC滤波器参数到底怎么定分流电阻到OPAMP输入之间一般要加一个RC低通滤波器。它不是为了滤掉所有高频分量而是为了滤掉远高于PWM频率的开关毛刺。如果截止频率设得太低会把电流变化细节削掉FOC算出来力矩滞后。设得太高开关振铃又滤不干净。我常用的一组合适参数是串联电阻100Ω并联电容1nF到4.7nF截止频率在30kHz到200kHz之间。下面是一组简单计算R 100Ω、C 4.7nF 时f_c 1 / (2πRC) 1 / (2π × 100 × 4.7 × 10⁻⁹) ≈ 338kHz。这个值远高于PWM频率20kHz又远低于开关振铃的十几MHz对于电流环带宽几千赫兹来说完全足够。但这里还有个陷阱滤波电容对OPAMP输入是一种容性负载尤其在同相输入模式下RC网络带来的相移可能让OPAMP环路不稳定。建议用LTspice搭一个小仿真输入一个方波看输出有没有振铃。如果振铃明显就把R稍微加大或者把C换小直到示波器上波形干净。5.2 采样保持时间与滤波电容的相互制约ADC采样保持电路本质上也是一个RC充电过程。如果外部滤波电容很大比如10nF以上ADC的采样开关打开后不是立刻就能把电压采准而是需要一定充电时间。如果采样时间设置太短读到的电压比实际值偏低而且这个误差随PWM占空比变化极难在软件里补偿。所以在定滤波电容时不要单看截止频率还要看ADC采样时间。另一个经验是如果滤波电容大于几个nF就要把ADC采样周期尽量设到最大值比如G4里常见的640.5周期或者810.5周期。换算下来在72MHz ADC时钟下大概是8到11微秒通常够用。5.3 PCB布局分流电阻的开尔文接法和大电流路径分流电阻采样最怕的不是元件参数而是PCB走线把功率电流串进来了。分流电阻的两个焊盘一边走母线大电流一边输出电压反馈如果用小信号走线和功率走线共用一段铜箔铜箔电阻就会叠加到采样信号上。正确做法是开尔文接法也就是四线制功率电流从分流电阻的两个大焊盘流过电压检测线从电阻的内侧端点单独引出汇合到运放的差分输入。检测线上几乎不流过功率电流因此不会引入额外压降。大电流路径和小信号采样线还要注意走线方向。采样线最好从分流电阻引出之后直接走一条短线到OPAMP引脚中途不要跨过MOS管栅极驱动走线也不要和大电流环路平行。如果是双层板下面一层铺完整地平面采样走线走在顶层被地平面保护住。6. 实测与校准从波形到数值的真实踩坑记录6.1 上电后看到的第一个波形我第一版G4驱动板焊接完成后用示波器接在OPAMP输出引脚上试测看到的是带着明显毛刺的方波状信号而不是平滑的正弦包络。这个现象解释起来不复杂每个PWM周期里运放输出都在随开关状态跳变。你看到的“毛刺”主要来自死区时间里的体二极管续流和栅极振铃。把示波器的触发源改成TIM1的PWM信号再把时基放大到微秒级能清楚看到在PWM开通瞬间有一个窄的尖峰持续几百纳秒。这就是为什么采样点必须避开这个区域。让ADC的触发时间设置到PWM周期的中心位置毛刺不再出现在采样窗口内电流波形才真正接近理想正弦。还有一个很隐蔽的问题三相采样通道之间的相位差。如果三个ADC通道在注入组里依次转换转换本身需要时间通道1和通道3之间可能差了十几微秒。在电机高速运转时这十几微秒对应的电流角度差已经不小会让电流环解算结果出现纹波。要解决这个问题PWM触发ADC的同时可以通过G4的多ADC同步模式来并行转换或者把电流采样点放在三个通道都最接近同一个时间点的地方。6.2 偏置问题的两种修法软件减法只是挡箭牌如果在零电流状态下运放输出不是预期的0V而是几十毫伏的误差那很可能是运放失调。G4内部校准时已经处理掉一部分但温度变化、电源电压波动、增益档不同都会让失调再漂出来。软件校正很简单在电机启动之前让三相PWM全部输出低电平记录三路ADC的读数作为零电流偏置存起来。之后每次读取相电流先减去这个偏置。这是几乎所有FOC库都做的最基本操作。但仅仅做软件偏置扣除还掩盖了硬件层面的问题。如果偏置随温度变化很大可以检查OPAMP的电源是否纹波过大。G4的OPAMP电源来自模拟电源引脚VDDA如果这个引脚的退耦电容太小或者在电源纹波大的情况下运放输出电压会产生随纹波抖动的偏置。我的做法是在VDDA引脚就近放一个1µF陶瓷电容加一个100nF高频电容并且在设计中尽量把VDDA和VREF分开避免ADC参考电压被运放电源污染。6.3 几个能让你少加班的经验第一不要把OPAMP输出引脚空着不用。我见过有人只在内部连了ADC外部pin悬空结果因为管脚浮空给内部电路引入电容耦合噪声。最好在软件初始化时把OPAMP的外部输出引脚配置为模拟模式并保持不动。第二分流电阻选型时TCR温度系数比初始精度更重要。电流采样电阻长期工作是会发热的普通厚膜电阻的阻值随温度明显漂移这会直接变成电流测量误差。选功率足够的分流电阻比如5mΩ/2W封装比选1%精度但扛不住温度的型号可靠得多。第三ADC转换结果里的偶发跳变别急着改滤波参数先检查看门狗和调试器。我曾经遇到ADC值每隔几百毫秒跳一次排查了整整三天最后发现是调试器在后台访问了外设寄存器把ADC触发源干扰了。断开调试器波形立刻恢复正常。第四如果你的电机在PWM占空比很低时出现电流采样缺失不要只怀疑硬件。低占空比意味着低侧MOS导通时间很短ADC来不及完成注入转换。这时要么改用单电阻重构算法要么把开关频率降低或者用G4更灵活的HRTIM来做更细致的时间切片。强迫自己为“不超过20%的低占空比区域”强行采样往往是设计阶段就埋下的雷。最后一点也是我每次做新板子都会保留的习惯在分流电阻和OPAMP之间预留0Ω电阻位。如果实际测试发现RC滤波特性不合适可以很方便地换不同阻值而不用重新打板。这个成本几乎为零但能让你在调试阶段省出一整周的时间。