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

共2条 1/1 1 跳转至

【let'sdo|2026年第1期】静音步进电机控制实践——过程帖

助工
2026-06-21 15:44:53     打赏

首先基于 STM32F103CBT6 + TMC2209 做了一个简单的步进电机控制功能演示。

硬件上 PA0 输出 TIM2 PWM 作为 STEP,PA1/PA2/PA3/PA4 分别控制 DIR、EN、MS1、MS2。

9cfd40664faaa9a6143e967722273a62.jpg

软件上,配置系统时钟为 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调的足够小才可以。这个在模块说明中有介绍,还是要仔细看说明书。








助工
2026-06-21 22:15:37     打赏
2楼

经后面调试发现,AI生成的代码配置中,细分步数错误,和手册不一样,幻觉还是有的,但电机确实能动了。


共2条 1/1 1 跳转至

回复

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