1. 项目概述与硬件基础
这次要分享的是一个基于STM32G0系列MCU的步进电机电流闭环控制系统。整套方案包含24V/1.75A规格的开发板,搭配1.8°步距角的步进电机,通过DRV8841驱动芯片实现精确控制。最核心的创新点在于软件层面实现了电流环参数的自动计算,这在工业控制领域具有很高的实用价值。
开发板采用ST的STM32G0系列MCU作为主控,64MHz的主频为16kHz的PWM和电流环计算提供了充足的算力。TI的DRV8841驱动芯片内置H桥和电流检测功能,配合开发板上的母线电压、相电流采样电路,构成了完整的硬件闭环。电机参数方面,7Ω的相电阻和2mH的电感量决定了控制算法的响应特性。
提示:选择DRV8841驱动芯片时要注意其1.75A的持续输出电流需留出至少30%余量,避免长时间满负荷运行导致过热。
2. 控制系统架构设计
2.1 电流环控制原理
电流闭环控制的核心是通过PI调节器使实际电流快速跟踪设定值。在步进电机控制中,这能有效抑制失步和振动。系统采用16kHz的PWM频率,与电流环计算频率保持一致,确保控制实时性。
PI参数的自动计算基于电机电气参数:
- Kp = L / (Ts * R)
- Ki = 1 / (Ts * R)
其中L=2mH,R=7Ω,Ts=62.5μs(1/16kHz)。代入计算得:
c复制float Ts = 0.0000625; // 16kHz周期
float L = 0.002; // 2mH
float R = 7.0; // 7Ω
Kp = L / (Ts * R); // 约4.57
Ki = 1 / (Ts * R); // 约2285.7
2.2 软件架构实现
Keil工程采用分层设计:
- 硬件抽象层(HAL):处理GPIO、定时器、ADC等外设
- 驱动层:封装DRV8841操作接口
- 算法层:实现电流环PI控制
- 应用层:处理Modbus通信和模式切换
关键代码结构:
c复制// 电流环控制结构体
typedef struct {
float Kp;
float Ki;
float I_ref;
float I_meas;
float err_sum;
} CurrentLoop_t;
// 位置控制结构体
typedef struct {
int32_t target_pos;
int32_t current_pos;
uint16_t speed;
} PositionCtrl_t;
3. 核心功能实现细节
3.1 自动调参实现
电流环参数自动计算通过以下函数实现:
c复制void CurrentLoop_AutoTune(CurrentLoop_t *loop) {
// 获取电机参数(实际项目中可能通过EEPROM或通信获取)
Motor_Params_t params = Motor_GetParams();
// 计算PI参数
loop->Kp = params.L / (CONTROL_PERIOD * params.R);
loop->Ki = 1.0f / (CONTROL_PERIOD * params.R);
// 限制积分项最大值
loop->err_sum_max = MAX_CURRENT / loop->Ki;
}
注意:实际应用中需要加入参数有效性检查,避免除零错误或异常值。
3.2 PWM配置关键点
使用TIM1产生16kHz PWM的配置要点:
- 时钟配置:64MHz主频,不分频
- 自动重载值:ARR = (64MHz/16kHz) - 1 = 3999
- 死区时间:根据DRV8841规格建议设置约500ns
具体实现:
c复制void PWM_Init(void) {
TIM_TimeBaseInitTypeDef TIM_BaseStruct;
TIM_BaseStruct.TIM_Prescaler = 0;
TIM_BaseStruct.TIM_Period = 3999;
TIM_BaseStruct.TIM_ClockDivision = 0;
TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_BaseStruct);
// 配置PWM通道...
// 设置死区时间...
}
3.3 电流采样处理
电流采样采用同步采样技术:
- PWM中点触发ADC采样
- 使用硬件滤波器:RC时间常数≈1μs
- 软件端采用移动平均滤波
ADC配置示例:
c复制void ADC_Config(void) {
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC4;
ADC_Init(ADC1, &ADC_InitStruct);
}
4. 控制模式实现
4.1 位置控制算法
位置模式采用梯形速度曲线:
c复制void PositionCtrl_Update(PositionCtrl_t *ctrl) {
// 计算位置误差
int32_t err = ctrl->target_pos - ctrl->current_pos;
// 生成梯形速度曲线
if(abs(err) > ACCEL_DISTANCE) {
ctrl->speed = MIN(ctrl->speed + ACCEL_RATE, MAX_SPEED);
} else {
ctrl->speed = MAX(ctrl->speed - DECEL_RATE, 0);
}
// 转换为电流设定值
CurrentLoop_SetReference(ctrl->speed * SPEED_TO_CURRENT_RATIO);
}
4.2 速度控制实现
速度环采用PI控制:
c复制void SpeedCtrl_Update(float target_speed) {
static float speed_integral = 0;
float current_speed = Encoder_GetSpeed();
float err = target_speed - current_speed;
speed_integral += err * SPEED_KI;
speed_integral = constrain(speed_integral, -MAX_INTEGRAL, MAX_INTEGRAL);
float current_ref = err * SPEED_KP + speed_integral;
CurrentLoop_SetReference(current_ref);
}
5. Modbus通信实现
5.1 协议栈配置
使用FreeMODBUS协议栈的移植要点:
- 串口配置:115200bps,8N1
- 定时器用于RTU帧间隔检测
- 保持寄存器映射控制参数
初始化代码:
c复制void Modbus_Init(void) {
// 串口初始化
USART_Init(USART1, 115200, USART_Mode_Tx|USART_Mode_Rx);
// 定时器初始化(3.5字符时间)
TIM_Config(35 * 1000000 / 115200);
// 寄存器映射
modbus_registers[MODBUS_POS_REG] = (uint16_t*)&target_position;
}
5.2 上位机交互设计
C# WinForm程序关键功能:
- 参数实时监控曲线
- 控制模式切换界面
- 参数保存/加载功能
通信线程示例:
csharp复制private void CommThread() {
while(!stopThread) {
// 读取保持寄存器
ushort[] regs = modbus.ReadHoldingRegisters(slaveId, startAddr, count);
// 更新UI
this.Invoke(new Action(() => {
txtPosition.Text = regs[0].ToString();
// ...
}));
}
}
6. 调试经验与问题排查
6.1 常见问题速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 电机抖动 | PI参数不合适 | 重新自动调参或手动调整 |
| 电流波动大 | 采样不同步 | 检查PWM触发ADC的时机 |
| Modbus通信失败 | 波特率不匹配 | 检查两端串口配置 |
| 电机发热严重 | 电流环响应慢 | 提高PWM频率或优化算法 |
6.2 实测优化技巧
- 电流采样校准:在零电流状态下读取ADC值作为偏置
- 死区补偿:根据实际测量调整死区时间
- 参数保存:将调好的参数存入Flash,避免每次上电重新调参
EEPROM存储示例:
c复制void Params_Save(void) {
FLASH_Unlock();
FLASH_ProgramWord(PARAMS_ADDR, *(uint32_t*)¤t_params);
FLASH_Lock();
}
7. 性能优化方向
- 采用FOC算法替代传统PWM控制
- 加入前馈补偿提高动态响应
- 实现参数自学习功能
- 支持CAN总线通信
前馈补偿实现示例:
c复制void CurrentLoop_UpdateWithFeedForward(CurrentLoop_t *loop, float feed_forward) {
float err = loop->I_ref - loop->I_meas;
loop->err_sum += err;
float output = err * loop->Kp + loop->err_sum * loop->Ki + feed_forward;
PWM_SetDuty(output);
}
这个项目从硬件选型到软件架构都经过精心设计,特别是在电流环自动调参和多种控制模式的实现上有很多创新点。在实际应用中,建议先进行电机参数识别,再开启自动调参功能,最后根据具体应用场景微调控制参数。