STM32F103CB + TMC2209
步进电机控制项目报告
基于 TIM2 PWM 硬件脉冲生成 + STEP/DIR 定频控制
MCU STM32F103CBT6 | 驱动芯片 TMC2209 |
系统时钟 72 MHz | 工具链 Keil MDK-ARM |
目录
1. 项目概述
2. 系统框图
3. 硬件设计 — 电路原理图与引脚分配
4. 软件架构设计
5. 主要参数情况
6. 实现步骤
7. 软件调试要点
8. 项目代码清单
9. 如何开启运行
1. 项目概述
本项目基于 STM32F103CBT6 微控制器和 Trinamic TMC2209 步进电机驱动芯片,实现步进电机的定频脉冲运动控制。系统采用 STEP/DIR 接口模式,通过 STM32 硬件定时器 (TIM2) 生成精确的 PWM 脉冲信号驱动 TMC2209,支持多档微步细分切换和正反转控制。
核心特性
· 硬件脉冲生成:TIM2 CH1 PWM 输出 STEP 脉冲,1μs 脉宽,频率可达 300,000 Hz
· 多档微步:支持 1/8、1/16、1/32、1/64 四种细分模式,通过 MS1/MS2 引脚切换
· 精确步数控制:TIM2 更新中断计数,到达目标步数自动停止
· 方向控制:DIR 引脚电平切换正反转
· 使能管理:ENN 低有效,支持驱动使能/失能
· 位置追踪:维护有符号绝对位置计数器
· 预留串口:USART1 (115200 8N1) 已配置,可扩展上位机通信
技术规格一览
MCU 型号 | STM32F103CBT6 (Cortex-M3, LQFP48) |
Flash / RAM | 128 KB / 20 KB |
系统时钟 | 72 MHz (HSE 8MHz × PLL9) |
驱动芯片 | TMC2209 (standalone STEP/DIR 模式) |
电机类型 | 两相四线步进电机,步距角 1.8° |
每转整步数 | 200 (360° / 1.8°) |
脉冲生成方式 | TIM2 CH1 PWM 硬件输出 |
脉冲宽度 | 1 μs (CCR1 = 72 @ 72MHz) |
频率范围 | 1,097 ~ 24,000,000 Hz (代码限速 1,100 ~ 300,000) |
HAL 固件版本 | STM32Cube FW_F1 V1.8.6 |
代码生成工具 | STM32CubeMX V6.15.0 |
IDE / 编译器 | Keil MDK-ARM V5.32, ARMCC V5.06 |
2. 系统框图
以下为系统总体架构框图,展示各功能模块之间的信号流向与连接关系:
┌─────────────┐ ┌──────────────────────────────────────────┐ ┌──────────────┐ │ HSE 晶振 │ │ STM32F103CBT6 │ │ TMC2209 │ │ 8 MHz │────────▶│ ┌────────┐ ┌──────────────┐ │ PA0 │ │ └─────────────┘ PD0 │ │PLL ×9 │ │ TIM2 CH1 │───────────│────────▶│ STEP ◀── │ PD1 │ │72 MHz │ │ PWM 脉冲 │ │ PA1 │ DIR ◀── │ ┌─────────────┐ │ └────────┘ │ ARR+CCR1=72 │ │────────▶│ ENN ◀── │ │ J-Link/SWD │ │ └──────────────┘ │ PA2 │ MS1 ◀── │ │ PA13/PA14 │────────▶│ ┌──────────────┐ ┌──────────┐ │────────▶│ MS2 ◀── │ └─────────────┘ │ │ GPIO │ │ NVIC │ │ PA3 │ │ ┌─────────────┐ │ │ DIR/ENN/MS │ │ TIM2_IRQ │ │────────▶│ A1 ── A+ │ │ 电源 │ │ └──────────────┘ └──────────┘ │ PA4 │ A2 ── A- │ │ 3.3V / 12V │────────▶│ ┌──────────────┐ │────────▶│ B1 ── B+ │ └─────────────┘ │ │ USART1 (预留)│ │ │ B2 ── B- │ │ └──────────────┘ │ └──────┬───────┘ └──────────────────────────────────────────┘ │ ▼ ┌──────────────┐ │ 步进电机 │ │ 1.8° 两相四线│ └──────────────┘ |
图 2-1 系统总体框图
数据流说明
信号路径 | 说明 |
HSE 8MHz → PLL ×9 → 72MHz | 系统时钟源,驱动 TIM2 定时器 (APB1×2 = 72MHz) |
TIM2 CH1 PWM → PA0 → TMC2209 STEP | 硬件生成精确脉冲,频率由 ARR 控制 |
GPIO PA1~PA4 → DIR/ENN/MS1/MS2 | 软件控制方向、使能、细分 |
TIM2 更新中断 → NVIC → Handler | 每个脉冲周期计数,到目标步数停止 |
TMC2209 → 电机线圈 A+/A-/B+/B- | 驱动芯片内部 H 桥输出电流驱动电机 |
J-Link SWD → STM32 | 程序烧录与在线调试 |
3. 硬件设计 — 电路原理图与引脚分配
3.1 电路连接原理图
┌─────────────────────────────┐ ┌──────────────────────────────┐ │ STM32F103CBT6 │ │ TMC2209 │ │ │ │ │ │ VDD ● │ ┌────▶│ STEP │ │ GND ● │ │ │ DIR │ │ PD0/OSC_IN ●───┐ │ │ │ ENN │ │ PD1/OSC_OUT ●──┤ Y1 8MHz │ PA0 ─────┤ │ MS1 │ │ └─── │ PA1 ─────┤ │ MS2 │ │ PA0/TIM2_CH1 ●─────────────┼───── │ │ │ │ PA1 ●─────────────┼──────────────┤ │ A1 ────── A+ (电机线圈A) │ │ PA2 ●─────────────┼──────────────┤ │ A2 ────── A- │ │ PA3 ●─────────────┼──────────────┤ │ B1 ────── B+ (电机线圈B) │ │ PA4 ●─────────────┘ │ │ B2 ────── B- │ │ │ │ │ │ │ PA9/USART1_TX ● (预留) │ │ │ VS ◀── 12V 电机供电 │ │ PA10/USART1_RX ● (预留) │ │ │ 5V_OUT (内部LDO) │ │ PA13/SWDIO ● (调试) │ │ │ GND ◀── 公共地 │ │ PA14/SWCLK ● (调试) │ │ │ │ └─────────────────────────────┘ │ └──────────────────────────────┘ │ │ │ ┌──────┴───────┐ └───────────│ 步进电机 │ │ 1.8°/200步/圈│ │ 两相四线 │ └──────────────┘ |
图 3-1 STM32 与 TMC2209 电路连接原理图
3.2 引脚分配表
STM32 引脚 | 功能 | TMC2209 引脚 | GPIO 模式 | 初始电平 | 说明 |
PA0 | TIM2_CH1 | STEP | AF_PP | — | PWM 脉冲输出,1μs 脉宽 |
PA1 | GPIO Output | DIR | PP | LOW | 方向:LOW=CW, HIGH=CCW |
PA2 | GPIO Output | ENN | PP | HIGH | 使能:LOW=使能, HIGH=失能 |
PA3 | GPIO Output | MS1 | PP | HIGH | 细分选择位 0 |
PA4 | GPIO Output | MS2 | PP | HIGH | 细分选择位 1 |
PA9 | USART1_TX | — | AF_PP | — | 串口发送 (预留) |
PA10 | USART1_RX | — | Input | — | 串口接收 (预留) |
PA13 | SWDIO | — | AF | — | SWD 调试接口 |
PA14 | SWCLK | — | AF | — | SWD 调试接口 |
PD0 | OSC_IN | — | — | — | HSE 外部晶振输入 |
PD1 | OSC_OUT | — | — | — | HSE 外部晶振输出 |
3.3 TMC2209 微步细分真值表
MS2 | MS1 | 细分 | 每转脉冲数 | 步距角 | |
LOW | LOW | 1/8 | 1,600 | 0.225° | |
LOW | HIGH | 1/32 | 6,400 | 0.05625° | |
HIGH | LOW | 1/64 | 12,800 | 0.028125° | |
HIGH | HIGH | 1/16 (默认) | 3,200 | 0.1125° | |
供电说明 TMC2209 的 VS 引脚接 12V 电机供电,内部 LDO 输出 5V 供逻辑使用。 STM32 使用独立 3.3V 供电,两者共地。 STEP/DIR/ENN/MS1/MS2 均为 3.3V 逻辑电平,TMC2209 兼容 3.3V 输入。 | |||||
4. 软件架构设计
4.1 分层架构
┌──────────────────────────────────────────────────────────────────────┐ │ 应用层 — main.c │ │ 演示循环: 遍历 8 种微步/速度配置, 正反转各 2 圈 │ └──────────────────────────────┬───────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ 运动控制层 — stepper.c / stepper.h │ │ TIM2 PWM 定频脉冲 + 更新中断步数计数 + 位置追踪 │ └──────────────────────────────┬───────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ 驱动 HAL 层 — tmc2209.c / tmc2209.h │ │ DIR 方向 / ENN 使能 / MS1+MS2 细分引脚控制 │ └──────────────────────────────┬───────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ STM32 HAL 库 (FW_F1 V1.8.6) │ │ HAL_GPIO · HAL_TIM (PWM) · HAL_UART · HAL_RCC · HAL_CORTEX │ └──────────────────────────────┬───────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ CMSIS Cortex-M3 + startup_stm32f103xb.s │ └──────────────────────────────────────────────────────────────────────┘ |
图 4-1 软件分层架构
4.2 时钟树配置
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ HSE │────▶│ PLL ×9 │────▶│ SYSCLK │────▶│ AHB /1 │ │ 8 MHz │ │ 72 MHz │ │ 72 MHz │ │ → APB2 /1 │ └──────────┘ └──────────┘ └──────────┘ │ = 72 MHz │ └──────────────┘ ┌──────────────┐ ┌───▶│ APB1 /2 │ │ │ = 36 MHz │ │ └──────┬───────┘ │ │ ×2 (自动) │ ▼ │ ┌──────────────┐ └────│ TIM2 │ │ = 72 MHz │ └──────────────┘
备注:APB1 预分频 = /2, 定时器时钟自动 ×2 → TIM2 = 72 MHz Flash 等待周期 = 2 (LATENCY_2) PWR 时钟使能, AFIO 时钟使能 (JTAG 禁用, 保留 SWD) |
图 4-2 STM32 时钟树配置
4.3 脉冲生成与中断机制
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ 1. Stepper_Move()│────▶│ 2. TIM2 PWM │────▶│ 3. 更新中断 │────▶│ 4. 步数计数 │ │ 计算 ARR │ │ PA0 输出脉冲 │ │ TIM2_IRQ │ │ step_count++ │ │ 设方向 │ │ CCR1=72 (1μs) │ │ 每周期触发 │ │ position+=dir │ │ 启动 PWM │ │ │ │ │ │ │ └──────────────────┘ └──────────────────┘ └──────────────────┘ └────────┬─────────┘ │ ┌────────────────────────────────────┘ ▼ ┌─────────────┐ 否 ┌──────────────┐ │ 到达目标? │───────────▶│ 继续 PWM │ └──────┬──────┘ └──────────────┘ 是 │ ▼ ┌──────────────────┐ │ 5. 停止 PWM │ │ 禁中断 │ │ complete=1 │ └──────────────────┘
主循环: while(!Stepper_IsComplete()) {} → 检测完成标志 → 进入下一次运动 |
图 4-3 脉冲生成与中断计数流程
4.4 TIM2 定时器配置详解
定时器时钟: 72 MHz (APB1 = 36 MHz, 定时器自动 ×2) 预分频 PSC: 0 (不分频) 计数模式: 向上计数 PWM 模式: PWM1 (CNT < CCR1 时输出高) ARR: 动态修改 = 72000000 / speed - 1 CCR1: 72 (固定, 1μs 脉冲宽度) ARR 预装载: 禁用 (即时生效) 中断: TIM_IT_UPDATE, 优先级 2
脉冲频率 f = 72MHz / (ARR+1) 脉冲周期 T = (ARR+1) / 72MHz 高电平时间 = CCR1 / 72MHz = 72 / 72MHz = 1μs |
5. 主要参数情况
5.1 电机与驱动参数
参数 | 值 | 说明 |
步距角 (整步) | 1.8° | 每整步旋转角度 |
每转整步数 | 200 | 360° / 1.8° = 200 |
电机类型 | 两相四线 | A+/A-/B+/B- 四线输出 |
驱动模式 | STEP/DIR standalone | 无 UART, 纯引脚控制 |
默认细分 | 1/16 | MS2=1, MS1=1 (上电默认) |
5.2 脉冲频率与转速关系
核心公式:f = RPM × 200 × microstep / 60 (Hz)
细分 | 每转脉冲数 | 50 RPM | 100 RPM | 150 RPM | 300 RPM | 600 RPM |
1/1 全步 | 200 | 167 Hz | 333 Hz | 500 Hz | 1,000 Hz | 2,000 Hz |
1/8 | 1,600 | 1,333 Hz | 2,667 Hz | 4,000 Hz | 8,000 Hz | 16,000 Hz |
1/16 | 3,200 | 2,667 Hz | 5,333 Hz | 8,000 Hz | 16,000 Hz | 32,000 Hz |
1/32 | 6,400 | 5,333 Hz | 10,667 Hz | 16,000 Hz | 32,000 Hz | 64,000 Hz |
1/64 | 12,800 | 10,667 Hz | 21,333 Hz | 32,000 Hz | 64,000 Hz | 128,000 Hz |
5.3 定时器约束参数
约束项 | 值 | 说明 |
TIM2 时钟频率 | 72,000,000 Hz | STEPPER_TIM_FREQ 宏定义 |
ARR 上限 | 65,535 | 16 位定时器寄存器上限 |
ARR 安全下限 | 200 | STEPPER_MIN_ARR, 防脉冲过窄 |
最小脉冲频率 | 1,097 Hz | 72MHz / 65536 ≈ 1098 Hz |
最大脉冲频率 | 24,000,000 Hz | 72MHz / 3 (ARR_MIN=200 时) |
代码限速下限 | 1,100 Hz | Stepper_Move() 内部保护值 |
代码限速上限 | 300,000 Hz | Stepper_Move() 内部保护值 |
脉冲宽度 | 1 μs | CCR1 = 72, 固定不变 |
5.4 演示程序配置表
主循环依次遍历以下 8 种配置,每种配置正转 2 圈 → 停 1s → 反转 2 圈 → 停 1s:
序号 | 细分 | 每转脉冲数 | 脉冲频率 (Hz) | 等效转速 (RPM) | 每次步数 (2圈) |
0 | 1/8 | 1,600 | 1,333 | 50 | 3,200 |
1 | 1/8 | 1,600 | 2,667 | 100 | 3,200 |
2 | 1/8 | 1,600 | 4,000 | 150 | 3,200 |
3 | 1/8 | 1,600 | 8,000 | 300 | 3,200 |
4 | 1/16 | 3,200 | 2,667 | 50 | 6,400 |
5 | 1/16 | 3,200 | 5,333 | 100 | 6,400 |
6 | 1/16 | 3,200 | 8,000 | 150 | 6,400 |
7 | 1/16 | 3,200 | 16,000 | 300 | 6,400 |
约束注意 全步模式下,低于 330 RPM 时脉冲频率 < 1100 Hz,ARR 超过 65535 导致 16 位定时器溢出。 解决方案 1:给 TIM2 加预分频 (PSC > 0) 降低时钟; 解决方案 2:切换到微步模式,同转速下脉冲频率按微步倍数提高。 | |||||
6. 实现步骤
1. STM32CubeMX 工程配置
在 STM32CubeMX V6.15.0 中选择 MCU 型号 STM32F103CBT6 (LQFP48)。配置 HSE 为外部晶振 8MHz,PLL 倍频 ×9 生成 SYSCLK 72MHz。APB1 预分频 /2 = 36MHz (TIM2 时钟自动 ×2 = 72MHz),APB2 = 72MHz。Flash 等待周期设为 2。
2. GPIO 引脚配置
配置 PA0 为 TIM2_CH1 复用推挽输出 (STEP 脉冲),PA1~PA4 为推挽输出 (DIR/ENN/MS1/MS2)。PA9/PA10 配置为 USART1_TX/RX (预留)。PA13/PA14 保留为 SWD 调试接口。在 MSP 初始化中禁用 JTAG,仅保留 SWD。
3. TIM2 PWM 定时器配置
配置 TIM2 为 PWM 模式 1,通道 1 输出。PSC=0 (不分频),ARR 初始值 1000 (后续动态修改)。CCR1=72 (1μs 脉冲宽度)。使能 TIM2 更新中断,NVIC 优先级设为 2。禁用 ARR 预装载以确保频率切换即时生效。
4. 生成代码框架
使用 STM32CubeMX 生成 Keil MDK-ARM V5.32 工程。生成内容包括:startup_stm32f103xb.s 启动文件、system_stm32f1xx.c 系统初始化、HAL 驱动库、外设初始化函数 (MX_GPIO_Init, MX_TIM2_Init, MX_USART1_UART_Init)、中断服务框架 (stm32f1xx_it.c)。
5. 编写 TMC2209 驱动层 (tmc2209.c/h)
定义引脚宏 (STEP/DIR/ENN/MS1/MS2 端口和引脚号)。实现方向枚举 (CW/CCW) 和微步枚举 (1/8, 1/16, 1/32, 1/64)。实现 TMC2209_Init() 初始化引脚状态 (ENN=HIGH 失能, DIR=LOW 顺时针, MS=1/16)。实现 apply_microstep_pins() 根据 MS2/MS1 真值表输出引脚电平。实现使能/失能/方向/细分设置函数及状态查询函数。
6. 编写运动控制层 (stepper.c/h)
定义 Stepper_t 结构体 (running/step_count/target_steps/position/direction/complete)。定义硬件常量 (TIM_FREQ=72MHz, PULSE_WIDTH=72, MIN_ARR=200, ARR_MAX=65535, MIN_SPEED=1097, MAX_SPEED=24000000)。实现 Stepper_Move(steps, dir, speed):速度保护→方向设置→ARR 计算→状态初始化→启动 PWM+中断。实现 Stepper_TIM2_IRQHandler():计数→位置更新→到达目标后停止。实现停止/状态查询/完成标志清除函数。
7. 编写主程序 (main.c)
定义微步/速度配置表 s_cfg_table[],包含 8 种组合 (1/8 和 1/16 各 4 档转速)。在 main() 中依次初始化 HAL→时钟→GPIO→TIM2→USART1→TMC2209→Stepper。使能驱动后进入主循环:取配置→设细分→正转 N 圈→等完成→停 1s→反转 N 圈→等完成→停 1s→切换下一配置。
8. 中断服务函数对接
在 stm32f1xx_it.c 中实现 TIM2_IRQHandler(),直接调用 Stepper_TIM2_IRQHandler()。该函数检查更新中断标志,清除标志后执行步数计数和完成判断。
9. 编译与烧录
在 Keil MDK-ARM 中编译工程 (ARMCC V5.06, -O1 优化, C99 模式)。使用 J-Link 通过 SWD 接口烧录 HEX 文件到 STM32F103CBT6。验证电机按预期正反转,观察不同微步/转速下的运行效果。
10. 调试与验证
通过 J-Link 在线调试,观察 s_stepper 结构体变量变化,验证步数计数和位置追踪。使用示波器测量 PA0 脉冲波形,确认脉冲频率和 1μs 脉宽。验证细分切换后电机运行精度。确认 ARR 在各种速度下不溢出 16 位范围。
7. 软件调试要点
7.1 调试环境
调试器 | J-Link (SWD 接口, PA13/PA14) |
IDE | Keil MDK-ARM V5.32 |
编译器优化 | -O1 (Level 1) |
调试信息 | 包含 (Debug 模式) |
Flash 烧录地址 | 0x08000000 (128KB) |
堆栈配置 | Stack 0x400 (1KB), Heap 0x200 (512B) |
7.2 关键调试变量
// 在 Keil Watch 窗口中监控以下变量: s_stepper.running // 1=运动中, 0=停止 s_stepper.step_count // 已完成步数 (递增) s_stepper.target_steps // 目标步数 s_stepper.position // 绝对位置 (有符号, 正负表示方向) s_stepper.direction // +1=CW, -1=CCW s_stepper.complete // 1=运动完成
// TMC2209 驱动状态: s_direction // 当前方向 s_enabled // 使能状态 s_microstep // 当前细分设置 |
7.3 常见问题与排查
现象 | 原因 | 排查方法 |
电机不转 | ENN 为高 (失能) | 检查 PA2 电平,确认 TMC2209_Enable() 已调用 |
电机抖动/堵转 | 脉冲频率过高或供电不足 | 降低 speed 参数,检查 12V 电源电流是否充足 |
步数不准 | 中断被更高优先级抢占 | 确认 TIM2 中断优先级 (2) 足够高,SysTick 为 15 |
ARR 溢出 | 低转速下 ARR > 65535 | 检查 speed 是否 >= 1100,或使用微步模式 |
细分切换异常 | 运动中切换 MS 引脚 | 确保在 Stepper_IsComplete() 后再切换细分 |
方向错误 | DIR 电平与预期相反 | 检查 TMC2209_SetDirection() 逻辑,CW=LOW, CCW=HIGH |
HardFault | 栈溢出或空指针 | 检查调用栈,Stack 最大使用 152B (配置 1024B) |
7.4 示波器验证要点
PA0 (STEP) 波形验证 使用示波器探头测量 PA0 引脚波形,验证: • 脉冲高电平宽度 = 1μs (CCR1=72 @ 72MHz) • 脉冲频率 = 配置表中的 speed 值 (如 1333 Hz, 2667 Hz 等) • 波形为标准方波,上升沿/下降沿陡峭 • 运动期间持续输出,停止后立即拉低 |
7.5 编译输出分析
输出文件 | TMC2209_SD_TEST.hex / .axf |
最大栈使用 | 152 字节 (配置 1024B, 使用率 15%) |
堆配置 | 512 字节 |
Flash 起始地址 | 0x08000000 |
RAM 起始地址 | 0x20000000 |
编译状态 | 0 Error, 0 Warning |
8. 项目代码清单
8.1 源文件结构
TMC2209_SD_TEST/ ├── TMC2209_SD_TEST.ioc # STM32CubeMX 配置文件 ├── keilkilll.bat # 编译清理脚本 │ ├── Core/ │ ├── Inc/ # 头文件目录 │ │ ├── main.h # 主头文件 (引脚宏定义) │ │ ├── tmc2209.h # TMC2209 驱动 HAL 层头文件 │ │ ├── stepper.h # 步进电机控制头文件 │ │ ├── stm32f1xx_it.h # 中断处理声明 │ │ └── stm32f1xx_hal_conf.h # HAL 库配置 │ │ │ └── Src/ # 源文件目录 │ ├── main.c # 主程序 (303行) │ ├── tmc2209.c # TMC2209 驱动实现 (97行) │ ├── stepper.c # 步进电机控制实现 (119行) │ ├── stm32f1xx_it.c # 中断服务函数 (213行) │ ├── stm32f1xx_hal_msp.c # HAL MSP 回调 (26行) │ └── system_stm32f1xx.c # CMSIS 系统初始化 │ ├── Drivers/ # HAL 驱动库 + CMSIS │ ├── CMSIS/ # ARM CMSIS 核心 + DSP + NN │ └── STM32F1xx_HAL_Driver/ # STM32F1 HAL 驱动源码 │ └── MDK-ARM/ # Keil 工程目录 ├── TMC2209_SD_TEST.uvprojx # Keil 工程文件 ├── startup_stm32f103xb.s # 启动汇编文件 ├── JLinkSettings.ini # J-Link 设置 └── TMC2209_SD_TEST/ # 编译输出 ├── TMC2209_SD_TEST.hex # HEX 烧录文件 ├── TMC2209_SD_TEST.axf # 可执行文件 └── TMC2209_SD_TEST.map # 内存映射表 |
8.2 核心代码 — tmc2209.c 驱动层
// TMC2209 细分引脚控制 — MS2/MS1 真值表 static void apply_microstep_pins(TMC2209_Microstep_t microstep) { GPIO_PinState ms1, ms2; switch (microstep) { case TMC2209_MICROSTEP_8: ms2=RESET; ms1=RESET; break; /* 1/8 */ case TMC2209_MICROSTEP_32: ms2=RESET; ms1=SET; break; /* 1/32 */ case TMC2209_MICROSTEP_64: ms2=SET; ms1=RESET; break; /* 1/64 */ case TMC2209_MICROSTEP_16: default: ms2=SET; ms1=SET; break; /* 1/16 */ } HAL_GPIO_WritePin(TMC2209_MS1_PORT, TMC2209_MS1_PIN, ms1); HAL_GPIO_WritePin(TMC2209_MS2_PORT, TMC2209_MS2_PIN, ms2); }
// 使能驱动 (ENN 低有效) void TMC2209_Enable(void) { HAL_GPIO_WritePin(TMC2209_EN_PORT, TMC2209_EN_PIN, GPIO_PIN_RESET); s_enabled = 1U; } |
8.3 核心代码 — stepper.c 运动控制
// 启动定频脉冲运动 int8_t Stepper_Move(uint32_t steps, uint8_t dir, uint32_t speed) { if (steps == 0U) { return -2; } if (s_stepper.running) { return -1; }
/* 速度保护 */ if (speed < MIN_SPEED) { speed = MIN_SPEED; } if (speed > MAX_SPEED) { speed = MAX_SPEED; }
/* 方向设置 */ if (dir == (uint8_t)TMC2209_DIR_CCW) { TMC2209_SetDirection(TMC2209_DIR_CCW); s_stepper.direction = -1; } else { TMC2209_SetDirection(TMC2209_DIR_CW); s_stepper.direction = 1; }
/* ARR 计算: 72MHz / speed - 1 */ uint32_t arr = STEPPER_TIM_FREQ / speed; if (arr > STEPPER_TIM_ARR_MAX) { arr = STEPPER_TIM_ARR_MAX; } if (arr < STEPPER_MIN_ARR) { arr = STEPPER_MIN_ARR; }
s_stepper.step_count = 0U; s_stepper.target_steps = steps; s_stepper.complete = 0U; s_stepper.running = 1U;
__HAL_TIM_SET_COUNTER(&htim2, 0U); __HAL_TIM_SET_AUTORELOAD(&htim2, arr - 1U); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, STEPPER_PULSE_WIDTH);
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE); __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
return 0; }
// TIM2 更新中断 — 步数计数与停止 void Stepper_TIM2_IRQHandler(void) { if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) == RESET) return; __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);
s_stepper.step_count++; s_stepper.position += s_stepper.direction;
if (s_stepper.step_count >= s_stepper.target_steps) { HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1); __HAL_TIM_DISABLE_IT(&htim2, TIM_IT_UPDATE); s_stepper.running = 0U; s_stepper.complete = 1U; } } |
8.4 核心代码 — main.c 主循环
// 微步/速度配置表 MicrostepRevolutionCfg_t s_cfg_table[] = { { TMC2209_MICROSTEP_8, FPPR * 8U, 1333U }, /* 50 rpm */ { TMC2209_MICROSTEP_8, FPPR * 8U, 2667U }, /* 100 rpm */ { TMC2209_MICROSTEP_8, FPPR * 8U, 4000U }, /* 150 rpm */ { TMC2209_MICROSTEP_8, FPPR * 8U, 8000U }, /* 300 rpm */ { TMC2209_MICROSTEP_16, FPPR * 16U, 2667U }, /* 50 rpm */ { TMC2209_MICROSTEP_16, FPPR * 16U, 5333U }, /* 100 rpm */ { TMC2209_MICROSTEP_16, FPPR * 16U, 8000U }, /* 150 rpm */ { TMC2209_MICROSTEP_16, FPPR * 16U, 16000U }, /* 300 rpm */ };
// 主循环: 正转 → 停 → 反转 → 停 → 切换配置 while (1) { cfg = &s_cfg_table[cfg_idx]; TMC2209_SetMicrostep(cfg->microstep); HAL_Delay(10);
/* 正转 N 圈 */ Stepper_Move(cfg->steps_per_revolution * TARGET_COUNT, TMC2209_DIR_CW, cfg->speed); while (!Stepper_IsComplete()) {} Stepper_ClearCompleteFlag();
HAL_Delay(1000);
/* 反转 N 圈 */ Stepper_Move(cfg->steps_per_revolution * TARGET_COUNT, TMC2209_DIR_CCW, cfg->speed); while (!Stepper_IsComplete()) {} Stepper_ClearCompleteFlag();
HAL_Delay(1000); cfg_idx = (cfg_idx + 1U) % cfg_len; } |
8.5 编译参与文件分组
Application/MDK-ARM | startup_stm32f103xb.s |
Application/User/Core | main.c, stm32f1xx_it.c, stm32f1xx_hal_msp.c, stepper.c, tmc2209.c |
Drivers/STM32F1xx_HAL_Driver | hal.c, hal_rcc.c, hal_gpio.c, hal_tim.c, hal_uart.c, hal_dma.c, hal_cortex.c, hal_pwr.c, hal_flash.c, hal_exti.c |
Drivers/CMSIS | system_stm32f1xx.c |
预定义宏 | USE_HAL_DRIVER, STM32F103xB |
头文件路径 | ../Core/Inc; ../Drivers/STM32F1xx_HAL_Driver/Inc; ../Drivers/CMSIS/Device/ST/STM32F1xx/Include; ../Drivers/CMSIS/Include |
9. 如何开启运行
9.1 硬件准备
器件 | 规格 | 说明 |
STM32F103CBT6 最小系统板 | LQFP48, 72MHz, 128KB Flash | 需有 8MHz 外部晶振 |
TMC2209 驱动模块 | standalone 模块 (带 MS1/MS2 排针) | STEP/DIR/ENN/MS1/MS2 接口 |
步进电机 | 两相四线, 1.8° 步距角 | NEMA17 或类似规格 |
直流电源 | 12V, ≥2A | 电机供电 |
J-Link 调试器 | SWD 接口 | 程序烧录与调试 |
杜邦线若干 | 母对母 / 公对母 | 板间连接 |
9.2 接线
STM32 TMC2209 模块 ───────────────────────────── PA0 ────────→ STEP PA1 ────────→ DIR PA2 ────────→ ENN PA3 ────────→ MS1 PA4 ────────→ MS2 GND ──────── GND (共地)
TMC2209 步进电机 ───────────────────────────── A1 ────────→ 线圈 A+ A2 ────────→ 线圈 A- B1 ────────→ 线圈 B+ B2 ────────→ 线圈 B-
TMC2209 电源 ───────────────────────────── VS ────────→ +12V GND ────────→ GND
J-Link STM32 ───────────────────────────── SWDIO ───────→ PA13 SWCLK ───────→ PA14 GND ───────→ GND Vref ────────→ 3.3V |
9.3 编译与烧录步骤
① 打开工程
双击 MDK-ARM\TMC2209_SD_TEST.uvprojx 打开 Keil MDK-ARM V5.32 工程。确认已安装 STM32F1xx DFP (Device Family Pack)。
② 编译
按 F7 或点击 Build 按钮。预期输出: 0 Error(s), 0 Warning(s)。输出文件: MDK-ARM\TMC2209_SD_TEST\TMC2209_SD_TEST.hex。
③ 连接硬件
按 9.2 节接线表连接 STM32、TMC2209、电机和电源。先接好所有线缆再上电。12V 电源给 TMC2209 供电,STM32 可由 J-Link 供电或独立 3.3V。
④ 烧录
按 F8 或点击 Download 按钮,通过 J-Link SWD 将程序烧录到 STM32。也可使用 J-Flash 直接烧录 HEX 文件。烧录完成后程序自动运行。
⑤ 观察运行
上电后程序自动开始运行:电机先以 1/8 细分 50 RPM 正转 2 圈 → 停 1s → 反转 2 圈 → 停 1s → 切换到 100 RPM → ... 依此循环 8 种配置。
⑥ 在线调试 (可选)
按 Ctrl+F5 进入调试模式。在 Watch 窗口添加 s_stepper 结构体变量,观察 step_count、position、running 等字段变化。可设置断点在 Stepper_TIM2_IRQHandler 验证中断计数。
9.4 修改配置指南
// 修改目标旋转圈数 (stepper.h): #define TARGET_COUNT 2U // 改为你需要的圈数
// 添加/修改转速配置 (main.c): static const MicrostepRevolutionCfg_t s_cfg_table[] = { { TMC2209_MICROSTEP_16, FPPR * 16U, 5333U }, /* 100 RPM, 1/16 */ // 添加更多配置... };
// 计算脉冲频率: f = RPM × 200 × microstep / 60 // 示例: 600 RPM, 1/16 微步 → f = 600 × 200 × 16 / 60 = 32000 Hz // 调用: Stepper_Move(3200 * 2, TMC2209_DIR_CW, 32000); |
运行验证清单 • 上电后电机立即开始转动 (延时约 10ms 用于细分切换稳定) • 正转 2 圈后停顿 1s,然后反转 2 圈回到原位 • 8 种配置依次切换,转速和细分档位可见明显变化 • 低转速 (50 RPM) 运行平稳,高转速 (300 RPM) 无堵转 • 1/16 细分下运行噪音低于 1/8 细分 |
效果演示:

TMC2209 步进电机控制项目报告 — 生成于 2026-07-12
我要赚赏金
