1. 项目概述
在工业自动化和机器人控制领域,步进电机的精确控制一直是核心技术难题。最近我在一个3D打印机项目中遇到了多轴协同运动的需求,于是基于STM32F103C8T6开发了一套4轴步进电机控制系统。这个系统最核心的特点是实现了每轴独立的梯形加减速控制,解决了传统步进电机直接启停导致的失步和振动问题。
这个项目最让我自豪的是,在72MHz主频的STM32上实现了4轴独立控制,每轴的脉冲生成误差小于1微秒。系统支持位置控制(通过脉冲数)和速度控制(通过脉冲频率),可以灵活应用于CNC雕刻机、机械臂等各种需要精密运动控制的场景。
2. 硬件设计
2.1 核心组件选型
选型时我主要考虑了性价比和实际需求。主控选择了经典的STM32F103C8T6,这款Cortex-M3内核的MCU虽然不算高端,但72MHz主频和丰富的外设完全能满足需求。它的4个定时器通道正好对应4个步进电机轴,硬件资源利用率很高。
步进电机驱动模块我选用了A4988,这款驱动芯片支持最高1/16微步,内置MOSFET和过流保护,价格也很亲民。实际测试中,它在12V供电下可以稳定驱动42步进电机,发热量也在可控范围内。
注意:电机电源和MCU电源一定要分开供电!我在初期测试时曾尝试共用电源,结果电机启动时的电流波动导致MCU频繁复位。后来改用独立的12V/5A和5V/1A电源后问题完全解决。
2.2 硬件连接设计
硬件连接上我充分利用了STM32的定时器资源。4个轴的脉冲信号分别使用TIM2的4个通道(PA0-PA3),方向信号则使用PB0-PB3。这种设计既保证了脉冲生成的精确性,又简化了软件实现。
具体引脚分配如下:
- 轴1:PA0(TIM2_CH1)脉冲,PB0方向
- 轴2:PA1(TIM2_CH2)脉冲,PB1方向
- 轴3:PA2(TIM2_CH3)脉冲,PB2方向
- 轴4:PA3(TIM2_CH4)脉冲,PB3方向
状态指示LED接在PC13,这个引脚在Blue Pill开发板上已经接了LED,方便调试。
3. 软件设计
3.1 开发环境搭建
我使用STM32CubeIDE作为开发环境,版本1.13.0。这个IDE集成了STM32CubeMX配置工具和Eclipse开发环境,可以自动生成初始化代码,大大提高了开发效率。
HAL库版本选择了STM32Cube_FW_F1_V1.8.0。虽然LL库效率更高,但HAL库的封装更好,开发速度更快。对于这个项目来说,HAL库的性能已经足够。
3.2 梯形加减速算法实现
3.2.1 数学模型
梯形加减速算法的核心是将运动过程分为三个阶段:
- 加速阶段:脉冲间隔从Tmax线性减小到Tmin
- 匀速阶段:脉冲间隔保持Tmin不变
- 减速阶段:脉冲间隔从Tmin线性增大到Tmax
加速度a的计算公式为:
a = (Tmax - Tmin) / (2 * Na)
其中Na是加速步数。
3.2.2 脉冲生成机制
脉冲生成使用了定时器的输出比较模式。通过动态修改CCR寄存器值来改变脉冲频率,具体实现如下:
- 初始化定时器,预分频设置为71,将72MHz时钟分频为1MHz(每计数1次=1μs)
- 设置ARR为999,初始频率1kHz
- 在中断服务函数中动态更新CCR值,实现频率调整
这种方法的优点是精度高,实测脉冲间隔误差小于1μs。
3.3 工程代码结构
工程采用模块化设计,主要文件包括:
code复制├── Core/
│ ├── Inc/
│ │ ├── stepper.h // 步进电机控制核心
│ │ ├── timer.h // 定时器配置
│ │ └── uart.h // 串口调试
│ ├── Src/
│ │ ├── main.c // 主程序
│ │ ├── stepper.c // 加减速算法
│ │ ├── timer.c // 定时器实现
│ │ └── uart.c // 串口打印
├── Drivers/ // HAL库驱动
└── STM32F103C8Tx_FLASH.ld // 链接脚本
3.4 核心代码解析
3.4.1 轴参数结构体
在stepper.h中定义了轴参数结构体:
c复制typedef struct {
TIM_HandleTypeDef *htim; // 定时器句柄
uint32_t channel; // 定时器通道
GPIO_TypeDef *dir_port; // 方向端口
uint16_t dir_pin; // 方向引脚
int32_t target_steps; // 目标步数
int32_t current_steps; // 当前步数
uint32_t max_speed; // 最大速度(Hz)
uint32_t acceleration; // 加速度(Hz/s)
uint32_t pulse_interval; // 当前脉冲间隔(μs)
uint32_t min_interval; // 最小间隔(μs)
uint32_t max_interval; // 最大间隔(μs)
uint8_t state; // 状态(0:停止,1:加速,2:匀速,3:减速)
uint32_t step_count; // 当前阶段步数
uint32_t total_steps; // 总步数
uint32_t accel_steps; // 加速步数
uint32_t decel_steps; // 减速步数
} Stepper_TypeDef;
3.4.2 加减速逻辑实现
stepper.c中的关键函数是Stepper_Update,它实现了梯形加减速的状态机:
c复制void Stepper_Update(Stepper_TypeDef *ax) {
if (ax->state == 0) return;
// 加速阶段
if (ax->state == 1) {
ax->step_count++;
ax->pulse_interval = ax->max_interval - (ax->acceleration * ax->step_count * 1000) / (2 * ax->max_speed);
if (ax->pulse_interval <= ax->min_interval || ax->step_count >= ax->accel_steps) {
ax->state = 2; // 切换到匀速
ax->step_count = 0;
ax->pulse_interval = ax->min_interval;
}
}
// 匀速阶段
else if (ax->state == 2) {
ax->step_count++;
if (ax->current_steps + ax->step_count >= ax->total_steps - ax->decel_steps) {
ax->state = 3; // 切换到减速
ax->step_count = 0;
}
}
// 减速阶段
else if (ax->state == 3) {
ax->step_count++;
ax->pulse_interval = ax->min_interval + (ax->acceleration * ax->step_count * 1000) / (2 * ax->max_speed);
if (ax->step_count >= ax->decel_steps) {
ax->state = 0; // 停止
ax->pulse_interval = 0;
}
}
// 设置方向
HAL_GPIO_WritePin(ax->dir_port, ax->dir_pin, (ax->target_steps > 0) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
4. 关键问题与解决方案
4.1 脉冲频率精度问题
最初我尝试用PWM模式生成脉冲,但发现频率调整不够灵活。后来改用输出比较模式,通过动态修改CCR值,实现了μs级的精度控制。具体实现是在定时器中断中更新CCR值:
c复制void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
for (int i=0; i<4; i++) {
if (axis[i].htim == htim && axis[i].state != 0) {
__HAL_TIM_SET_COMPARE(htim, axis[i].channel, axis[i].pulse_interval);
Stepper_GeneratePulse(&axis[i]);
}
}
}
}
4.2 多轴控制冲突
由于4个轴共用TIM2定时器,初期出现了脉冲互相干扰的问题。解决方案是为每个通道独立设置CCR值,并在中断中区分处理。实测表明,这种方法在72MHz主频下完全能满足4轴的实时性要求。
4.3 加减速平滑性
梯形加减速在阶段切换时会有加速度突变,导致电机轻微振动。我尝试过S形加减速,但计算量太大,在STM32F103上实现困难。最终采用了一个折中方案:在阶段切换时插入几个过渡步,使加速度变化更平滑。
5. 测试与验证
测试分为三个阶段:
- 单轴基本功能测试:
- 设置目标步数1000,观察电机转动
- 用示波器测量脉冲频率变化
- 验证位置精度
- 多轴协同测试:
- 同时控制4轴运动
- 测试各轴独立性
- 测量最大同步误差
- 长时间稳定性测试:
- 连续运行8小时
- 监测温升和位置漂移
- 记录异常情况
测试结果表明,系统在2000Hz最大速度下,位置误差小于±1步,完全满足设计要求。
6. 性能优化技巧
在实际使用中,我总结了几条优化经验:
-
中断优化:将脉冲生成和状态更新分开,脉冲生成在定时器中断中处理,状态更新在主循环中处理,减少中断处理时间。
-
速度规划:对于短距离移动,自动降低最大速度,避免还没加速到最高速就要减速的情况。
-
动态调整:根据负载情况自动调整加速度参数,重载时降低加速度,避免失步。
-
空闲降频:电机停止时降低定时器频率,减少功耗。
这个项目最让我满意的是它的实用性。代码已经成功应用在3D打印机和一个小型CNC平台上,运行稳定可靠。虽然STM32F103的性能有限,但通过精心设计和优化,完全可以满足大多数步进电机控制的需求。
