第 8 篇:TMC2240 电机正反转实现|DIR 引脚控制 + 代码优化(稳定不抖动)

#TMC2240 #电机正反转 #DIR引脚控制 #STM32实战 #嵌入式电机驱动

作者:BackCatK Chen 厦门市电子工程中级工程师

(承接前 7 篇斩波模式配置,关注我解锁 TMC2240 全场景控制技巧,从模式配置到运动控制一步到位!)


👋 为什么正反转时电机抖动、冲击大?

实现电机正反转是嵌入式开发的基础需求,但很多开发者会遇到这些问题:

  • 切换正反转时,电机瞬间卡顿、抖动,甚至发出 "咔咔" 冲击声;
  • DIR 引脚配置后,电机方向不切换,或切换逻辑混乱;
  • 连续运行时方向切换频繁,电机发热严重;
  • 点动控制时,启停不平稳,定位精度差。

其实 TMC2240 的正反转控制核心是「DIR 引脚电平切换」+「平滑切换逻辑」------ 方向切换不是简单的电平反转,还要配合转速控制避免电流冲击。这篇文章承接前 7 篇的基础配置(电流、微步、斩波模式),从正反转原理、DIR 引脚配置,到平滑切换逻辑、连续 / 点动控制代码,全程保姆级拆解,新手跟着复制代码就能实现稳定的正反转,还能避免常见的抖动、冲击问题!


📌 核心前提:先确认 3 个基础条件(避免白忙活)

在实现正反转前,必须确保以下 3 个条件满足,否则方向控制无效:

  1. 硬件连接正常:DIR 引脚已正确连接到 STM32 的 GPIO 口(如 PA0),电机绕组 A/B 相接线无误;
  2. 基础配置完成:已完成前 7 篇的配置(电流、微步、斩波模式),电机能正常转动(无方向控制时默认单方向运行);
  3. EN 引脚使能:TMC2240 的 DRV_ENN 引脚已拉低(电机使能),否则电机无响应。

✨ 避坑提示:若电机还不能单方向运行,先回头检查前 7 篇的配置(尤其是 DRV_CONF、IHOLD_IRUN、CHOPCONF),再进行方向控制!


🎯 一、正反转核心原理:DIR 引脚电平决定方向

1.1 原理说明

TMC2240 的正反转由「DIR 引脚(方向控制引脚)」的电平状态决定,核心规则:

  • DIR = 高电平(GPIO_PIN_SET):电机正转(默认方向,可通过 GCONF 寄存器的 shaft 位(bit4)反转);
  • DIR = 低电平(GPIO_PIN_RESET):电机反转;
  • 方向切换逻辑:修改 DIR 引脚电平后,需等待电机转速稳定或减速后再切换,避免瞬间电流冲击。

1.2 方向反转的 2 种方式(按需选择)

方式 实现方法 适用场景 优点
硬件方式 切换 DIR 引脚电平 大多数场景(动态切换方向) 灵活,支持运行中切换
软件方式 配置 GCONF 寄存器的 shaft 位(bit4) 固定方向反转(无需修改硬件) 无需占用 GPIO,适合 GPIO 资源紧张的场景

📌 重点说明:本文重点讲解「硬件方式(DIR 引脚控制)」,软件方式仅需配置 GCONF 寄存器 bit4=1,即可反转默认方向,操作简单。


🛠️ 二、第一步:DIR 引脚 GPIO 配置(STM32 HAL 库)

2.1 硬件连接示意图(以 STM32F103 为例)

复制代码
STM32 PA0(DIR引脚) → TMC2240 DIR引脚
STM32 PB0(STEP引脚)→ TMC2240 STEP引脚(提供脉冲信号,控制转速)
STM32 PC0(DRV_ENN引脚)  → TMC2240 DRV_ENN引脚(拉低使能)

2.2 GPIO 配置代码(直接复用,适配 STM32 全系列)

c 复制代码
// 1. 宏定义(单独放tmc2240_conf.h,方便修改引脚)
#define TMC2240_DIR_PORT    GPIOA
#define TMC2240_DIR_PIN     GPIO_PIN_0
#define TMC2240_STEP_PORT   GPIOB
#define TMC2240_STEP_PIN    GPIO_PIN_0
#define TMC2240_EN_PORT     GPIOC
#define TMC2240_EN_PIN      GPIO_PIN_0

// 2. GPIO初始化函数(正反转核心引脚配置)
void TMC2240_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  
  // 使能GPIO时钟(根据实际引脚修改时钟总线)
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  
  // DIR引脚配置(输出模式,推挽输出,无上拉下拉)
  GPIO_InitStruct.Pin = TMC2240_DIR_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(TMC2240_DIR_PORT, &GPIO_InitStruct);
  
  // STEP引脚配置(输出模式,推挽输出,无上拉下拉)
  GPIO_InitStruct.Pin = TMC2240_STEP_PIN;
  HAL_GPIO_Init(TMC2240_STEP_PORT, &GPIO_InitStruct);
  
  // DRV_ENN引脚配置(输出模式,推挽输出,初始拉低使能)
  GPIO_InitStruct.Pin = TMC2240_EN_PIN;
  HAL_GPIO_Init(TMC2240_EN_PORT, &GPIO_InitStruct);
  HAL_GPIO_WritePin(TMC2240_EN_PORT, TMC2240_EN_PIN, GPIO_PIN_RESET); // 使能电机
  
  // 初始化DIR引脚为高电平(默认正转)
  HAL_GPIO_WritePin(TMC2240_DIR_PORT, TMC2240_DIR_PIN, GPIO_PIN_SET);
  printf("GPIO初始化完成!默认方向:正转\r\n");
}

2.3 配置说明

  • 引脚模式:DIR 和 STEP 引脚必须配置为「推挽输出(GPIO_MODE_OUTPUT_PP)」,确保能稳定输出高低电平;
  • 时钟使能:根据 STM32 型号修改时钟总线(如 F4 系列为__HAL_RCC_GPIOA_CLK_ENABLE (),F1 系列相同);
  • 初始状态:DRV_ENN 引脚拉低使能电机,DIR 引脚默认高电平(正转),避免电机上电后无方向运行。

🚀 三、第二步:正反转切换逻辑(避免电流冲击,稳定核心)

直接切换 DIR 引脚电平会导致电机瞬间反向,产生大电流冲击,导致抖动、发热。正确的切换逻辑是:

复制代码
停止电机 → 延迟50ms(释放电流)→ 切换DIR电平 → 启动电机

复制代码
减速到最低转速 → 切换DIR电平 → 加速到目标转速

3.1 核心切换函数(通用模板,直接复用)

c 复制代码
// 1. 方向枚举(清晰区分方向)
typedef enum {
  TMC2240_FORWARD = 0,  // 正转
  TMC2240_REVERSE = 1   // 反转
} TMC2240_DirTypeDef;

// 2. 全局变量(存储当前方向和转速)
TMC2240_DirTypeDef current_dir = TMC2240_FORWARD; // 默认正转
uint16_t current_speed = 100; // 默认转速100rpm

// 3. 转速控制函数(生成STEP脉冲,控制转速,核心!)
// 参数:speed - 目标转速(rpm)
void TMC2240_Set_Speed(uint16_t speed)
{
  if(speed == 0)
  {
    // 转速为0,停止输出脉冲
    return;
  }
  
  // 计算STEP脉冲周期(根据电机步距角和微步计算)
  // 电机步距角1.8°,256微步 → 每圈步数 = 360/1.8 * 256 = 51200步/圈
  uint32_t steps_per_round = 51200;
  // 脉冲周期 = 60s / (转速 * 每圈步数) → 单位:us
  uint32_t pulse_period = 60 * 1000000 / (speed * steps_per_round);
  
  // 输出STEP脉冲(高低电平各占一半周期)
  HAL_GPIO_WritePin(TMC2240_STEP_PORT, TMC2240_STEP_PIN, GPIO_PIN_SET);
  HAL_Delay(pulse_period / 1000); // 毫秒级延迟(适用于低速)
  // 若需高速,改用定时器中断生成脉冲(后续优化部分讲解)
  HAL_GPIO_WritePin(TMC2240_STEP_PORT, TMC2240_STEP_PIN, GPIO_PIN_RESET);
  HAL_Delay(pulse_period / 1000);
}

// 4. 方向切换函数(平滑切换,无冲击)
void TMC2240_Switch_Dir(TMC2240_DirTypeDef target_dir)
{
  if(target_dir == current_dir)
  {
    // 目标方向与当前方向一致,无需切换
    printf("当前已为%s方向,无需切换\r\n", target_dir == TMC2240_FORWARD ? "正转" : "反转");
    return;
  }
  
  printf("开始切换到%s方向...\r\n", target_dir == TMC2240_FORWARD ? "正转" : "反转");
  
  // 步骤1:停止电机(停止输出STEP脉冲)
  current_speed = 0;
  HAL_Delay(50); // 延迟50ms,释放电机绕组电流
  
  // 步骤2:确保STEP为低电平后,再切换DIR电平(满足DIR-STEP时序要求)
  HAL_GPIO_WritePin(TMC2240_STEP_PORT, TMC2240_STEP_PIN, GPIO_PIN_RESET);
  HAL_Delay(1); // 确保电平稳定(远大于20ns时序要求)
  
  // 步骤3:切换DIR引脚电平
  if(target_dir == TMC2240_FORWARD)
  {
    HAL_GPIO_WritePin(TMC2240_DIR_PORT, TMC2240_DIR_PIN, GPIO_PIN_SET);
  }
  else
  {
    HAL_GPIO_WritePin(TMC2240_DIR_PORT, TMC2240_DIR_PIN, GPIO_PIN_RESET);
  }
  HAL_Delay(1); // 满足DIR到STEP的建立时间要求(≥20ns)
  
  // 步骤4:恢复目标转速
  current_speed = 100;
  current_dir = target_dir;
  
  printf("方向切换完成!当前方向:%s\r\n", current_dir == TMC2240_FORWARD ? "正转" : "反转");
}

// 5. 软件反转方向函数(配置GCONF寄存器bit4,shaft位)
void TMC2240_Swap_Dir_Software(void)
{
  uint32_t gconf_val = TMC2240_SPI_ReadReg(0x03); // 读取GCONF寄存器(地址0x03)
  gconf_val ^= (1 << 4); // 翻转bit4(shaft位,控制方向反转)
  TMC2240_SPI_WriteReg(0x03, gconf_val); // 写入配置
  current_dir = current_dir == TMC2240_FORWARD ? TMC2240_REVERSE : TMC2240_FORWARD;
  printf("软件方向反转完成!当前方向:%s\r\n", current_dir == TMC2240_FORWARD ? "正转" : "反转");
}

3.2 关键优化点(避免冲击的核心)

  1. 停止电机后再切换:直接切换方向会导致电机绕组电流瞬间反向,产生大冲击,停止后延迟 50ms 可释放电流;
  2. 满足时序要求:DIR 到 STEP 的建立时间≥20ns、保持时间≥20ns,添加 1ms 延迟确保电平稳定;
  3. 电平切换后延迟:DIR 引脚电平切换后,TMC2240 需要 10ms 左右稳定响应,避免立即启动导致方向错乱;
  4. 转速恢复平稳:切换后恢复转速时,建议从低速逐步加速到目标转速(后续进阶部分讲解),进一步减少抖动。

📝 四、实战 1:连续正反转控制(循环切换,稳定运行)

4.1 连续运行代码(直接复制到 main 函数)

c 复制代码
// 连续正反转测试函数
void TMC2240_Continuous_Run(void)
{
  printf("===== 连续正反转测试开始 =====\r\n");
  
  while(1)
  {
    // 正转运行5秒
    printf("正转运行中...\r\n");
    current_dir = TMC2240_FORWARD;
    current_speed = 100; // 100rpm
    for(uint32_t i=0; i<500; i++) // 运行5秒(每10ms一个脉冲周期)
    {
      TMC2240_Set_Speed(current_speed);
    }
    
    // 切换到反转
    TMC2240_Switch_Dir(TMC2240_REVERSE);
    
    // 反转运行5秒
    printf("反转运行中...\r\n");
    for(uint32_t i=0; i<500; i++)
    {
      TMC2240_Set_Speed(current_speed);
    }
    
    // 切换到正转
    TMC2240_Switch_Dir(TMC2240_FORWARD);
  }
}

// main函数
int main(void)
{
  // 初始化:HAL_Init()、时钟、串口(打印调试)
  HAL_Init();
  SystemClock_Config();
  MX_USART1_UART_Init();
  
  // 初始化TMC2240相关GPIO
  TMC2240_GPIO_Init();
  
  // 基础配置(前7篇的配置:电流、微步、斩波模式)
  TMC2240_Basic_Config();
  TMC2240_Enable_StealthChop2(); // 启用静音模式(低速无噪音)
  
  // 启动连续正反转测试
  TMC2240_Continuous_Run();
  
  while (1)
  {
  }
}

4.2 测试效果预期

  • 电机正转 5 秒后,平稳切换到反转,无抖动、无冲击声;
  • 反转 5 秒后,平稳切换到正转,运行过程中噪音小(静音模式);
  • 电机发热正常(运行 10 分钟后温度 < 60℃)。

📝 五、实战 2:点动控制(按指令启停 + 方向切换)

点动控制适用于需要精准启停的场景(如按钮控制、上位机指令控制),核心逻辑:按指令启动电机,运行指定步数后停止,支持方向切换。

5.1 点动控制代码(直接复用)

c 复制代码
// 点动控制函数(指定方向和步数)
// 参数:dir - 目标方向;steps - 运行步数(256微步下,51200步=1圈)
void TMC2240_Point_Move(TMC2240_DirTypeDef dir, uint32_t steps)
{
  printf("点动控制:%s,运行步数:%d\r\n", dir == TMC2240_FORWARD ? "正转" : "反转", steps);
  
  // 步骤1:切换到目标方向
  TMC2240_Switch_Dir(dir);
  
  // 步骤2:运行指定步数
  current_speed = 50; // 点动速度50rpm(低速精准)
  for(uint32_t i=0; i<steps; i++)
  {
    TMC2240_Set_Speed(current_speed);
  }
  
  // 步骤3:停止电机
  current_speed = 0;
  printf("点动控制完成!\r\n");
}

// 测试函数(正转半圈→反转1圈→正转1/4圈)
void TMC2240_Point_Test(void)
{
  printf("===== 点动控制测试开始 =====\r\n");
  
  // 正转半圈(51200/2=25600步)
  TMC2240_Point_Move(TMC2240_FORWARD, 25600);
  HAL_Delay(1000); // 暂停1秒
  
  // 反转1圈(51200步)
  TMC2240_Point_Move(TMC2240_REVERSE, 51200);
  HAL_Delay(1000);
  
  // 正转1/4圈(51200/4=12800步)
  TMC2240_Point_Move(TMC2240_FORWARD, 12800);
  HAL_Delay(1000);
  
  printf("===== 点动控制测试完成 =====\r\n");
}

// main函数中替换连续运行函数
int main(void)
{
  // 初始化流程同上...
  
  // 启动点动控制测试
  TMC2240_Point_Test();
  
  while (1)
  {
  }
}

5.2 测试效果预期

  • 电机按指令正转半圈后停止,暂停 1 秒;
  • 反转 1 圈后停止,暂停 1 秒;
  • 正转 1/4 圈后停止,整个过程启停平稳,定位精准(无丢步)。

🛡️ 六、进阶优化:用定时器中断生成 STEP 脉冲(高速稳定)

前面的代码用HAL_Delay()生成 STEP 脉冲,适用于低速场景(≤200rpm),高速时会导致 CPU 占用率过高、转速不稳定。用定时器中断生成脉冲,可实现高速稳定控制。

6.1 定时器配置代码(STM32F103 TIM2 为例)

c 复制代码
// 全局定时器句柄(供中断回调函数使用)
TIM_HandleTypeDef htim2;

// 定时器初始化函数(生成STEP脉冲)
void TMC2240_TIM_Init(void)
{
  // 使能TIM2时钟
  __HAL_RCC_TIM2_CLK_ENABLE();
  
  // 定时器配置(定时周期根据转速动态修改)
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 72 - 1; // 时钟分频:72MHz/72=1MHz
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 10000; // 初始周期10ms(100Hz)
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_Base_Init(&htim2);
  
  // 启用定时器更新中断
  HAL_TIM_Base_Start_IT(&htim2);
  
  // 配置中断优先级
  HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(TIM2_IRQn);
}

// 定时器中断回调函数(生成STEP脉冲)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim->Instance == TIM2 && current_speed > 0)
  {
    // 翻转STEP引脚电平(生成脉冲)
    HAL_GPIO_TogglePin(TMC2240_STEP_PORT, TMC2240_STEP_PIN);
  }
}

// 转速设置函数(动态修改定时器周期)
void TMC2240_Set_Speed_HighSpeed(uint16_t speed)
{
  if(speed == 0)
  {
    HAL_TIM_Base_Stop_IT(&htim2); // 停止定时器,停止脉冲
    HAL_GPIO_WritePin(TMC2240_STEP_PORT, TMC2240_STEP_PIN, GPIO_PIN_RESET);
    current_speed = 0;
    return;
  }
  
  current_speed = speed;
  uint32_t steps_per_round = 51200;
  // 脉冲周期 = 60s / (转速 * 每圈步数) → 单位:us
  uint32_t pulse_period = 60 * 1000000 / (speed * steps_per_round);
  // 定时器周期 = 脉冲周期 / 2(高低电平各占一半)
  htim2.Init.Period = pulse_period / 2 - 1;
  
  HAL_TIM_Base_DeInit(&htim2);
  HAL_TIM_Base_Init(&htim2);
  HAL_TIM_Base_Start_IT(&htim2);
}

6.2 优化效果

  • 高速场景(≥300rpm)下,电机运行稳定,无丢步;
  • CPU 占用率显著降低(从 100% 降至 < 10%),可同时处理其他任务;
  • 转速精度更高(定时器中断计时更精准)。

🚨 七、测试方法:用万用表验证方向切换(确保配置正确)

7.1 电机端子电压检测(直观判断方向)

  1. 准备工具:万用表(直流电压档);
  2. 检测步骤:
  • 电机正转时,测量电机 A 相和 B 相端子电压(如 A + 和 B+),记录电压值(如 A 相 = 2.5V,B 相 = 1.2V);
  • 切换到反转后,再次测量同一端子电压,电压值会反向(如 A 相 = 1.2V,B 相 = 2.5V);
  • 若电压无变化,说明方向切换失败,检查 DIR 引脚配置或硬件连接。

7.2 常见问题排查(90% 新手会踩)

错误现象 核心原因 解决方法
方向切换无反应 1. DIR 引脚未正确连接;2. GPIO 配置错误(如模式设为输入);3. 电机未使能(DRV_ENN未拉低) 1. 重新焊接 DIR 引脚;2. 检查 GPIO 配置为推挽输出;3. 确保 DRV_ENN 引脚拉低
切换方向时电机抖动严重 1. 未停止电机直接切换;2. 延迟时间不足;3. 转速过高;4. 未满足DIR-STEP时序要求 1. 按 "停止→切换→启动" 逻辑修改代码;2. 延长延迟时间至 50ms;3. 切换时降低转速;4. 确保STEP为低电平时切换DIR电平
点动控制定位不准 1. 步数计算错误;2. 高速点动导致丢步;3. 微步配置错误(CHOPCONF的MRES值) 1. 重新计算每圈步数(360 / 步距角 × 微步);2. 点动速度≤50rpm;3. 验证 CHOPCONF 的 MRES 值(0x07对应256微步)
高速运行时方向错乱 1. STEP 脉冲周期过短(CPU 处理不过来);2. 定时器中断优先级过低 1. 改用定时器中断生成脉冲;2. 提高定时器中断优先级
软件反转方向无效 错误配置GCONF寄存器bit1(fast_standstill位),未配置bit4(shaft位) 按TMC2240_Swap_Dir_Software()函数配置,修改GCONF寄存器bit4

📊 正反转控制速查表(打印贴工位,快速查阅)

功能 核心代码 关键参数 备注
GPIO 初始化 TMC2240_GPIO_Init() DIR/STEP/DRV_ENN 引脚 推挽输出,DRV_ENN 拉低使能
正转使能 HAL_GPIO_WritePin(DIR_PORT, DIR_PIN, SET) - 默认方向
反转使能 HAL_GPIO_WritePin(DIR_PORT, DIR_PIN, RESET) - 电平反转
软件反转方向 TMC2240_Swap_Dir_Software() GCONF寄存器bit4(shaft位) 无需修改硬件引脚
平滑切换 TMC2240_Switch_Dir(target_dir) 延迟 50ms,STEP低电平时切换DIR 避免电流冲击,满足时序要求
连续运行 TMC2240_Continuous_Run() 转速 100rpm,运行 5 秒 静音模式下无噪音
点动控制 TMC2240_Point_Move(dir, steps) 转速 50rpm,步数 = 圈数 ×51200 精准定位
高速优化 TMC2240_TIM_Init () + 中断回调 定时器分频 72,周期动态修改 适用于≥300rpm 场景

🔜 下期预告

下一篇《速度调节实战|STEP 信号生成 + 平滑调速算法》 核心内容:速度与 STEP 频率关系、定时器生成固定频率 STEP 信号、PWM 脉冲调速代码、平滑调速(加减速算法)实现、不同速度下运行效果对比!

关注我 @BackCatK Chen,嵌入式开发少走 90% 的弯路!如果正反转控制中遇到方向切换失败、抖动、定位不准等问题,可在评论区留言 "问题现象 + 硬件配置(STM32 型号 + 电机参数)",我会 1 对 1 提供解决方案!

🎁欢迎关注,获取更多技术干货!

🎁资料包亮点

这份资料包涵盖了从硬件电路设计STM32单片机开发 ,再到Linux系统学习的全链路内容,适合不同阶段的学习者:

  • 硬件基础:包含硬件电路合集、硬件设计开发工具包,帮你打牢底层基础。
  • STM32专项:从环境搭建、开发工具、传感器模块到项目实战,还有书籍和芯片手册,一站式搞定STM32学习。
  • C语言进阶:C语言学习资料包,助你掌握嵌入式开发的核心语言。
  • 面试求职:嵌入式面试题合集,提前备战技术面试。
  • Linux拓展:Linux相关学习资料包,拓宽技术视野。
📂资料包目录
  • 00-STM32单片机环境搭建
  • 01-硬件电路合集
  • 02-硬件设计开发工具包
  • 03-C语言学习资料包
  • 04-STM32单片机开发工具包
  • 05-STM32传感器模块合集
  • 06-STM32项目合集
  • 07-STM32单片机书籍&芯片手册
  • 08-Linux相关学习资料包
相关推荐
星马梦缘5 小时前
EDA彩灯电路绘制
单片机·嵌入式硬件·物联网·pcb·eda·嘉立创
Forsete8 小时前
LINUX驱动开发#9——定时器
linux·驱动开发·单片机
Hello_Embed10 小时前
libmodbus 移植 STM32(USB 串口后端篇)
笔记·stm32·单片机·嵌入式·freertos·libmodbus
VekiSon11 小时前
Linux内核驱动——杂项设备驱动与内核模块编译
linux·c语言·arm开发·嵌入式硬件
来自晴朗的明天12 小时前
14、光耦隔离电路(EL3H7)
单片机·嵌入式硬件·硬件工程
G***技12 小时前
杰和IB3-272:以低功耗高性能打造新一代工业智能交互核心
单片机·嵌入式硬件·物联网
czhaii13 小时前
STC AI8052U单片机特点
单片机
MAR-Sky14 小时前
keil5中数据的不同定义和单片机(以stc8为例)里的对应关系(idata,xdata,data,code)
单片机·嵌入式硬件
项目題供诗15 小时前
51单片机入门(八)
单片机·嵌入式硬件·51单片机