简介:面向小华半导体HC32M120与HC32F460电机控制开发者的BLDC磁场定向控制方案资料包,适用于无感三相电机驱动逆变器设计,覆盖无刷直流电机/永磁同步电机FOC控制中的算法、采样与硬件实现问题。方案采用两电阻采样电流,提供全开源FOC控制算法与角度估算观测器,同时具备过流软硬件保护、过压保护及旋钮调速输入,可配合IAR/Keil工程直接评估或二次开发。包内约2000个文件,以C/H源码、工程配置、PDF文档与Gerber制板文件为主,涵盖HC32F460(Cortex-M4@200MHz)与HC32M120(Cortex-M0+@48MHz)两套芯片的完整软硬件参考设计,压缩包整体45.2MB,目录结构便于按硬件、软件、文档分区快速检索。目前已吸引152人学习,适合电机驱动、变频器及无人机电调领域的初中级工程师对照原理图与调试配置快速上手。
1. 拿到 XHSC-HC32M120 与 HC32F460 的 BLDC FOC 资料包,先确认这三件事
拿到小华半导体这包 HC32M120/HC32F460 的无刷直流电机(BLDC)磁场定向控制(FOC)资料,绝大多数人第一反应是去找 SVPWM 波形算法,觉得那才是核心技术。但按我跟过几块板子的经验,结论正好相反:真正让项目翻车的从来不是扇区计算,而是电机转起来之前的三件事——转子初始位置怎么对、开环怎么强拖、闭环怎么切入。这份 2026-01-16 整理的资料恰好把这串流程串成了完整路径,对正从方波控制转 FOC、或者刚拿到样片想快速出转子的团队特别合适。下面按我落地这套资料的经验,把能直接照做的步骤和坑位写清楚。
2. 用 HC32 定时器搭最小 FOC 系统:互补 PWM、ADC 采样点与死区参数
资料里同时出现 HC32M120 和 HC32F460 两颗芯片,很多人会疑惑该先看哪颗。我的理解是:M120 面向低成本单电机板,外设精简、顺手;F460 是带 FPU 的 M4 核,适合把无感 FOC 算法、通信和 UI 叠在同一颗里跑。先别急着二选一,两块都跑一遍同一套 FOC 工程,反而能帮你摸清外设差异在哪。
2.1 先把最小系统框出来:一张板子的四个模块怎么分工
FOC 的最小系统不是 CPU,而是「PWM 生成 → 三相桥 → 电流采样 → 坐标变换」这一条闭路。画框图时我习惯把它拆成四块:定时器负责产生三相互补 PWM 并留死区;三相桥把 PWM 逻辑电平变成电机相电压;电流采样用两个低边采样电阻加运放,把相电流送进 ADC;最后在 CPU 里做 Clarke/Park 变换、PI 调节和 SVPWM。HC32M120 的价值在定时器,HC32F460 的价值在算力,但四块结构完全一样。
| 模块 | 常见选型 | 作用 | 容易忽略的点 |
|---|---|---|---|
| PWM 生成 | HC32M120 的 HRTIM / F460 的定时器 | 三相互补输出、中心对齐、死区 | 死区时钟分频别漏配 |
| 三相桥 | 半桥驱动 + N-MOS | 把 PWM 变成相电压 | 自举电容充电时间 |
| 电流采样 | 低边采样电阻 + 差分运放 | 把电流变成 ADC 电压 | 采样点要卡在开关稳定后 |
| 坐标变换 | CPU + 三角函数 | 电流环、SVPWM | 三角函数开销要看 cycle 数 |
这四块里,定时器和 ADC 的配置是资料里最值得逐行抄的部分,因为它们直接决定波形质量。我一般先把 PWM 调出来,再接电机,最后才碰电流环,顺序不要反。
2.2 12kHz 互补 PWM 与死区:中心对齐的好处是 ADC 好采样
FOC 的 PWM 频率我习惯从 12kHz 起步,这频率在听噪之上,MOS 开关损耗又不至于太大,无感算法也有足够多的采样点。HC32M120 的电机定时器支持 up-down 计数模式,也就是中心对齐 PWM,溢出点正好在 PWM 周期的中间位置。这个位置有两个好处:三相桥臂的开关动作都远离采样点,且流过采样电阻的电流最接近相电流平均值。
// 示意代码:函数名以所选小华SDK头文件为准,核心是四组参数 void foc_pwm_init(void) { stc_hrtim_init_t stcPwmInit; MEM_ZERO_STRUCT(stcPwmInit); PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_HRTIM, Enable); HRTIM_Init(&stcPwmInit); // 默认进入 up-down 计数模式 // PWM 频率 12kHz:PCLK 120MHz 时,重载值约 5000 // 中心对齐下,计数器从 0 到 5000 再回 0 为一个完整周期 HRTIM_SetPeriod(HRTIM_CH_A, 5000u); // 死区时间 1.5us:寄存器值 = 1.5us * 120MHz = 180 HRTIM_SetDeadTime(HRTIM_CH_A, 180u, 180u); HRTIM_DTCTL->DFC = HRTIM_DTCLK_DIV1; // 死区时钟不分频 HRTIM_DTCTL->DTA = 180u; // 上升沿死区 HRTIM_DTCTL->DTB = 180u; // 下降沿死区 HRTIM_Start(HRTIM_CH_A); HRTIM_Start(HRTIM_CH_B); HRTIM_Start(HRTIM_CH_C); }这段配置里最容易漏的是死区时钟分频:分频配错,死区时间会变成微秒级或零死区,后者在负载稍大时直通短路,烧 MOS 是瞬间的事。死区 1.5us 是低压小功率板的常见起点,具体以你选的 MOS 关断延时为准,通常留 2 到 3 倍余量。PWM 频率改了记得同步重算重载值和死区寄存器值,这两个是强耦合的。
2.3 ADC 采样窗口与电流重构:双电阻法的窗口限制
电流采样的核心不是 ADC 精度,而是采样时刻。双电阻法在每个 PWM 周期采 A、B 两相电流,C 相用基尔霍夫定律推算。采样点必须选在 PWM 中心区,因为那里三相桥臂的状态稳定,采样电阻上的电压没有开关毛刺。HC32 的定时器可以直接触发 ADC,省去在中断里手动启动采样的麻烦。
// 电流采样初始化:由中心对齐 PWM 的溢出事件触发 ADC void foc_adc_init(void) { stc_adc_cfg_t stcAdcCfg; MEM_ZERO_STRUCT(stcAdcCfg); PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_ADC, Enable); ADC_Init(&stcAdcCfg); // 12bit 单端输入模式 // 关键:用 HRTIM 溢出事件触发 ADC HRTIM_TriggerADC(HRTIM_CH_A, HRTIM_TRIGGER_ADC_OVERFLOW); // 双通道采样 A、B 相电流 ADC_ChannelConfig(ADC_CH_IA, ADC_12BIT); ADC_ChannelConfig(ADC_CH_IB, ADC_12BIT); ADC_Enable(); }这里有个双电阻采样的硬限制:每个 PWM 周期里,非零矢量作用时间必须足够长,长到采样电阻上的电流建立完成。如果占空比太小,采样窗口不足,重构出的电流会畸变。常见的下限是 2us 到 3us,换算成占空比就是载波周期的百分比。遇到低占空比工况电流波形畸变,先看是不是这个窗口不够,别一上来就调 PI。
2.4 七段式 SVPWM 的最小实现:用零序分量等效空间矢量
SVPWM 的直觉理解是「用八个开关矢量合成任意方向的电压矢量」,但写代码时不用真的查扇区表。常见做法是注入零序分量,把三相目标电压平移到一个合适的位置,效果与七段式 SVPWM 完全等价,代码还短。先由电流环输出 Vd、Vq,做反 Park 得到三相电压目标值,再算零序偏移,最后转成占空比。
// 由 dq 轴电压生成三相占空比,这就是 SVPWM 的等效实现 void foc_svpwm(float vd, float vq, float theta_elec, float v_bus, uint16_t *cmp_a, uint16_t *cmp_b, uint16_t *cmp_c) { // 1. 反 Park:dq -> alpha/beta float va = vd * cosf(theta_elec) - vq * sinf(theta_elec); float vb = vd * sinf(theta_elec) + vq * cosf(theta_elec); // 2. 由 alpha/beta 得到三相目标电压,再注入零序分量 float ua = va; float ub = -0.5f * va + 0.866f * vb; float uc = -0.5f * va - 0.866f * vb; float vmax = fmaxf(fmaxf(ua, ub), uc); float vmin = fminf(fminf(ua, ub), uc); float voff = -0.5f * (vmax + vmin); // 零序分量注入 // 3. 转成周期计数值:电压 -> 比较值 float ma = (ua + voff) / v_bus * 2.0f; float mb = (ub + voff) / v_bus * 2.0f; float mc = (uc + voff) / v_bus * 2.0f; *cmp_a = (uint16_t)(ma * 5000.0f); *cmp_b = (uint16_t)(mb * 5000.0f); *cmp_c = (uint16_t)(mc * 5000.0f); }注意调制比上限:FOC 线性调制区最高到约 0.866,超过之后电压会饱和。资料里的代码通常不会帮你处理饱和,你要自己在电流环输出端做限幅,否则高速弱磁阶段会出现电流失控。另外,5000 这个常量要跟前面定时器重载值保持一致,我习惯用宏定义统一管理。
3. 启动流程:转子初始位置检测、对齐法、强拖开环与闭环切入
PWM 和采样都打通之后,电机还不会转,因为你不知道转子在哪。BLDC 在零速时反电动势为零,无感 FOC 天生看不见位置,这是启动问题绕不开的根因。FOC 启动的资料通常会给出两到三套方案:对齐法、高频注入法、强拖开环法。高频注入适合凸极率高的内嵌式电机,算法复杂;低压无刷电机多数是表贴,对齐法最便宜可靠。
3.1 转子初始位置检测:为什么无感 FOC 在零速时是盲的
反电动势的大小正比于转速,零速时反电动势为零,任何反电动势观测器都失效。这就是无感 FOC 和带编码器 FOC 最大的区别:带编码器可以直接读角度,无感只能在转起来之后反推位置。FOC 转子初始位置检测的常见做法分三类:给固定电压矢量把转子拉到已知位置、高频注入检测磁路饱和差异、短时脉冲检测电感变化。对低压表贴电机,高频注入往往吃力不讨好,对齐法 100ms 就能搞定,而且不需要额外硬件。
3.2 对齐法:从零速把转子拉到已知位置
对齐法的原理很朴素:给任意一相或两相通一个固定方向的合成矢量,定子磁场会把转子拖到与矢量对齐的位置,拖到位之后把当前角度记为 0 度。这事听起来简单,实际坑在时间和电流上。时间太短转子还在振荡就进入下一步,角度基准是歪的;电流太大转子会冲过平衡点然后来回摇摆,一样对不齐。
常见做法是给额定电流的 5% 到 10%,持续 500ms 到 1s。注意这要求电流环在对齐阶段就工作,不能直接开环给占空比——开环给的电压会随母线电压波动,电流无法控制在安全范围。对齐结束后,转子可能还有残余振荡,我的习惯是再多等 200ms,让机械振荡彻底衰减再清零角度。
3.3 强拖开环的波形表与电流限幅
对齐完成之后,转子的位置已知且可控。下一步是让转子从零开始加速,这个阶段叫强拖开环:不给转子位置反馈,直接按设定加速度递增电角度,同时让电流环输出跟住 Iq 参考。转速太低时反电动势观测器不可靠,所以强拖要到一定转速才敢切闭环。
// 强拖阶段:按加速度把电频率推上去,并限制最大电流 void openloop_ramp(float target_hz, float accel_hz_per_s, float *current_hz, float dt_sec) { if (*current_hz < target_hz) { *current_hz += accel_hz_per_s * dt_sec; if (*current_hz > target_hz) { *current_hz = target_hz; } } // 电角度累加:角度 = 角速度积分 theta_open += 2.0f * PI * (*current_hz) * dt_sec; if (theta_open > 2.0f * PI) { theta_open -= 2.0f * PI; } }强拖加速度怎么选?加速度太快,转子跟不上定子磁场,会失步;太慢,启动时间太长,堵转保护容易误触发。常见的起步加速度是每秒钟增加 10Hz 到 20Hz 电频率,具体以电机极对数和负载惯量为准。强拖阶段必须同时限制 dq 轴电流,尤其 Iq 参考值不能超过电机额定电流,否则绕组发热会很快。
3.4 闭环切入:角度对齐与积分预置
从开环强拖切换到闭环控制的瞬间,如果开环电角度和观测器估算角度之间存在偏差,电流环会把这个偏差解释为巨大的误差,输出瞬间饱和,电流尖峰直接顶到过流保护。所以切入不能靠嘴喊「切」,得满足两个条件:转速已经高到观测器稳定输出,且开环角度与估算角度误差小于约 5 度。
// 闭环切入判断:角度误差和电流裕度都满足才能切 bool foc_can_enter_closed(float theta_est, float theta_open, float iq_ref, float iq_rated) { float angle_err = fabsf(theta_est - theta_open); return (angle_err < 0.08f) && // 约 4.6 度 (fabsf(iq_ref) < 0.9f * iq_rated); // 电流环还没饱和 }切换瞬间还有一个隐藏问题:PI 积分器里存着开环阶段的旧值,直接切到闭环会让积分器瞬间反转。资料里通常会建议在切入瞬间把电流环积分清零,或者把积分初值预置为开环阶段的输出电压。我一般选后者,因为平滑,但前提是开环阶段就有电压前馈值。切过去之后,马上检查 Iq 实际值和参考值的贴合度,如果偏差大,多半是角度基准没对齐。
4. FOC 电流环带宽怎么调:PI 初值、速度环匹配与滑膜观测器边界
电机能转之后,调参阶段就开始了。FOC 控制中带宽是一个非常容易被误解的词,尤其电流环带宽,它不是越大越好。带宽决定电流环能跟多快的参考变化:跟慢了,负载突变时电流过冲,保护误动作;跟快了,PWM 噪声和采样噪声被放大,电流波形像长了毛刺。调参之前把带宽想明白,比盲目试 PI 值重要得多。
4.1 电流环带宽先想明白再调 PI
电流环带宽的合理范围一般在开关频率的 1/10 到 1/20。12kHz 的 PWM,电流环带宽从 600Hz 到 1.2kHz 左右起步。带宽 600Hz 意味着电流环能在约 0.27ms 内跟上参考值的阶跃变化——对大多数低压 BLDC 应用已经够用。带宽调太高,采样延迟和 PWM 延迟造成的相位裕度不足,电流环会震荡,表现是电机高频啸叫加电流波形抖动。实际调试时先把带宽设低,确认稳定再往上推。
4.2 PI 初值怎么估算:从电机参数反推,别瞎猜
电流环 PI 初值不必靠试错,可以从电机相电阻和相电感估算。连续域的结论是:Kp 约等于电感乘以带宽角频率,Ki 约等于电阻乘以带宽角频率。模型不精确没关系,它给的是合理量级,至少让你不用从零开始乱试。
// 电流环 PI 初值估算:连续域近似,上板后再微调 float ri = 0.5f; // 相电阻,单位欧姆 float li = 0.3e-3f; // 相电感,单位亨 float bw = 6283.0f; // 电流环带宽 1kHz 换算成角频率 rad/s float kp = li * bw; // 约 1.88 float ki = ri * bw; // 约 3141注意这是连续域结果,离散化之后 Ki 的写法要按你用的 PI 形式换算。增量式 PI、位置式 PI、带前馈的 PI,写进去的 Ki 值差一个 PWM 周期倍数,抄资料代码时最容易错在这一行。我的习惯是先把 Kp 调好,让电流能跟上阶跃且不振荡,再加 Ki 消除静差。Kp 太小,电流响应软;Kp 过大,电流环会发出持续的嘶嘶声。
4.3 速度环带宽与环路匹配:慢十倍的逻辑
速度环带宽要低于电流环带宽,常见取电流环的 1/5 到 1/10。原因是速度环的输出就是电流环的参考,如果速度环比电流环还快,两个环路会互相激励,整个系统震荡。速度环带宽低一点不是坏事,机械系统本身响应慢,带宽太高反而会把转速传感器的噪声放大成转矩波动。电机带负载时速度掉得多,优先检查速度环 Kp,而不是电流环——很多人在这里浪费时间。
| 环路 | 典型带宽 | Kp 初值来源 | 现场先调什么 |
|---|---|---|---|
| 电流环 | 开关频率的 1/10~1/20 | 相电感 x 带宽角频率 | Kp,后加 Ki |
| 速度环 | 电流环的 1/5~1/10 | 从电流环带宽逐级降 | 负载突变后的转速恢复 |
| 位置环 | 速度环的 1/5 左右 | 只在伺服里需要 | 不单独调,先看速度环 |
4.4 滑膜观测器、低通滤波与相位边界
无感 FOC 的滑膜观测器(SMO)通过电流误差构造滑膜面,从等效控制量里提取反电动势,再利用反电动势估算转子位置。实现简单、参数少,但对模型误差敏感。滑膜增益 K 要够大才能克服参数偏差,调太大会把开关噪声放大成位置抖动。SMO 输出通常接一个一阶低通滤波器滤掉高频抖振,但低通会带来相位延迟,转速越高延迟对应的电角度越大,等效成 dq 轴耦合,表现为高速时电流失控。常见的补救是低通输出之后再加一个随转速变化的前馈补偿角。补偿角的量级可以通过低通截止频率处的相频特性估算,实测时看高速电流波形是否趋向平滑。
5. 无感 FOC 常见问题排查:初始角度偏差、采样窗口与相位延迟
这部分是血泪经验汇总,也是资料里最容易被跳过但最值钱的部分。无感 FOC 的故障往往不是单一原因,而是几个问题叠在一起。排查顺序我固定为:先看角度基准,再看采样窗口,最后看滤波延迟。角度错一切白搭,采样窗口错波形全是毛刺,滤波延迟错高速必翻车。
5.1 对齐就抖、反转:初始角度估算失败的三种表现
现象:上电对齐阶段转子抖动,甚至反向转一个小角度;或者对齐时看着正常,一带载就堵转,伴随过流保护。原因:对齐电压矢量方向和转子磁极实际位置之间存在偏差,或者对齐时间太短,转子还没停稳就进入强拖。解决:先把对齐电压幅值降到额定电流的 5%,时间延长到至少 500ms;再检查电流环在对齐阶段是否真正投入,很多工程为了省事直接给固定占空比,母线电压一波动就废了。
5.2 空载正常、带载颤振:采样窗口不够大
现象:电机空载转得很好,一加载就抖动,相电流波形边缘出现明显的台阶状畸变。原因:双电阻采样在低占空比区间采样窗口不足,重构电流失真,电流环被错误信号激励。解决:确认采样点是否在中心对齐 PWM 的溢出点,再检查最小非零矢量时间是否大于 2us 到 3us。如果不够,优先把 PWM 频率从 16kHz 降到 12kHz,或者改成三电阻采样,而不是去调电流环 PI。
5.3 高速运行电流突增:低通滤波相位延迟
现象:转速到中高速段后,电流忽然不规则波动,电机温度快速上升,甚至过流报警。原因:滑膜观测器输出经过低通滤波后,相位延迟随转速增大,位置估算滞后导致 dq 轴耦合失效。解决:给观测器角度加上随电频率变化的补偿角,再观察高速电流是否变平滑。补偿角度不是固定值,要在几个转速点上实测后做线性插值,这是无感 FOC 调高速绕不开的一步。
5.4 切闭环瞬间过流:软切换与积分预置
现象:强拖阶段一切正常,切入闭环的瞬间电流尖峰顶到保护值,或者转速明显掉一下再恢复。原因:切入时开环角度与估算角度有偏差,加上电流环积分器里存着旧值,输出瞬间饱和。解决:先确认切入条件是角度误差小于 5 度且电流环未饱和,再把积分器初值预置为开环阶段的输出占空比。这里有个细节:积分预置要同时作用于 d 轴和 q 轴,只预置 q 轴会出现 d 轴电流冲击。
5.5 电机高频啸叫:死区与噪声频谱
现象:电机运行时有刺耳的高频啸叫,电流波形看是好的,但声音不对。原因:死区时间太大或 PWM 频率落在听觉敏感区,也可能是采样噪声被电流环放大后激励了定子。解决:先确认死区时间是否与 MOS 关断延时匹配,死区过大在小占空比时尤其明显。再检查电流采样有没有加 RC 滤波,采样数据是否做了多次平均。啸叫问题如果波形正常,优先查机械和滤波路径,不要动 PI。
6. 用示波器验证 FOC:五分钟内判断环路的三个动作
调完参数,最终要靠示波器确认,不能只看电机转没转。我的验证流程固定三件事:抓相电流波形、看 SVPWM 马鞍波、对比 Iq 参考和实际值。接线时电流探头夹一相,示波器带宽限制在 20MHz,时间轴调到 2ms 一格,先看电流波形是不是平滑正弦。波形边缘发毛,说明采样噪声偏大;波形有明显削顶,说明电压调制进入饱和区。
SVPWM 的马鞍波不是看波形好不好看,是确认调制比上限:正常线性调制区,相电压波形应该呈马鞍形,上下削平超过三分之一基本就是饱和了。最后一个动作是把速度环输出的 Iq 参考和实际 Iq 同时送进示波器两个通道,看两条线是否贴合。贴合度好,说明电流环带宽够;严重分离,先加带宽,再看角度估算是否滞后。这套流程我自己每接一块新板子都会走一遍,说不上多聪明,但确实能少翻几次车。希望帮到你。
本文还有配套的精品资源,点击获取