这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【let'sdo|2026年第1期】静音步进电机控制实践-成果贴

共1条 1/1 1 跳转至

【let'sdo|2026年第1期】静音步进电机控制实践-成果贴

助工
2026-06-05 20:16:28     打赏

成果帖

1、项目介绍

使用MCU控制TMC2209 SilentStepStick 驱动步进电机,实现一个可控制转动方向和速度的基础运动控制系统。

活动任务:

• 基础任务(入门级),控制端: •生成STEP脉冲信号 •DIR控制电机正反转 •支持至少两种转速,例如快速、慢速 •电机能够稳定运行

•进阶任务,在基础任务上实现: •速度调节功能 •加速/减速控制 •按键或串口控制运动,例如:启动、停止、反转

• 自由发挥方向(不做强制要求): •梯形加减速控制 •多种运动模式 •定位控制(步数控制) •PWM方式生成STEP

2、硬件准备

  • 树莓派Pico主控板 x1

  • TMC2209步进电机驱动模块 x1

  • 12V步进电机 x1

  • 12V电源适配器

  • 连接线若干

硬件连接图(参考用,请忽略很多不严谨的地方。。)

image-20260605194916256.png

layout图(洞洞板走线,因此设置得很粗,至于未连接的线实际上是飞线了)

image-20260605195100514.png

2、关键代码介绍

/*
* step  ms1 ms2
* 1/8   0   0
* 1/16  1   1
* 1/32  1   0
* 1/64  0   1
*/
// 引脚定义
int en = 7;        // 使能引脚 - 1为禁用,0为使能
int ms1 = 8;       // 微步设置1
int ms2 = 9;       // 微步设置2
int sprd = 10;     // 斩波模式选择引脚 1-SpreadCycle,0-Stealthchop
                   // 低速用 StealthChop 保持安静,高速切到 SpreadCycle 保证力矩。
int step = 11;     // 步进脉冲引脚
int pdn = 14;      // 功耗模式 1-保持力矩,0-省电
int dir = 15;      // 方向引脚 1-顺时针,0-逆时针
#define PIN_LED     (25u)

// 电机控制变量
int motorSpeed = 1000; // 步进脉冲间隔(微秒),值越小速度越快
int microstepMode = 16; // 当前微步模式
bool running = false;  // 电机运行状态
bool direction = true; // 旋转方向

void setup() {
  // 初始化控制引脚
  pinMode(en, OUTPUT);
  pinMode(ms1, OUTPUT);
  pinMode(ms2, OUTPUT);
  pinMode(sprd, OUTPUT);
  pinMode(step, OUTPUT);
  pinMode(pdn, OUTPUT);
  pinMode(dir, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  // 设置初始状态
  digitalWrite(en, HIGH);    // 禁用驱动器
  digitalWrite(dir, HIGH);   // 设置方向为顺时针
  digitalWrite(sprd, LOW);   // 初始设置为Stealthchop模式
  digitalWrite(pdn, HIGH);   // 设置为保持力矩模式
  digitalWrite(step, LOW);   // 步进脉冲初始为低

  // 设置微步模式为1/16 (MS1=1, MS2=1)
  setMicrostepMode(16);

  // 初始化串口通信(用于调试和控制命令)
  Serial.begin(115200);
  // 对于树莓派Pico RP2040,等待串口连接
  while (!Serial && millis() < 5000) {
    // 等待串口打开或最多等待5秒
  }
  Serial.println("TMC2209步进电机控制器已启动(GPIO模式)");
  Serial.println("命令:");
  Serial.println(" s - 启动电机");
  Serial.println(" t - 停止电机");
  Serial.println(" d - 切换方向");
  Serial.println(" + - 加速");
  Serial.println(" - - 减速");
  Serial.println(" m - 更改微步模式");
  Serial.println(" c - 切换斩波模式(SpreadCycle/StealthChop)");
  Serial.println(" p - 切换功耗模式(保持力矩/省电)");
  Serial.println(" h - 输出帮助信息");
}

void loop() {
  // 检查串口命令
  if (Serial.available()) {
    char command = Serial.read();
    handleCommand(command);
  }

  // 如果电机正在运行,则发送步进脉冲
  if (running) {
    digitalWrite(step, HIGH);
    delayMicroseconds(motorSpeed / 2); // 高电平一半时间
    digitalWrite(step, LOW);
    delayMicroseconds(motorSpeed / 2); // 低电平一半时间
  }

   // 使用定时器控制LED闪烁,不受电机运行影响
  static unsigned long lastLEDToggle = 0;
  const unsigned long ledInterval = 500; // LED闪烁间隔(毫秒)
  if (millis() - lastLEDToggle >= ledInterval) {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    lastLEDToggle = millis();
  }
}

// 设置微步模式
void setMicrostepMode(int mode) {
  switch(mode) {
    case 8: // 1/8步
      digitalWrite(ms1, LOW);
      digitalWrite(ms2, LOW);
      microstepMode = 8;
      break;
    case 16: // 1/16步
      digitalWrite(ms1, HIGH);
      digitalWrite(ms2, HIGH);
      microstepMode = 16;
      break;
    case 32: // 1/32步
      digitalWrite(ms1, HIGH);
      digitalWrite(ms2, LOW);
      microstepMode = 32;
      break;
    case 64: // 1/64步
      digitalWrite(ms1, LOW);
      digitalWrite(ms2, HIGH);
      microstepMode = 64;
      break;
    default:
      // 默认设为1/16步
      digitalWrite(ms1, HIGH);
      digitalWrite(ms2, HIGH);
      microstepMode = 16;
      break;
  }

  Serial.print("微步模式设置为: 1/");
  Serial.println(microstepMode);
}

// 处理串口命令
void handleCommand(char cmd) {
  switch(cmd) {
    case 's': // 启动电机
      enableDriver();
      running = true;
      Serial.println("电机启动");
      break;

    case 't': // 停止电机
      running = false;
      disableDriver();
      Serial.println("电机停止");
      break;

    case 'd': // 切换方向
      direction = !direction;
      digitalWrite(dir, direction);
      Serial.print("方向切换为: ");
      Serial.println(direction ? "顺时针" : "逆时针");
      break;

    case '+': // 加速
      motorSpeed -= 100; // 减少延时时间,提高速度
      if(motorSpeed < 100) motorSpeed = 100; // 限制最小延时
      Serial.print("加速 - 步进间隔: ");
      Serial.print(motorSpeed);
      Serial.println("us");
      break;

    case '-': // 减速
      motorSpeed += 100; // 增加延时时间,降低速度
      if(motorSpeed > 5000) motorSpeed = 5000; // 限制最大延时
      Serial.print("减速 - 步进间隔: ");
      Serial.print(motorSpeed);
      Serial.println("us");
      break;

    case 'm': // 更改微步模式
      cycleMicrostepMode();
      break;

    case 'c': // 切换斩波模式
      toggleChopperMode();
      break;

    case 'p': // 切换功耗模式
      togglePowerMode();
      break;

    case 'h': // 显示帮助
      printHelp();
      break;

    case '\n':
    case '\r':
      break; // 忽略换行符

    default:
      Serial.print("未知命令: ");
      Serial.println(cmd);
      Serial.println("输入'h'查看帮助");
      break;
  }
}

// 循环切换微步模式
void cycleMicrostepMode() {
  int modes[] = {8, 16, 32, 64};
  static int modeIndex = 0;

  modeIndex = (modeIndex + 1) % 4;
  setMicrostepMode(modes[modeIndex]);
}

// 切换斩波模式
void toggleChopperMode() {
  // 当前模式是StealthChop (sprd=LOW),切换到SpreadCycle (sprd=HIGH)
  bool currentMode = digitalRead(sprd);
  digitalWrite(sprd, !currentMode);

  Serial.print("斩波模式切换为: ");
  Serial.println(!currentMode ? "SpreadCycle" : "StealthChop");
}

// 切换功耗模式
void togglePowerMode() {
  // 当前模式是保持力矩 (pdn=HIGH),切换到省电模式 (pdn=LOW)
  bool currentMode = digitalRead(pdn);
  digitalWrite(pdn, !currentMode);

  Serial.print("功耗模式切换为: ");
  Serial.println(!currentMode ? "省电模式" : "保持力矩");
}

// 使能驱动器
void enableDriver() {
  digitalWrite(en, LOW); // 使能驱动器
}

// 禁用驱动器
void disableDriver() {
  digitalWrite(en, HIGH); // 禁用驱动器
}

// 打印帮助信息
void printHelp() {
  Serial.println("=== TMC2209步进电机控制器 (GPIO模式) ===");
  Serial.println("命令列表:");
  Serial.println(" s - 启动电机");
  Serial.println(" t - 停止电机");
  Serial.println(" d - 切换方向 (顺时针/逆时针)");
  Serial.println(" + - 增加速度");
  Serial.println(" - - 降低速度");
  Serial.println(" m - 循环切换微步模式");
  Serial.println(" c - 切换斩波模式 (StealthChop/SpreadCycle)");
  Serial.println(" p - 切换功耗模式 (保持力矩/省电)");
  Serial.println(" h - 显示此帮助信息");
  Serial.println("=========================================");
  Serial.print("当前状态: ");
  Serial.println(running ? "运行" : "停止");
  Serial.print("当前方向: ");
  Serial.println(direction ? "顺时针" : "逆时针");
  Serial.print("当前速度: ");
  Serial.print(1000000/motorSpeed); // 转换为Hz
  Serial.println(" Hz");
  Serial.print("当前微步: 1/");
  Serial.println(microstepMode);
  Serial.print("斩波模式: ");
  Serial.println(digitalRead(sprd) ? "SpreadCycle" : "StealthChop");
  Serial.print("功耗模式: ");
  Serial.println(digitalRead(pdn) ? "保持力矩" : "省电");
}

3、功能展示(包含成果视频)

实现情况:

功能实现情况
生成STEP脉冲信号完成
DIR控制电机正反转完成
支持至少两种转速,例如快速、慢速完成
电机能够稳定运行完成
速度调节功能完成
按键或串口控制运动,例如:启动、停止、反转完成
PWM方式生成STEP完成

其他更多功能请见代码或帮助,除了串口控制tmc2209,基本所有功能都已经实现了。

b站视频介绍:

4、技术难点与解决方案/心得体会

之前只玩过直流有刷电机,对步进电机一直不太了解,感谢得捷给了这次机会,使我可以研究一下步进电机的控制。其实一开始看原理的时候还有点云里雾里,直到搞明白TMC2209的控制后,就明白了很多,当然还有很多进阶的控制,希望后面还有机会深入!

搞明白原理后,就开始想办法连接,之前马马虎虎搞个杜邦线连就好,但是前段时间因为反接电源烧了一个DAC模块,吃一堑长一智,决定还是回归大学初学电子时的法子——洞洞板。相比大学,现在已经可以拿EDA软件设计一下原理图,虽然要在洞洞板上走线,也大致layout规划了一番,最后达到自己满意的一个效果。焊接完,先测试有没有短路,再逐步加模块看是否正常,前面一切顺利,直到我断开12v,插上USB准备开发时,电源芯片开始冒烟,慌忙断电,最后用一颗二极管隔离开USB到电源模块的通路。而arduino 的开发就很简单了,arduino的封装很好,很容易就驱动起来该有的外设:串口、GPIO、PWM,再将要求告诉ai,调试一番,很快就实现功能了。

回顾一下,比较开心的时刻:拿到板子时、搞明白原理时、加了一个二极管解决冒烟问题时、电机转起来时。在这个AI的时代,写代码的空间不断被压缩,那实实在在跑起来的电路,或许能带给工程师更多的慰藉吧。



共1条 1/1 1 跳转至

回复

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