电机驱动开发学习13. 电流环控制
电机驱动开发学习13. 电流环控制

一、电流环是什么
lesson11/12 分别以 转速(RPM) 和 霍尔累计位置 为被控量。本章把控制目标换成 相电流(mA):给定 目标电流,PID 自动调节 PWM 占空比,使采样电流逼近目标——在理想情况下电机输出 近似恒定转矩。
这就是 单环电流闭环:被控量是 ADC 采样的相电流,执行量仍是 PWM 占空比,反馈来自 lesson6 已在 bsp_adc.c 中实现的三相电流采集与零偏校准。
1.1 与其它单环的区别
| 环 | 被控量 SP/ACT | 典型现象 | 适用场景 |
|---|---|---|---|
| 速度环(lesson11) | RPM | 恒速运行,负载变化时自动加力 | 风扇、输送带 |
| 位置环(lesson12) | 霍尔计数 | 转到指定位置后停下 | 定点定位 |
| 电流环(本章) | 相电流 (mA) | 恒流/恒力矩倾向,响应快 | 力控、串级内环 |
三者 PID 公式相同(位置式,lesson8/9),差别在于 反馈量纲 与 整定思路:
- 速度环:误差单位是 RPM,输出对应「需要多快」;
- 位置环:误差单位是计数,输出对应「需要转多远」;
- 电流环:误差单位是 mA,输出对应「需要多大驱动电压/占空比」;方向由用户单独设定(按键 K3/K4 或串口
d),PID 只调节电流幅值。
1.2 电流反馈:三相 ADC 与 get_curr_val_max()
lesson6 已在 ADC3 + DMA 中轮询采集 U/V/W 三相电流(PF6/PF7/PF8)。本章在 lesson6 基础上 改进了零偏校准(见 §1.6),静止时 ACT 应接近 0,否则电流环无法启动。
int32_t get_curr_val_u(void); /* U 相电流,单位 mA */
int32_t get_curr_val_v(void);
int32_t get_curr_val_w(void);
int32_t get_curr_val_max(void); /* 三相最大值,作为电流环反馈 ACT */
void adc_curr_recalibrate(void); /* 重新做零偏校准(s 0 / cal 时调用) */
uint8_t adc_curr_is_calibrated(void); /* 1=校准完成,电流环才输出 PWM */
六步换相下 同一时刻只有两相导通,未导通相采样可能接近 0。本章取 三相最大值 作为反馈,实现简单、便于观察;精度不如 FOC 的 d/q 轴电流分解,但对 学习单环 PID 结构 足够。
| 项目 | 说明 |
|---|---|
| 采样电阻 | 0.02 Ω(本板 R48 等) |
| 零偏 | 上电 静止 时自动校准,偏置电压约 1.65 V |
| 正常运行 | 空载约 0.3~1 A,带载 3~5 A |
| 软件过流 | 8000 mA,连续 200 ms 关断(lesson6) |
1.3 六步换相下的说明
野火官方文档指出:六步换相转矩不够平稳,纯电流环力矩控制效果有限;完整力矩控制需 FOC/SVPWM(lesson16 及以后)。本章仍用六步换相 + 单环电流 PID,目的是:
- 理解 电流作为反馈量 的 PID 闭环结构;
- 为 后面的 电流→速度→位置串级 打基础(电流环作最内环);
- 配合 VOFA+ / FreeMASTER 观察 SP、ACT、PWM 的跟随关系。
1.4 控制周期
野火有刷电流环官方例程使用 25 ms 周期。本章沿用 25 ms(HAL_GetTick() 节拍,与 lesson11/12 的 50 ms 不同)。改周期后 Kp/Ki/Kd 须重调,且 dt 必须与周期严格一致(CURR_PID_DT = 0.025f)。
1.5 电流环特有问题
| 问题 | 说明 | 本章处理思路 |
|---|---|---|
| 零偏未校好 | 停转 ACT≈7000 mA,ERR 为负,OUT=0 | §1.6:s 0 → cal → 等 2s |
| 采样噪声 | 电流 ADC 波动大,ACT 曲线不够平滑 | 官方偏 Ki 主导;看均值趋势 |
| 换相脉动 | 运行中 ACT 在几百 mA 范围跳动 | §1.6.3 属正常;用 max(U,V,W) 近似 |
| 方向与电流 | 电流采样无符号 | 方向由 d/K3/K4 设定,PID 输出 ≥0 |
| SP=0 停转 | 目标电流为 0 应关断 | CURR_PID_STOP_MA 阈值停 PWM |
| 与过流保护冲突 | 闭环目标过高触发保护 | SP 上限 6000 mA,低于过流 8000 mA |
1.6 电流零偏校准
电流采样是 差分测量:零电流时 ADC 仍有约 1.65 V 偏置,须先测出偏置再减掉,否则会把偏置当成电流。
1.6.1 本章校准策略
| 项目 | 值 | 说明 |
|---|---|---|
ADC_CURR_CAL_SETTLE_MS |
800 ms | 上电后先等模拟/front-end 稳定,再开始累计偏置 |
ADC_CURR_CAL_SAMPLES |
64 次 | 对每相 ADC 原始均值 取平均 作为 adc_offset |
| 校准期间 ACT | 强制为 0 | 避免未校完就参与 PID |
| 校准完成标志 | adc_curr_is_calibrated()==1 |
串口 pid 显示 cal=1 |
s 0 停环 或串口 cal 会调用 adc_curr_recalibrate(),重新计时并累计 64 次;校准完成前电流环 不算 PWM 输出。
1.6.2 典型故障:停转 ACT 却显示 7000+ mA
旧版 lesson6 逻辑在上电后 很快用单次采样锁零偏,模拟未稳定时偏置偏低 → 静止也显示约 7~8 A → 后果:
ACT 虚高 → ERR = SP − ACT 为负 → OUT 被钳在 0 → 电机不转(开环/闭环都不行)
处理:
s 0 → cal → 等约 2 s → pid
确认 cal=1,且 g_fm_iu/iv/iw_ma 与 ACT 均接近 0(几百 mA 以内),再 v 800 或 s 1。
1.6.3 运行中 ACT 在 100~600 mA 跳动正常吗?
正常。 六步换相 + max(U,V,W) + ADC 与 PWM 不同步,ACT 会有 脉动和毛刺:
- 看 趋势和均值,不要盯单点;
g_fm_iu/iv/iw应 一相高、其余低,随换相交替——这是六步特征;- ACT 均值长期明显低于 SP 时,可略加大 Ki 或少量 Kp;
- 需要平滑恒流见 FOC 章节,非本章六步方案所能完全达到。
二、实验简介
2.1 本章目标
在 lesson12 工程基础上,将位置环改为 电流环 PID:
- 反馈:
get_curr_val_max()→ 三相最大电流 (mA) - 给定:
g_fm_target_curr(目标电流 mA,默认 1500 = 1.5 A) - 输出:位置式 PID → 非负 PWM(方向独立设定)
- 复用 lesson9
bsp_pid.c/h、lesson10 FreeMASTER(PID 参数)、VOFA+ 三通道波形(SP/ACT/PWM) - 保留 lesson6/7 过流、堵转保护
- 串口命令:
c [mA]设目标、s 1/0启停闭环、cal零偏重校准、kp/ki/kd调参
2.2 硬件说明
与 lesson4 / lesson6 / lesson11 完全相同:野火骄阳 F407 + 无刷驱动板 + 带霍尔 BLDC,推荐 「无刷电机驱动接口 2」 牛角排线。电流采样在驱动板完成,经排线到 MCU ADC3。
三、程序设计
3.1 目录与模块划分
在 lesson12 基础上,位置环应用层 改为电流环:
User/
├── adc/
│ └── bsp_adc.c/h # 三相电流、零偏校准、get_curr_val_max()
├── pid/
│ ├── bsp_pid.c/h # 复用 lesson9
│ └── bsp_pid_app.c/h # 电流环:读电流、调 PWM、串口/FreeMASTER
├── freemaster/
│ └── bsp_fm_vars.h # g_fm_target_curr、g_fm_curr_loop_en 等
└── main.c
3.2 电流环数据流
每 25 ms(curr_pid_poll):
1. actual_ma = get_curr_val_max() /* 校准未完成时 ACT 为 0 */
2. error = target_ma - actual_ma
3. 若 target_ma < CURR_PID_STOP_MA:停 PWM、清积分,return
4. 若 !adc_curr_is_calibrated():不输出 PWM
5. out = pid_update(&g_fm_pid, target_ma, actual_ma)
6. 大误差起转 + 限幅 + 斜坡 → set_bldcm_speed(duty)
与野火有刷电流环一致:PID 输出只映射占空比,不通过 PID 符号换向。
3.3 核心代码示例
3.3.1 头文件常量
/* bsp_pid_app.h — 电流环 */
#define CURR_PID_TARGET_INIT 1500.0f /* 默认 1.5 A */
#define CURR_PID_LOOP_MS 25U
#define CURR_PID_DT 0.025f
#define CURR_PID_STOP_MA 50.0f
#define CURR_PID_BOOT_ERR_MA 300.0f /* 误差大时起转最小占空比 */
#define CURR_PID_BOOT_MIN_DUTY 800U
#define CURR_PID_PWM_MAX_STEP 250U
#define CURR_PID_KP_INIT 0.0f /* 参考野火有刷电流环 */
#define CURR_PID_KI_INIT 3.5f
#define CURR_PID_KD_INIT 0.0f
3.3.2 单次电流环计算
static void curr_pid_control(void)
{
float cont_val;
curr_pid_refresh_current(); /* 更新 g_fm_actual_curr / U/V/W */
if (g_fm_target_curr < CURR_PID_STOP_MA)
{
set_bldcm_speed(0U);
set_bldcm_disable();
pid_reset(&g_fm_pid);
return;
}
cont_val = pid_update(&g_fm_pid, g_fm_target_curr, g_fm_actual_curr);
if (!adc_curr_is_calibrated())
return; /* 零偏未校完,不输出 */
curr_pid_apply_output(cont_val);
3.3.3 输出执行
static void curr_pid_apply_output(float cont_val)
{
/* out ≥ 0;大误差时 duty 不低于 CURR_PID_BOOT_MIN_DUTY(克服静摩擦) */
/* 闭环运行期间勿每周期 bldcm_apply_state(0) 关驱动,与 lesson11 一致 */
set_bldcm_speed(duty);
}
3.3.4 零偏校准(bsp_adc.c)
#define ADC_CURR_CAL_SETTLE_MS 800U /* 上电稳定等待 */
#define ADC_CURR_CAL_SAMPLES 64U /* 64 次均值锁偏置 */
void adc_curr_recalibrate(void); /* s 0 / cal 时调用 */
uint8_t adc_curr_is_calibrated(void); /* 三相均 cal_done 才为 1 */
3.4 PID 参数与限幅建议
| 项目 | 建议初值 | 说明 |
|---|---|---|
| 目标 SP | 1500 mA(1.5 A) | 空载起步;可试 800~2500 mA |
out_min / out_max |
0 / ~5500 | 与 lesson4 一致 |
integral_max |
5500 | 与 PWM 满量程同量级 |
dt |
0.025f | 与 25 ms 周期一致 |
| Kp / Ki / Kd | 0 / 3.5 / 0(野火有刷官方) | 不能照搬 lesson11/12 参数 |
| SP 上限 | 6000 mA | 低于软件过流 8000 mA |
电流环与速度/位置环调参差异:
- 官方电流环常 Kp=0、靠 Ki 消除静差;
- 电流响应快,周期宜 25 ms(比速度环 50 ms 更短);
- ACT 噪声较大,波形不必追求完全平滑,看 趋势跟随 即可。
3.5 与 lesson11/12 的接口对照
| lesson11 速度环 | lesson12 位置环 | lesson13 电流环 |
|---|---|---|
g_fm_target_rpm |
g_fm_target_pos |
g_fm_target_curr |
motor_hall_get_rpm() |
motor_hall_get_position() |
get_curr_val_max() |
speed_pid_control() |
pos_pid_control() |
curr_pid_control() |
g_fm_speed_loop_en |
g_fm_pos_loop_en |
g_fm_curr_loop_en |
串口 t [rpm] |
串口 p [pos] |
串口 c [mA] |
| PID 输出带符号(正反转) | PID 输出带符号 | PID 输出仅 PWM 幅值 |
四、FreeMASTER 与串口调参
4.1 FreeMASTER 监视变量
| 符号 | 类型 | 含义 |
|---|---|---|
g_fm_target_curr |
float | 目标电流 SP(mA) |
g_fm_actual_curr |
float | 反馈电流 ACT(三相 max,mA) |
g_fm_iu_ma / iv / iw |
float | 三相电流分量 |
g_fm_error |
float | SP − ACT |
g_fm_pid.output |
float | PID 总输出 |
g_fm_pid.p_term / i_term / d_term |
float | P / I / D 分项 |
g_fm_pwm_out |
float | 实际 PWM 占空比 |
g_fm_vbus_v |
float | 母线电压 (V) |
g_fm_curr_loop_en |
float | 1.0=闭环开,0.0=关 |
g_fm_protect_en |
float | 过流+堵转保护开关 |
g_fm_fault_code |
float | 0/1/2 故障码 |
Scope 建议:g_fm_target_curr、g_fm_actual_curr、g_fm_pwm_out 三曲线同屏。
4.2 VOFA+ FireWater
VOFA+ 只输出过程量波形,便于观察电流跟随;PID 输出分项(OUT/P/I/D)及 Kp/Ki/Kd 请用 FreeMASTER,避免串口带宽被占满。
| 通道 | 含义 |
|---|---|
| ch0 | 目标电流 SP(g_fm_target_curr,mA) |
| ch1 | 反馈电流 ACT(g_fm_actual_curr,mA) |
| ch2 | 实际 PWM(g_fm_pwm_out) |
115200、协议 FireWater、3 通道。
4.3 串口命令
| 命令 | 作用 | 示例 |
|---|---|---|
c [mA] |
设置目标电流 | c 1500 |
c +200 / c -200 |
相对当前目标 ±200 mA | c +200 |
kp / ki / kd |
修改 PID | ki 3.5 |
s 1 / s 0 |
启 / 停电流闭环 | s 1 |
pid |
打印 SP/ACT/PWM/cal/fault | pid |
r |
清积分 | r |
cal |
电流零偏重新校准(须 s 0、电机停转) |
cal |
? |
帮助 | ? |
v [pwm] |
开环 PWM(须 s 0) |
v 500 |
d [0|1] |
开环方向(须 s 0) |
d 0 |
cal 说明:电机 必须停转(s 0),否则零偏会按「有电流」去校,ACT 仍虚高。cal 后约 2 s 内 pid 应显示 cal=1,ACT/U/V/W≈0。
启闭环:须 s 1 或 g_fm_curr_loop_en=1.0;只改 g_fm_target_curr 不会自动启电机。
闭环中:K3/K4 目标电流 ±200 mA;开环中:K1/K2 调 PWM,K3/K4 换向。
五、主程序流程
5.1 初始化
- 时钟、LED、串口、ADC(
ADC_Init内adc_curr_recalibrate()) bldcm_init():TIM8 PWM、TIM5 霍尔curr_pid_init():默认 SP=1500 mA、Kp=0 Ki=3.5 Kd=0、闭环关- 上电后 约 2 s 内勿启电机,等零偏
cal=1 - 默认 不使能电机,等待
s 1
5.2 主循环
while (1)
{
deal_curr_pid_serial_data();
deal_key_input();
motor_protect_sync();
curr_pid_poll(); /* 25 ms 电流环 */
motor_stall_poll();
motor_hall_speed_poll();
motor_overcurrent_poll();
curr_pid_vofa_poll();
}
六、建议操作与 PID 整定
安全提示:首次闭环请 空载、小目标(如 800~1500 mA),手勿靠近转子;过流或振动大时立即
s 0。
6.1 推荐操作流程(含零偏)
① 烧录 → ② 上电等 3 s(零偏自动校准)→ ③ pid 看 cal=1、ACT≈0
④ s 0 → v 800 确认开环能转 → ⑤ r → ⑥ c 1500 → ⑦ d 0 → ⑧ s 1
⑨ 看 ACT 趋势逼近 SP → ⑩ 调 Ki
若 停转 ACT 仍 7000+:
s 0 → cal → 等 2 s → pid(须 cal=1、ACT≈0)→ 再 v 800 或 s 1
| 步骤 | 操作 | 目的 |
|---|---|---|
| 1 | 烧录 lesson13,FreeMASTER 加载 .axf |
确认变量符号 |
| 2 | 上电 等 3 s,pid 或 Watch g_fm_* |
cal=1,ACT/U/V/W≈0 |
| 3 | s 0,v 800 开环慢转 |
确认硬件能转、运行时有电流 |
| 4 | s 0 → cal → 等 2 s(若步骤 2 未通过) |
零偏重校准 |
| 5 | r |
清积分 |
| 6 | c 1000 或 c 1500 |
小目标起步 |
| 7 | d 0 |
确认转向 |
| 8 | s 1 |
启电流闭环 |
| 9 | VOFA+ / FreeMASTER 看 SP、ACT、PWM | ACT 有纹波正常,看 均值趋势 |
| 10 | 调 ki |
见下文 |
6.2 FreeMASTER 读数速查
| 读数 | 含义 | 处理 |
|---|---|---|
| ACT≈7000,SP=2000,ERR 负,OUT=0 | 零偏错误,以为电流已过大 | cal,见 §1.6.2 |
| cal=0 | 仍在校准 | 等 ~2 s,勿 s 1 |
| ACT 0~几百跳动,SP=1500 | 六步纹波 + I 环爬升 | 正常,见 §1.6.3 |
| fault=1 | 堵转 | s 0 → r → 降 SP 再试 |
| fault=2 | 过流 | 降 SP/Ki;查 ACT 是否虚高 |
6.3 阶跃响应现象
理想波形:
- 启环瞬间:ACT 低于 SP → PWM 上升,电流增大;
- 接近目标:误差减小 → PWM 稳定在某个占空比;
- 改 SP:K3/K4 或
c命令阶跃,ACT 先冲再稳(可能略有 overshoot)。
若 ACT 长期低于 SP:Ki 偏小 → 加大 Ki。
若 ACT 振荡:Ki 过大 → 减小 Ki 或略加 Kp/Kd。
若 波形毛刺多、ACT 在 100~600 mA 跳:六步换相 正常现象(§1.6.3);看 均值趋势 即可。
6.4 推荐起步参数
| 参数 | 起步值 | 说明 |
|---|---|---|
| Kp | 0 | 野火有刷电流环官方 |
| Ki | 2.8~3.5 | 消除静差主力 |
| Kd | 0 | 一般不加 |
| 目标 SP | 1000~1500 mA | 空载 1~1.5 A |
| 周期 | 25 ms | 与 CURR_PID_DT 一致 |
6.5 分步调参
只加 I: r → kp 0 → kd 0 → ki 1.0 → c 1200 → s 1,逐步加大 Ki 直到 ACT 能跟上 SP 且不过冲严重。
可选 P: 若 Ki 已较大仍响应慢,可小 Kp(如 0.5~2.0)试加快。
6.6 常见现象
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 停转 ACT≈7000,电机不转 | 零偏过早/错误锁定 | s 0 → cal → 等 2s → pid 看 cal=1、ACT≈0 |
s 1 打印成功但不转,OUT=0 |
ACT 虚高 → ERR 为负 | 同上;或 g_fm_protect_en、fault |
v 800 也不转 |
未使能/霍尔/过流;或 ACT 虚高近 8A | 先 cal;再查开环与接线 |
| 能转,ACT 100~600 跳动 | 六步换相脉动 | 正常(§1.6.3);均值低于 SP 可略加 Ki |
| ACT 均值长期远低于 SP | Ki 偏小 | ki 4~6 试,或略加 Kp |
| 启环后电流上冲过流 | SP 过大或 Ki 过大 | 降低 SP;s 0 后 r |
| 换向后电流不对 | 方向与 SP 未重配 | 先 s 0 再 d 换向后 s 1 |
| FreeMASTER 启环无效 | g_fm_curr_loop_en 用了 uint8 |
必须为 float 4 字节 |
6.7 运行效果

七、本章小结
- 电流环 = 以 ADC 相电流(mA) 为反馈、PWM 幅值 为输出的单环 PID;方向 独立设定。
- 反馈取
get_curr_val_max();须先完成 零偏校准(cal=1),停转 ACT 应≈0,否则 ERR 为负、电机不转。 cal/s 0可触发adc_curr_recalibrate();上电或校准后 约 2 s 再启环。- 运行中 ACT 几百 mA 脉动 属六步换相正常现象,看 趋势 不调波形毛刺。
- 电流环宜 Kp=0、Ki≈3.5 起步;与 lesson11/12 参数完全不能互换。
- 启闭环须
g_fm_curr_loop_en=1.0或s 1;SP 建议不超过 6000 mA。
参考:野火《电机应用开发实战指南》「直流电机电流环控制」、BLDC 双环/串级说明;
源码: https://gitee.com/xundh/learn-motor-stm32
更多推荐

所有评论(0)