这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 静音步进电机控制实践-按键启停控制实现

共1条 1/1 1 跳转至

静音步进电机控制实践-按键启停控制实现

高工
2026-06-30 23:40:27     打赏

1. 硬件接线

信号STM32H533 引脚说明
EN(使能)PB15TMC2209 主动低,下降沿进入工作态
DIR(方向)PB14高/低电平直接决定旋转方向
STEP(脉冲)PC8 / TIM3_CH35 kHz 基准方波,50% 占空比
USER 按钮PC13NUCLEO-H533RE 板载 B1(BSP 已配置为内部下拉 + 上升沿中断)
TIM3 配置(CubeMX 生成):
  • 计数时钟源:内部,APB1 Timer Clock = 250 MHz

  • 预分频 PSC = 249 → 计数节拍 1 MHz(1 tick = 1 µs)

  • 自动重载 ARR = 199 → 周期 200 µs,频率 = 1 MHz / 200 = 5 kHz

  • 比较寄存器 CCR = 99 → 50% 占空比

2. 已实现的功能

  1. 上电默认停机:电机初始化后 EN 高、PWM 不输出脉冲,方向为 CW。

  2. 板载按键切换启停:按一次 B1 → 启动(EN 拉低、PC8 输出 5 kHz 方波);再按一次 → 停止(先关 PWM 再拉高 EN)。

  3. LED 按键反馈:每次按下按键,绿灯短暂闪一下,给用户肉眼确认按键被识别。

未实现(待后续阶段):
  • 方向切换(DIR 引脚已经接好,但没有触发手段)

  • 调速(当前频率固定为 5 kHz)

  • 限位/原点开关处理

  • 串口指令、上位机协议

3. 软件架构

        工程在 CubeMX 自动生成的骨架上,新增了一个独立的 motor 驱动模块,按钮中断作为唯一的外部事件源:

+---------------------------+
|        main.c             |
|  - HAL_Init / 时钟 / 外设  |
|  - motor_init(&motor_cfg) |
|  - BSP_PB_Init(BUTTON_EXTI)|
|  - while(1) 空闲          |
+-------------+-------------+
              |  EXTI13 (上升沿)
              v
+---------------------------+
|  BSP_PB_Callback (用户)   |
|   -> motor_toggle()       |
+-------------+-------------+
              v
+---------------------------+
|       motor 模块          |
|  motor_init / start /     |
|  stop / toggle / set_dir  |
|  / set_freq               |
+-------------+-------------+
              |  GPIO + TIM3 PWM
              v
        TMC2209 SILENTSTEPSTICK  ->  步进电机 -> 滑轨

        模块之间的耦合只有函数调用,没有任何全局变量污染 main()。

4. motor 模块设计要点

        驱动模块没有写死任何引脚号——所有硬件相关的参数都通过 motor_cfg_t 在 main.c 里组装好后传给 motor_init():

static const motor_cfg_t motor_cfg = {
    .en_port         = MotorEN_GPIO_Port,   // GPIOB
    .en_pin          = MotorEN_Pin,         // GPIO_PIN_15
    .dir_port        = MotorDir_GPIO_Port,  // GPIOB
    .dir_pin         = MotorDir_Pin,        // GPIO_PIN_14
    .tim             = &htim3,
    .tim_channel     = TIM_CHANNEL_3,
    .default_freq_hz = MOTOR_DEFAULT_HZ,    // 5000
};
motor_init(&motor_cfg);

        带来的好处是:换一块板、换一个定时器通道、或者把电机换成另一台,只需要改 motor_cfg,模块本身不动。

单例 + 公开结构

        模块内只存在一个全局实例 motor_t motor,状态字段(频率、方向、运行中)直接可读:

typedef struct {
    const motor_cfg_t   *cfg;
    uint32_t             freq_hz;
    uint8_t              dir;        // MOTOR_DIR_CW / MOTOR_DIR_CCW
    bool                 running;
} motor_t;
extern motor_t motor;

        简单的查询通过头文件里的 static inline 直接读字段,不需要单独的 GetXXX() 函数——比上一版 Stepper_GetInfo() 之类的访问层薄一些。

启停时序

启动(motor_start()):
  1. 把当前频率对应的 CCR 写进比较寄存器(保证第一帧就是 50% 占空比)

  2. 拉低 EN(TMC2209 使能)

  3. HAL_TIM_PWM_Start 让 TIM3_CH3 开始输出

  4. 把 motor.running = true

停止(motor_stop()):
  1. HAL_TIM_PWM_Stop 关 OC 输出

  2. HAL_TIM_Base_Stop 关计数器(避免残留触发)

  3. 清零计数器

  4. 拉高 EN(释放驱动器)

  5. motor.running = false

        motor_init() 里额外给 TIM3 打开了 OSSI 位——通道关闭时输出会被强制拉低而不是高阻,避免 PC8 浮空被 TMC2209 误识别为脉冲。

改频率

        调用 motor_set_freq(hz) 时,如果电机正在转,会先 HAL_TIM_PWM_Stop 把输出稳住,再写 ARR + CCR + 清计数器,最后再 HAL_TIM_PWM_Start。换频过程中 STEP 线不会产生毛刺脉冲。

5. 按键回调路径

        正确的用户入口是 BSP 提供的弱符号 BSP_PB_Callback。        触发链:
PC13 上升沿
   │
   ▼
EXTI13_IRQHandler  (Core/Src/stm32h5xx_it.c)
   │
   ▼
BSP_PB_IRQHandler(BUTTON_USER)
   │
   ▼
HAL_EXTI_IRQHandler(&hpb_exti[Button])
   │   ├── 读 RPR1 -> 命中上升沿
   │   └── 调用 BSP 自己注册的 RisingCallback
   ▼
BUTTON_USER_EXTI_Callback  →  BSP_PB_Callback(BUTTON_USER)
   │
   ▼
用户实现的 BSP_PB_Callback  →  motor_toggle()

        main.c 里把 motor_toggle() + LED 闪烁放在回调里就够了。while(1) 主循环什么都不用做——PWM 由定时器硬件持续产生,按键由中断处理,两者天然解耦。

6. 构建配置

        CMakeLists.txt 在 target_sources 里加了 Core/Src/motor.c,并把 Core/Inc 加入 include 路径。Debug 配置下编译产物:
Memory region    Used Size   Region Size   %age Used
          RAM:        1864 B       272 KB      0.67%
        FLASH:       27556 B       512 KB      5.26%

7. 效果展示

滑轨控制.gif





关键词: 按键     启停     实现    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]