物理直觉:对直流电机,转矩 ∝ 电流。控住电流就等于控住「电机的力气」,这是后续三环控制里最内环的基石。

其中 $\overline{ADC}$ 是电流通道滤波后的当前均值,$ADC_{ref}$ 是上电时(电机未转)测得的零点参考值,ADC2CURT 是「ADC 数值 → 电流(mA)」的换算系数。先减零点再乘系数,电流才算得干净。
采集链路:20mΩ 采样电阻 → 差分放大 6 倍 + 1.27V 偏置(第 6 章的电路)→ ADC1 通道 8(PB0)→ DMA 循环搬运。程序里做了三级平均 + 两道整形:
| 层级 | 做法 | 目的 |
|---|---|---|
| 一级 | 单次多通道采样取平均 | 去单点毛刺 |
| 二级 | 累计 15 次再平均 | 压随机噪声 |
| 三级 | 上电累计 16 次平均 → 存为零点参考 | 标定 ADC 零点 |
/* 采完参考值后,每轮计算一次电流 */
temp_c = (add_adc - init_adc_value) * ADC2CURT; /* 换算电流 */
/* 一阶低通:60% 旧值 + 40% 新值,波形更平滑 */
g_motor_data.current = g_motor_data.current * 0.60f + 0.40f * temp_c;
if (g_motor_data.current <= 20) /* ≤20mA 视为微弱浮动 */
g_motor_data.current = 0.0; /* 直接清零 */电流环参数:位置式 KP=10.0、KI=7.0、KD=2.0(增量式 0.0/6.0/4.0),采样周期 50ms,结构体 g_current_pid。初始目标电流设为 40mA——太小了电机根本转不起来。
/* TIM6 更新中断:50ms 算一次电流环 PID */
if (val % SMAPLSE_PID_SPEED == 0) {
if (g_run_flag) {
motor_pwm_temp = increment_pid_ctrl(&g_current_pid,
g_motor_data.current);
/* PID 输出再做一次低通(0.5/0.5),占空比不突变 */
g_motor_data.motor_pwm = (int32_t)((g_motor_data.motor_pwm * 0.5)
+ (motor_pwm_temp * 0.5));
if (g_motor_data.motor_pwm >= 8200) /* 上限 */
g_motor_data.motor_pwm = 8200;
else if (g_motor_data.motor_pwm <= 0) /* 下限是 0,不是 -8200 */
g_motor_data.motor_pwm = 0;
motor_pwm_set(g_motor_data.motor_pwm);
}
val = 0;
}
val++;按键:KEY0 目标电流 +20mA(上限 120mA),KEY1 −20mA(小于 60mA 自动停机并重置 PID),KEY2 立即停机。
