STM32F1单片机驱动42步进电机

我们使用的单片机是STM32F103ZET6,电机是42步进电机(额定电流是1A)、驱动是TMC2209;但是暂时使用2160这个外接驱动(注意:2160为大电流电机驱动不能长时间带动这个42电机,否则会发烫烧电机)。

  1. 开启一个定时器2外设中断:为电机提供步进脉冲;

  2. 开启三个GPIO口:作为EN、STEP、DIR控制;

  3. 42步进电机:步距角1.8°、16细分、3200步每圈。

一、代码:

tim.c:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */
// 在全局变量区添加
uint8_t StepperState;
volatile uint32_t step_counter;
volatile bool rotation_enable;

/* USER CODE END 0 */

TIM_HandleTypeDef htim2;

/* TIM2 init function */
void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 36 - 1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 100 - 1;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */
  HAL_TIM_Base_Start_IT(&htim2);
  /* USER CODE END TIM2_Init 2 */

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspInit 0 */

  /* USER CODE END TIM2_MspInit 0 */
    /* TIM2 clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();

    /* TIM2 interrupt Init */
    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspInit 1 */

  /* USER CODE END TIM2_MspInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspDeInit 0 */

  /* USER CODE END TIM2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM2_CLK_DISABLE();

    /* TIM2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspDeInit 1 */

  /* USER CODE END TIM2_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */


/* 电机调速函数(TIM2重新配置频率函数) */
void Stepper_SetSpeed(uint32_t new_period, uint16_t new_prescaler)
{
  HAL_TIM_Base_Stop_IT(&htim2);
  
  htim2.Init.Prescaler = new_prescaler;
  htim2.Init.Period = new_period;
  
  if (HAL_TIM_Base_Init(&htim2) == HAL_OK) {
    HAL_TIM_Base_Start_IT(&htim2);
  }
}


/*
 * @brief: 步进电机控制函数
 * @param: step_mode: 步进模式,1为正常运动,2为正反转
 * @return: 无
 * @note: 步进电机控制函数,根据步进模式控制步进电机的运动

*/
void Stepper_Isr(uint8_t step_mode)
{
  static uint8_t dir_switch = 0;

  if(rotation_enable) {
    // 生成步进脉冲(电平翻转)
    if (StepperState == 0)
    {
      MOTOR_STEP_H;
      StepperState = 1;
    }
    else
    {
      MOTOR_STEP_L;
      StepperState = 0;
      step_counter++;
    }
    
    if(step_counter >= (MOTOR_ONE_CIRCLE_STEP * MOTOR_NUM) && step_mode == 1) { 
      step_counter = 0;
      static uint8_t motor_speed = 0;
      switch (motor_speed)
      {
        case 0:
          Stepper_SetSpeed(800 - 1, 36 - 1);
          break;
        
        case 1:
          Stepper_SetSpeed(600 - 1, 36 - 1);
          break;

        case 2:
          Stepper_SetSpeed(400 - 1, 36 - 1);
          break;

        case 3:
          Stepper_SetSpeed(200 - 1, 36 - 1);
          break;

        case 4:
          Stepper_SetSpeed(100 - 1, 36 - 1);
          break;
      
        default:
          break;
      }      
      motor_speed++;
      if(motor_speed >= 5) {
        motor_speed = 0;
      }
    }

    // 仅在上升沿计数
    if(step_counter >= 3200 && step_mode == 2) { 
        step_counter = 0;
        // 切换方向
      if (dir_switch == 0)
      {
        MOTOR_DIR_REVER;
        dir_switch = 1;
      }
      else
      {
        MOTOR_DIR_CW;
        dir_switch = 0;
      }
    }
  }
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim == (&htim2))
  {
    Stepper_Isr(0);
  }
}


/* USER CODE END 1 */

tim.h

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.h
  * @brief   This file contains all the function prototypes for
  *          the tim.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __TIM_H__
#define __TIM_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

extern TIM_HandleTypeDef htim2;

/* USER CODE BEGIN Private defines */
#define MOTOR_ONE_CIRCLE_STEP     3200       // 电机每圈的步数
#define MOTOR_NUM                 1          // 电机跑的圈数

/* USER CODE END Private defines */

void MX_TIM2_Init(void);

/* USER CODE BEGIN Prototypes */
void Stepper_Isr(uint8_t step_mode);

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __TIM_H__ */

stm32f1xx_it.c:

/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

main.c

/* Private defines -----------------------------------------------------------*/
#define MOTOR_EN_Pin GPIO_PIN_0
#define MOTOR_EN_GPIO_Port GPIOF
#define MOTOR_DIR_Pin GPIO_PIN_1
#define MOTOR_DIR_GPIO_Port GPIOF
#define MOTOR_STEP_Pin GPIO_PIN_2
#define MOTOR_STEP_GPIO_Port GPIOF

/* USER CODE BEGIN Private defines */
#define MOTOR_EN_ON     HAL_GPIO_WritePin(MOTOR_EN_GPIO_Port, MOTOR_EN_Pin, GPIO_PIN_RESET)
#define MOTOR_EN_OFF    HAL_GPIO_WritePin(MOTOR_EN_GPIO_Port, MOTOR_EN_Pin, GPIO_PIN_SET)
#define MOTOR_DIR_CW    HAL_GPIO_WritePin(MOTOR_DIR_GPIO_Port, MOTOR_DIR_Pin, GPIO_PIN_SET)
#define MOTOR_DIR_REVER HAL_GPIO_WritePin(MOTOR_DIR_GPIO_Port, MOTOR_DIR_Pin, GPIO_PIN_RESET)
#define MOTOR_STEP_H    HAL_GPIO_WritePin(MOTOR_STEP_GPIO_Port, MOTOR_STEP_Pin, GPIO_PIN_SET)
#define MOTOR_STEP_L    HAL_GPIO_WritePin(MOTOR_STEP_GPIO_Port, MOTOR_STEP_Pin, GPIO_PIN_RESET)


void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOF_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOF, MOTOR_EN_Pin|MOTOR_DIR_Pin|MOTOR_STEP_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pins : PFPin PFPin PFPin */
  GPIO_InitStruct.Pin = MOTOR_EN_Pin|MOTOR_DIR_Pin|MOTOR_STEP_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
}


/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
  MOTOR_EN_ON;
  MOTOR_DIR_CW;
  rotation_enable = true;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    HAL_Delay(1000);
  }
  /* USER CODE END 3 */
}

二、调速:

步进电机的速度通常是通过改变脉冲的频率来调节的,也就是调整定时器的中断频率。因此,调速的关键在于修改定时器的预分频器(Prescaler)或自动重装载值(Period)。

1、调速原理:

  • 定时器频率计算公式:Freq = CPU_Freq / (Prescaler + 1) / (Period + 1)
  • 假设CPU时钟72MHz,默认参数(36-1,1000-1)产生2kHz中断
  • 周期值越小/预分频值越小 → 中断频率越高 → 电机转速越快

注意:实际使用时要确保新参数在定时器的有效范围内(0x0000-0xFFFF)

// 示例:提高速度(减小周期值)
Stepper_SetSpeed(500 - 1, 36 - 1);  // 2倍速

// 示例:降低速度(增大周期值)
Stepper_SetSpeed(2000 - 1, 36 - 1); // 半速

### STM32F103ZET6 驱动步进电机教程 #### 硬件连接 为了使STM32F103ZET6能够有效地控制步进电机,硬件部分的设计至关重要。通常情况下,会采用一个专门设计用于驱动步进电机驱动模块来简化电路并提高可靠性。对于57型闭环步进电机而言,推荐使用共阴极接法进行连接[^1]。 具体来说,在构建该系统的物理连接时,需要准备如下组件: - **STM32F103ZET6 开发板** - **步进电机驱动器**(例如TB6600) - **目标步进电机** 这些元件之间的典型连接方式包括但不限于将STM32的GPIO引脚配置成PWM输出模式,并通过合适的接口与驱动器相连;而驱动器则负责接收来自MCU的信号并对实际电机施加相应的电流以实现精确的位置或速度控制[^2]。 #### 示例代码 下面给出一段基于标准库编写的C语言程序片段,展示了如何利用定时器生成PWM波形从而间接调控步进电机的动作频率和方向。这段代码适用于STM32系列单片机平台上的应用开发环境。 ```c #include "stm32f1xx_hal.h" TIM_HandleTypeDef htim2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); while (1){ /* 用户逻辑 */ } } // 定义PWM参数设置函数 void Set_PWM_DutyCycle(uint32_t Channel, uint32_t DutyCycle){ __HAL_TIM_SET_COMPARE(&htim2, Channel, DutyCycle); } ``` 此段代码初始化了一个定时器实例`htim2`,并通过定义辅助方法`Set_PWM_DutyCycle()`允许动态调整指定通道下的占空比值。这使得开发者可以根据需求灵活改变发送给步进电机的具体脉冲宽度调制指令。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值