You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用TMC2209驱动与ESP32无法启动步进电机的问题求助

TMC2209 + ESP32 步进电机无法启动故障排查求助

使用TMC2209驱动器搭配ESP32控制步进电机,电机完全无响应,已反复检查接线但问题未解决,请求帮忙排查故障并指导步进电机启动步骤。

我的代码

#define STEP 38
#define EN 37
#define DIR 36
#define INDEX 35
#define DIAG 21
#define MS2 13
#define MS1 14
#define PDN_RX 11
#define PDN_TX 10
#define TX 43
#define RX 44

uint8_t GCONF[] = {0xA, 0x00, 0x80, 0x00, 0x00, 0x00, 0x65, 0x00};
uint8_t FACTORY_CONF[] = {0xA, 0x00, 0x87, 0x00, 0x00, 0x00, 0x1F, 0x00};
uint8_t IHOLD_IRUN[] = {0xA,0x00,0x90,0x00,0x49,0x49,0x00};
uint8_t TPOWERDOWN[] = {0xA, 0x00, 0x91, 0x00, 0x00, 0x00, 0xFF, 0x00};
uint8_t TPWMTHRS[] = {0xA, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t VACTUAL[] = {0xA, 0x00, 0xA2, 0x00, 0xFF, 0xFF, 0xFF, 0x00};
uint8_t SGTHRS[] = {0xA, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x50, 0x00};
uint8_t COOLCONF[] = {0xA, 0x00, 0xC2, 0x00, 0x00, 0xB0, 0x66, 0x00};

const uart_port_t uart_num = UART_NUM_0;

uint8_t CalcCRC (uint8_t * datagram, uint8_t datagramLength) {
  int i, j; /* Loop Counters */
  uint8_t *crc = datagram + (datagramLength - 1);  // CRC located in last byte of message
  uint8_t currentByte;                            // Byte to be sent
  *crc = 0;                                      // Initialize CRC to 0
  for (i = 0; i < (datagramLength - 1); i++) {  // Execute for all bytes of a message
      currentByte = datagram[i];               // Retrieve a byte to be sent from Array
      for (j = 0; j < 8; j++) {               // Execute for all bits of a byte
          if ((*crc >> 7) ^ (currentByte & 0x01)) { // update CRC based result of XOR operation
              *crc = (*crc << 1) ^ 0x07; // Shift CRC to the left and XOR with 0x07
          } /*of if*/
          else {
              *crc = (*crc << 1); // Shift CRC to the left
          } /*of else*/
          currentByte = currentByte >> 1; /* Shift byte to the right once */
      } /*of for j counter*/
  } /*of for datagram length*/
  return datagram[datagramLength - 1]; // Return the CRC
} /*of CalcCRC*/

void CalcRegistersCrc() 
{
    uint8_t CRC = CalcCRC((const char *)GCONF, sizeof(GCONF));
    printf("%02X\n", CRC);
    CRC = CalcCRC((const char *)FACTORY_CONF, sizeof(FACTORY_CONF));
    printf("%02X\n", CRC);
    CRC = CalcCRC((const char *)IHOLD_IRUN, sizeof(IHOLD_IRUN));
    printf("%02X\n", CRC);
    CRC = CalcCRC((const char *)TPOWERDOWN, sizeof(TPOWERDOWN));
    printf("%02X\n", CRC);
    CRC = CalcCRC((const char *)TPWMTHRS, sizeof(TPWMTHRS));
    printf("%02X\n", CRC);
    CRC = CalcCRC((const char *)VACTUAL, sizeof(VACTUAL));
    printf("%02X\n", CRC);
    CRC = CalcCRC((const char *)SGTHRS, sizeof(SGTHRS));
    printf("%02X\n", CRC);
    CRC = CalcCRC((const char *)COOLCONF, sizeof(COOLCONF));
    printf("%02X\n", CRC);
}

void WriteRegisters()
{
    uart_write_bytes(uart_num, GCONF, sizeof(GCONF));
    uart_write_bytes(uart_num, FACTORY_CONF, sizeof(FACTORY_CONF));
    uart_write_bytes(uart_num, IHOLD_IRUN, sizeof(IHOLD_IRUN));
    uart_write_bytes(uart_num, TPOWERDOWN, sizeof(TPOWERDOWN));
    uart_write_bytes(uart_num, TPWMTHRS, sizeof(TPWMTHRS));
    uart_write_bytes(uart_num, VACTUAL, sizeof(VACTUAL));
    uart_write_bytes(uart_num, SGTHRS, sizeof(SGTHRS));
    uart_write_bytes(uart_num, COOLCONF, sizeof(COOLCONF));
    
  
    ESP_LOGI("STEPPER MOTOR", "All registers are written");
}

void SetPins()
{
    gpio_set_direction(EN, GPIO_MODE_OUTPUT);
    gpio_set_direction(MS1, GPIO_MODE_OUTPUT);
    gpio_set_direction(MS2, GPIO_MODE_OUTPUT);

    gpio_set_level(EN, 0);
    gpio_set_level(MS1, 0);
    gpio_set_level(MS2, 1);
}

void InitUart()
{
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_APB
    };

    uart_param_config(uart_num, &uart_config);
    uart_set_pin(uart_num, TX, RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    uart_driver_install(uart_num, 2048, 0, 0, NULL, 0);
}


void ReadData()
{
    ;
}

void StepperMotorTask(void *pvParameters)
{   
    CalcRegistersCrc();
    SetPins();
    InitUart();
    while (1)
    {
        WriteRegisters();
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

故障排查要点与修正方案

1. 核心问题:缺少STEP脉冲输出

代码中仅定义了STEP和DIR引脚,但未初始化它们的GPIO方向,也没有输出任何STEP脉冲。TMC2209在默认的STEP/DIR模式下,必须接收连续的STEP脉冲才能驱动电机转动。

2. 串口配置冲突

UART_NUM_0是ESP32的默认调试串口(USB转串口),用来和TMC2209通信会与调试输出(printf/ESP_LOGI)冲突,导致寄存器写入失败。建议改用UART_NUM_1或UART_NUM_2,同时确保:

  • ESP32的TX引脚接TMC2209的PDN_RX
  • ESP32的RX引脚接TMC2209的PDN_TX
  • TMC2209的PDN引脚需拉低(接GND),进入UART通信模式

3. 寄存器CRC处理错误

当前代码仅计算CRC并打印,但未将计算后的CRC值写入寄存器数组的最后一位,导致TMC2209无法识别无效的寄存器指令。需要将计算后的CRC填充到对应寄存器数组的末尾。

4. 寄存器重复写入

WriteRegisters函数在循环中每秒执行一次,这完全没必要,寄存器仅需在初始化时写入一次即可,重复写入会干扰驱动器正常工作。

修正后的代码

#define STEP 38
#define EN 37
#define DIR 36
#define INDEX 35
#define DIAG 21
#define MS2 13
#define MS1 14
#define PDN_RX 11
#define PDN_TX 10
#define TX 43
#define RX 44

// 初始化寄存器时预留CRC位,后续计算填充
uint8_t GCONF[] = {0xA, 0x00, 0x80, 0x00, 0x00, 0x00, 0x65, 0x00};
uint8_t FACTORY_CONF[] = {0xA, 0x00, 0x87, 0x00, 0x00, 0x00, 0x1F, 0x00};
uint8_t IHOLD_IRUN[] = {0xA,0x00,0x90,0x00,0x49,0x49,0x00};
uint8_t TPOWERDOWN[] = {0xA, 0x00, 0x91, 0x00, 0x00, 0x00, 0xFF, 0x00};
uint8_t TPWMTHRS[] = {0xA, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t VACTUAL[] = {0xA, 0x00, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00}; // 初始速度设为0,按需调整
uint8_t SGTHRS[] = {0xA, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x50, 0x00};
uint8_t COOLCONF[] = {0xA, 0x00, 0xC2, 0x00, 0x00, 0xB0, 0x66, 0x00};

const uart_port_t uart_num = UART_NUM_1; // 改用UART1避免调试冲突

uint8_t CalcCRC (uint8_t * datagram, uint8_t datagramLength) {
  int i, j;
  uint8_t *crc = datagram + (datagramLength - 1);
  uint8_t currentByte;
  *crc = 0;
  for (i = 0; i < (datagramLength - 1); i++) {
      currentByte = datagram[i];
      for (j = 0; j < 8; j++) {
          if ((*crc >> 7) ^ (currentByte & 0x01)) {
              *crc = (*crc << 1) ^ 0x07;
          } else {
              *crc = (*crc << 1);
          }
          currentByte = currentByte >> 1;
      }
  }
  return *crc;
}

void InitRegisters() {
    // 计算并填充所有寄存器的CRC
    CalcCRC(GCONF, sizeof(GCONF));
    CalcCRC(FACTORY_CONF, sizeof(FACTORY_CONF));
    CalcCRC(IHOLD_IRUN, sizeof(IHOLD_IRUN));
    CalcCRC(TPOWERDOWN, sizeof(TPOWERDOWN));
    CalcCRC(TPWMTHRS, sizeof(TPWMTHRS));
    CalcCRC(VACTUAL, sizeof(VACTUAL));
    CalcCRC(SGTHRS, sizeof(SGTHRS));
    CalcCRC(COOLCONF, sizeof(COOLCONF));
}

void WriteRegisters() {
    uart_write_bytes(uart_num, GCONF, sizeof(GCONF));
    vTaskDelay(10 / portTICK_PERIOD_MS); // 给驱动器预留响应时间
    uart_write_bytes(uart_num, FACTORY_CONF, sizeof(FACTORY_CONF));
    vTaskDelay(10 / portTICK_PERIOD_MS);
    uart_write_bytes(uart_num, IHOLD_IRUN, sizeof(IHOLD_IRUN));
    vTaskDelay(10 / portTICK_PERIOD_MS);
    uart_write_bytes(uart_num, TPOWERDOWN, sizeof(TPOWERDOWN));
    vTaskDelay(10 / portTICK_PERIOD_MS);
    uart_write_bytes(uart_num, TPWMTHRS, sizeof(TPWMTHRS));
    vTaskDelay(10 / portTICK_PERIOD_MS);
    uart_write_bytes(uart_num, VACTUAL, sizeof(VACTUAL));
    vTaskDelay(10 / portTICK_PERIOD_MS);
    uart_write_bytes(uart_num, SGTHRS, sizeof(SGTHRS));
    vTaskDelay(10 / portTICK_PERIOD_MS);
    uart_write_bytes(uart_num, COOLCONF, sizeof(COOLCONF));
    vTaskDelay(10 / portTICK_PERIOD_MS);
    
    ESP_LOGI("STEPPER MOTOR", "All registers are written");
}

void SetPins() {
    gpio_set_direction(EN, GPIO_MODE_OUTPUT);
    gpio_set_direction(MS1, GPIO_MODE_OUTPUT);
    gpio_set_direction(MS2, GPIO_MODE_OUTPUT);
    gpio_set_direction(STEP, GPIO_MODE_OUTPUT); // 初始化STEP引脚
    gpio_set_direction(DIR, GPIO_MODE_OUTPUT);  // 初始化DIR引脚

    gpio_set_level(EN, 0);       // 低电平使能驱动器
    gpio_set_level(MS1, 0);      // 设置1/4细分
    gpio_set_level(MS2, 1);
    gpio_set_level(DIR, 0);      // 设置电机转动方向
    gpio_set_level(STEP, 0);     // STEP初始电平
}

void InitUart() {
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_APB
    };

    uart_param_config(uart_num, &uart_config);
    uart_set_pin(uart_num, TX, RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    uart_driver_install(uart_num, 2048, 2048, 0, NULL, 0); // 初始化接收缓冲区
}

void StepperMotorTask(void *pvParameters) {   
    InitRegisters(); // 先计算并填充寄存器CRC
    SetPins();
    InitUart();
    WriteRegisters(); // 仅初始化时写入一次寄存器

    while (1) {
        // 输出STEP脉冲驱动电机,调整延迟时间可改变转速
        gpio_set_level(STEP, 1);
        vTaskDelay(1 / portTICK_PERIOD_MS); // 脉冲宽度1ms
        gpio_set_level(STEP, 0);
        vTaskDelay(1 / portTICK_PERIOD_MS); // 脉冲间隔1ms
    }
}

额外检查项

  • 确认驱动器VM引脚电源电压符合电机规格(通常为12-24V),且电源能提供足够电流
  • 检查电机绕组接线是否正确,无短路或接反
  • 测试DIAG引脚状态,若驱动器报错会输出相应信号

内容的提问来源于stack exchange,提问作者Boris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 13:09:52