首先基于 STM32F103CBT6 + TMC2209 做了一个简单的步进电机控制功能演示。
硬件上 PA0 输出 TIM2 PWM 作为 STEP,PA1/PA2/PA3/PA4 分别控制 DIR、EN、MS1、MS2。

软件上,配置系统时钟为 72MHz,TIM2 在 PWM 模式下产生步进脉冲,并通过更新中断动态修改 ARR 实现变速。
接着是电机控制的实现:采用 AVR446 梯形速度曲线算法实现加减速的整数迭代计算,支持 1/2、1/4、1/8、1/16 微步切换,主循环按序列往复运动。以上算法全程AI实现,未写一行代码。AI真是太厉害了,真的是解放生产力啊。
/**
* @file main.c
* @brief STM32F103CB + TMC2209 步进电机控制演示程序
*
* 硬件连接:
* PA0 (TIM2_CH1) -----> TMC2209 STEP
* PA1 -----> TMC2209 DIR
* PA2 -----> TMC2209 ENN (低电平使能)
* PA3 -----> TMC2209 MS1 (细分选择位0)
* PA4 -----> TMC2209 MS2 (细分选择位1)
* PA9 (USART1_TX)----> 预留串口
* PA10 (USART1_RX)<---- 预留串口
* MS1, MS2 通过 PA3/PA4 软件控制细分
* SPREAD -----> GND (stealthChop 超静音模式)
*
* 演示运动序列 (循环执行):
* 1. 1/16 细分: 正向 2500 步(1000加速+500匀速+1000减速)≈ 2.07s
* 2. 停止 500ms
* 3. 切换为 1/8 细分: 反向 2500 步
* 4. 停止 500ms
* 5. 切换为 1/4 细分: 正向 2500 步
* 6. 停止 500ms
* 7. 切换为 1/2 细分: 反向 2500 步
* 8. 停止 500ms、恢复 1/16、重复
*
* 时钟配置:
* HSE = 8 MHz, PLL x9 => SYSCLK = 72 MHz
* AHB = 72 MHz, APB1 = 36 MHz (预分频/2), APB2 = 72 MHz
* TIM2 时钟 = 2 * APB1 = 72 MHz (因 APB1 预分频 != 1)
*/
#include "main.h"
#include "tmc2209.h"
#include "stepper.h"
/* ==================== 外设句柄 ==================== */
TIM_HandleTypeDef htim2;
UART_HandleTypeDef huart1;
/* ==================== 私有函数声明 ==================== */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
static void MX_USART1_UART_Init(void);
/* ==================== 主程序 ==================== */
int main(void)
{
/* HAL 库初始化(SysTick 配置,HAL 基础初始化)*/
HAL_Init();
/* 系统时钟配置 => 72 MHz */
SystemClock_Config();
/* 外设初始化(顺序不可随意调整)*/
MX_GPIO_Init(); /* GPIO 必须在 TIM2 前初始化 */
MX_TIM2_Init(); /* TIM2 PWM 配置 */
MX_USART1_UART_Init(); /* USART1 预留 */
/* ---- 应用层初始化 ---- */
TMC2209_Init(); /* 初始化 DIR/EN 引脚,驱动器默认失能 */
Stepper_Init(); /* 初始化步进电机控制模块,设置默认速度/加速度 */
/* 使能 TMC2209 驱动器 (EN = LOW) */
TMC2209_Enable();
/* 等待驱动器就绪(TMC2209 内部上电复位时间 < 1ms,此处留余量)*/
HAL_Delay(10);
/* ==================== 演示主循环 ==================== */
/* 细分循环序列: 1/16 -> 1/8 -> 1/4 -> 1/2 -> 重复 */
const TMC2209_Microstep_t microstep_seq[] = {
TMC2209_MICROSTEP_16,
TMC2209_MICROSTEP_8,
TMC2209_MICROSTEP_4,
TMC2209_MICROSTEP_2,
};
const uint8_t seq_len = (uint8_t)(sizeof(microstep_seq) / sizeof(microstep_seq[0]));
uint8_t seq_idx = 0U;
uint8_t dir = (uint8_t)TMC2209_DIR_CW;
while (1)
{
/* 设置当前细分 */
TMC2209_SetMicrostep(microstep_seq[seq_idx]);
/* 启动梯形速度曲线运动:2500步 */
int8_t ret = Stepper_Move(2500U, dir);
if (ret == 0)
{
while (!Stepper_IsMoveComplete())
{
/* 可执行其他任务 */
}
Stepper_ClearCompleteFlag();
}
/* 停止 500ms */
HAL_Delay(500U);
/* 切换方向 */
dir = (dir == (uint8_t)TMC2209_DIR_CW)
? (uint8_t)TMC2209_DIR_CCW
: (uint8_t)TMC2209_DIR_CW;
/* 切换细分序列 */
seq_idx = (uint8_t)((seq_idx + 1U) % seq_len);
}
}
/* ==================== 外设初始化函数 ==================== */
/**
* @brief 系统时钟配置
* HSE(8MHz) -> PLL x9 -> SYSCLK = 72MHz
* APB1 = 36MHz (TIM2_CLK = 72MHz)
* APB2 = 72MHz
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; /* APB1=36MHz, TIM2=72MHz */
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
Error_Handler();
}
}
/**
* @brief GPIO 初始化
* PA0: TIM2_CH1 复用推挽 (STEP)
* PA1: 推挽输出 (DIR)
* PA2: 推挽输出 (EN, 初始 HIGH=失能)
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
/* PA0 - TIM2_CH1 复用推挽 (STEP) */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* PA1 - 推挽输出 (DIR), 初始 LOW */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* PA2 - 推挺输出 (EN), 初始 HIGH=驱动失能 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* PA3 - 推挺输出 (MS1), 初始 HIGH (1/16细分 MS1=1) */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* PA4 - 推挺输出 (MS2), 初始 HIGH (1/16细分 MS2=1) */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/**
* @brief TIM2 初始化 - PWM 模式 CH1 (PA0)
* PSC=0, TIM2_CLK=72MHz, ARR 动态修改
* CCR1=72 => 1µs 高电平脉冲
*/
static void MX_TIM2_Init(void)
{
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0U;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = (STEPPER_TIM_FREQ / STEPPER_DEFAULT_MIN_SPEED) - 1U;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = STEPPER_PULSE_WIDTH;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) {
Error_Handler();
}
HAL_NVIC_SetPriority(TIM2_IRQn, 2U, 0U);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
/**
* @brief USART1 初始化(预留,115200 8N1)
*/
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200U;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
}
/* ==================== 错误处理 ==================== */
void Error_Handler(void)
{
__disable_irq();
while (1) {}
}
/* ==================== HAL MSP 回调 ==================== */
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim_base)
{
if (htim_base->Instance == TIM2) {
__HAL_RCC_TIM2_CLK_ENABLE();
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim_base)
{
if (htim_base->Instance == TIM2) {
__HAL_RCC_TIM2_CLK_DISABLE();
HAL_NVIC_DisableIRQ(TIM2_IRQn);
}
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (huart->Instance == USART1) {
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/* PA9: USART1_TX */
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* PA10: USART1_RX */
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) {
__HAL_RCC_USART1_CLK_DISABLE();
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10);
}
}/**
* @file stepper.c
* @brief 步进电机梯形速度曲线控制实现
*
* ==========================================================================
* 算法说明 (基于 Atmel AVR446 应用笔记)
* ==========================================================================
*
* 物理背景:
* 匀加速度 a 下,第 n 步的瞬时速度: v(n) = sqrt(2 * a * n + v0^2)
* 对应定时器步进间隔: c(n) = f_timer / v(n)
*
* 直接计算 sqrt 对无 FPU 的 Cortex-M3 代价较高,AVR446 给出整数迭代近似:
*
* 加速段迭代 (delay 递减):
* c[0] = f_timer / min_speed (起始延迟)
* c[n] = c[n-1] - (2 * c[n-1]) / (4*n + 1) n=1,2,3,...
*
* 减速段迭代 (delay 递增,加速的精确逆运算):
* c[n-1] = c[n] + (2 * c[n]) / (4*n - 1) n = accel_steps-1, ..., 1
* 实现时令 n = accel_steps - decel_count,从 accel_steps-1 递减到 1
*
* 误差分析: 整数截断误差 < 1 tick/步,累积不超过 20 ticks/1000步,可忽略
*
* ==========================================================================
* 演示参数验证 (max=2000, min=200, accel=1980, total=2500步)
* accel_steps = (2000^2 - 200^2) / (2*1980) = 3960000 / 3960 = 1000
* decel_steps = 1000 (对称)
* cruise_steps = 2500 - 1000 - 1000 = 500
* min_delay = 72000000 / 2000 = 36000 ticks
* first_delay = 72000000 / 200 = 360000 ticks
* ==========================================================================
*/
#include "main.h"
#include "stepper.h"
#include "tmc2209.h"
/* ==================== 模块实例 ==================== */
static Stepper_t s_stepper;
/* ==================== 内部辅助函数 ==================== */
/**
* @brief 整数平方根(牛顿迭代法)
* @param n 输入值
* @retval floor(sqrt(n))
*/
static uint32_t isqrt32(uint32_t n)
{
if (n == 0U) { return 0U; }
uint32_t x = n;
uint32_t y = (x + 1U) / 2U;
while (y < x) {
x = y;
y = (x + n / x) / 2U;
}
return x;
}
/**
* @brief 启动 TIM2 PWM 并使能更新中断
*/
static void stepper_start_timer(void)
{
/* 清除残留中断标志 */
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);
/* 使能更新中断 */
__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE);
/* 启动 PWM 输出 (PA0 开始输出脉冲) */
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
}
/**
* @brief 停止 TIM2 PWM 并禁用更新中断
*/
static void stepper_stop_timer(void)
{
/* 停止 PWM 输出 */
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1);
/* 禁用更新中断 */
__HAL_TIM_DISABLE_IT(&htim2, TIM_IT_UPDATE);
}
/* ==================== 公开函数实现 ==================== */
void Stepper_Init(void)
{
/* 清空状态 */
s_stepper.state = STEPPER_IDLE;
s_stepper.step_count = 0U;
s_stepper.accel_count = 0U;
s_stepper.cruise_count = 0U;
s_stepper.decel_count = 0U;
s_stepper.position = 0;
s_stepper.direction = 1;
s_stepper.move_complete = 0U;
s_stepper.stop_request = 0U;
/* 设置默认运动参数 */
Stepper_SetMaxSpeed(STEPPER_DEFAULT_MAX_SPEED);
Stepper_SetMinSpeed(STEPPER_DEFAULT_MIN_SPEED);
Stepper_SetAcceleration(STEPPER_DEFAULT_ACCEL);
/* 预置 TIM2 初值(不启动) */
uint32_t init_arr = STEPPER_TIM_FREQ / STEPPER_DEFAULT_MIN_SPEED;
__HAL_TIM_SET_AUTORELOAD(&htim2, init_arr - 1U);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, STEPPER_PULSE_WIDTH);
}
int8_t Stepper_Move(uint32_t steps, uint8_t dir)
{
if (steps == 0U) { return -2; }
if (s_stepper.state != STEPPER_IDLE) { return -1; }
/* 设置方向 */
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;
}
/* 计算步进延迟基准值 */
s_stepper.min_delay = STEPPER_TIM_FREQ / s_stepper.max_speed; /* 最小延迟 (最大速度) */
s_stepper.first_delay = STEPPER_TIM_FREQ / s_stepper.min_speed; /* 起始延迟 (最低速度) */
/* 计算加速段步数: s = (v_max^2 - v_min^2) / (2 * a) */
uint32_t v_max_sq = s_stepper.max_speed * s_stepper.max_speed;
uint32_t v_min_sq = s_stepper.min_speed * s_stepper.min_speed;
uint32_t accel_ideal = (v_max_sq - v_min_sq) / (2U * s_stepper.acceleration);
if (accel_ideal == 0U) { accel_ideal = 1U; }
s_stepper.accel_steps = accel_ideal;
s_stepper.decel_steps = accel_ideal; /* 对称减速 */
if (steps >= (s_stepper.accel_steps + s_stepper.decel_steps)) {
/* 完整梯形曲线 */
s_stepper.cruise_steps = steps - s_stepper.accel_steps - s_stepper.decel_steps;
} else {
/* 三角形曲线:步数不足以达到 max_speed */
s_stepper.accel_steps = steps / 2U;
s_stepper.decel_steps = steps - s_stepper.accel_steps;
s_stepper.cruise_steps = 0U;
/* 重新计算峰值速度对应的最小延迟 */
uint32_t peak_v_sq = 2U * s_stepper.acceleration * s_stepper.accel_steps
+ v_min_sq;
uint32_t peak_v = isqrt32(peak_v_sq);
if (peak_v > s_stepper.max_speed) { peak_v = s_stepper.max_speed; }
if (peak_v < s_stepper.min_speed) { peak_v = s_stepper.min_speed; }
s_stepper.min_delay = STEPPER_TIM_FREQ / peak_v;
}
/* 初始化运行时变量 */
s_stepper.step_count = 0U;
s_stepper.accel_count = 0U;
s_stepper.cruise_count = 0U;
s_stepper.decel_count = 0U;
s_stepper.current_delay = s_stepper.first_delay;
s_stepper.move_complete = 0U;
s_stepper.stop_request = 0U;
/* 设置 TIM2 初始 ARR 和 CCR1 */
uint32_t arr = s_stepper.first_delay - 1U;
if (arr < STEPPER_MIN_ARR) { arr = STEPPER_MIN_ARR; }
__HAL_TIM_SET_AUTORELOAD(&htim2, arr);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, STEPPER_PULSE_WIDTH);
/* 切换到加速状态并启动定时器 */
s_stepper.state = STEPPER_ACCEL;
stepper_start_timer();
return 0;
}
void Stepper_EmergencyStop(void)
{
s_stepper.stop_request = 1U;
stepper_stop_timer();
s_stepper.state = STEPPER_IDLE;
}
void Stepper_SmoothStop(void)
{
if (s_stepper.state == STEPPER_ACCEL) {
/* 加速段:以当前已加速步数作为减速步数 */
s_stepper.decel_steps = s_stepper.accel_count + 1U;
s_stepper.cruise_steps = 0U;
s_stepper.decel_count = 0U;
s_stepper.state = STEPPER_DECEL;
} else if (s_stepper.state == STEPPER_CRUISE) {
/* 匀速段:直接切入减速 */
s_stepper.decel_count = 0U;
s_stepper.state = STEPPER_DECEL;
}
/* 已在减速或空闲:不操作 */
}
uint8_t Stepper_IsRunning(void)
{
return (s_stepper.state != STEPPER_IDLE) ? 1U : 0U;
}
uint8_t Stepper_IsMoveComplete(void)
{
return s_stepper.move_complete;
}
void Stepper_ClearCompleteFlag(void)
{
s_stepper.move_complete = 0U;
}
int32_t Stepper_GetPosition(void)
{
return s_stepper.position;
}
void Stepper_SetMaxSpeed(uint32_t speed)
{
if (speed > 0U) { s_stepper.max_speed = speed; }
}
void Stepper_SetMinSpeed(uint32_t speed)
{
if (speed > 0U) { s_stepper.min_speed = speed; }
}
void Stepper_SetAcceleration(uint32_t accel)
{
if (accel > 0U) { s_stepper.acceleration = accel; }
}
/* ==================== 核心中断服务程序 ==================== */
/**
* @brief TIM2 更新中断处理
*
* 时序说明:
* TIM2 计数器从 0 计数到 ARR,发生溢出更新事件 => 进入此中断
* 此时 TIM2 PWM 已完成一个脉冲周期(一个 STEP 上升沿已产生)
* 计算下一步所需延迟,更新 ARR 即可改变下一步的步进频率
*
* 关键: 不经过 HAL 中断分发(直接注册在 TIM2_IRQHandler),
* 减少约 20-30 个时钟周期的中断延迟
*/
void Stepper_TIM2_IRQHandler(void)
{
/* 检查并清除更新中断标志 */
if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) == RESET) {
return;
}
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);
/* 紧急停止检查 */
if (s_stepper.stop_request != 0U) {
stepper_stop_timer();
s_stepper.state = STEPPER_IDLE;
return;
}
/* 累计步数和绝对位置 */
s_stepper.step_count++;
s_stepper.position += s_stepper.direction;
/* ===== 梯形速度曲线状态机 ===== */
switch (s_stepper.state) {
/* ---- 加速阶段 ---- */
case STEPPER_ACCEL: {
s_stepper.accel_count++;
if (s_stepper.accel_count < s_stepper.accel_steps) {
/*
* AVR446 加速迭代公式:
* c[n] = c[n-1] - (2 * c[n-1]) / (4*n + 1)
* n = accel_count (本次加速已走步数)
*/
uint32_t n = s_stepper.accel_count;
uint32_t delta = (2U * s_stepper.current_delay) / (4U * n + 1U);
if (delta > 0U) {
s_stepper.current_delay -= delta;
}
/* 钳位到最小延迟(不超过最大速度) */
if (s_stepper.current_delay < s_stepper.min_delay) {
s_stepper.current_delay = s_stepper.min_delay;
}
} else {
/* 加速段完成 */
s_stepper.current_delay = s_stepper.min_delay;
if (s_stepper.cruise_steps > 0U) {
s_stepper.state = STEPPER_CRUISE;
s_stepper.cruise_count = 0U;
} else {
s_stepper.state = STEPPER_DECEL;
s_stepper.decel_count = 0U;
}
}
/* 更新 ARR */
uint32_t arr = s_stepper.current_delay;
if (arr < STEPPER_MIN_ARR + 1U) { arr = STEPPER_MIN_ARR + 1U; }
__HAL_TIM_SET_AUTORELOAD(&htim2, arr - 1U);
break;
}
/* ---- 匀速阶段 ---- */
case STEPPER_CRUISE: {
s_stepper.cruise_count++;
if (s_stepper.cruise_count >= s_stepper.cruise_steps) {
/* 匀速段完成,进入减速 */
s_stepper.state = STEPPER_DECEL;
s_stepper.decel_count = 0U;
}
/* ARR 保持 min_delay-1 不变,无需写入 */
break;
}
/* ---- 减速阶段 ---- */
case STEPPER_DECEL: {
s_stepper.decel_count++;
if (s_stepper.decel_count >= s_stepper.decel_steps) {
/* 运动完成 */
stepper_stop_timer();
s_stepper.state = STEPPER_IDLE;
s_stepper.move_complete = 1U;
} else {
/*
* AVR446 减速迭代公式 (加速的精确逆运算):
* c[n] = c[n-1] + (2 * c[n-1]) / (4*n - 1)
* n = accel_steps - decel_count (从 accel_steps-1 递减到 1)
*/
uint32_t n = s_stepper.accel_steps - s_stepper.decel_count;
if (n == 0U) { n = 1U; } /* 安全保护 */
uint32_t delta = (2U * s_stepper.current_delay) / (4U * n - 1U);
s_stepper.current_delay += delta;
uint32_t arr = s_stepper.current_delay;
if (arr < STEPPER_MIN_ARR + 1U) { arr = STEPPER_MIN_ARR + 1U; }
__HAL_TIM_SET_AUTORELOAD(&htim2, arr - 1U);
}
break;
}
/* ---- 空闲(防御性处理)---- */
default: {
stepper_stop_timer();
s_stepper.state = STEPPER_IDLE;
break;
}
}
}最后是调试与排错:运行时发现电极特别烫,在网友帮助下,发现TMC2209模块有个调试Vref电平的可调电阻,因为电机的电流很小,要把Vref调的足够小才可以。这个在模块说明中有介绍,还是要仔细看说明书。
我要赚赏金
