STM32F103C8T6+TB6612FNG驱动未知型号步进电机调试(已完)

简介:

软件开发环境:window11pro ,STM32CubeMX,  Keil5_armv5

调试器: ST_LINK V2 

硬件:

STM32F103C8T6最小开发板一块,

未知名两相四线步进电机一个,

TB6612驱动板一个,

杜邦线若干,

LED灯珠4个。(前期测试输出信号)

结果:已经调试出四拍单步驱动,运行结果正常,只是抖动比较大。

一。电机

1.电机的理论知识

a.步距角:

控制系统发给电机一个脉冲,电机转动的角度。

b.步距角的计算:

步距角的计算方法主要取决于电机的类型和参数。对于步进电机,步距角可以通过以下公式计算:123

  • 步距角=360°/每圈脉冲数。
  • 步距角=360°/步进电机的步数。(步数=拍数?)

对于特定类型的电机,如五相步进电机,步距角可以通过以下公式计算:4

  • 步距角=360°/步数。

对于三相异步电动机,步距角可以通过以下公式计算:5

  • 步距角=360°/(电机极数×3)。

其中,每圈脉冲数、步进电机的步数和电机极数都是特定于电机的参数。此外,某些电机可能会直接在产品技术规格中提供步距角的大小,这样可以直接查阅而无需计算。

2.未知电机拆解图

pos机打印机拆下来的步进电机。

对此了解不多,如下为电机剖解图:

两块线圈中间是两块铁,具体内部结构比较复杂,和塑胶交合在一起详情如下:

分上下两层,每一层有5个突出的铁块

转子是两块圆形磁铁

经测试,这块磁铁不是一体的,环周刚好有五对磁极,与上面的五个铁片对应。

判定为双极性整步驱动

3.未知电机参数

步距角取决于电机上的磁极总数。
步距角的公式如下所示:

步距角=360度/N,其中N=(NPH×PH)

  • NPH:每相的磁极数
  • PH:相数
  • N:各项的磁极总数

磁极齿数:线圈内嵌齿数5*2+外壳齿数5*2 = 20

在此我的理解齿数就是极数。根据步距角计算公式:步距角=360/(极数*运行拍数)计算该电机的步距角如下:

四拍整步的步距角:360/(20*4)=4.5

八拍半步的步距角:360/(20*8)=2.25

二。驱动板

1.电机引脚输出配置

TB6612FNG的主要引脚功能:
(1)AINl/AIN2、BIN1/BIN2、PWMA/PWMB为控制信号输入端;
(2)AO1/A02、B01/B02为2路电机控制输出端;
(3)STBY为正常工作/待机状态控制引脚;
(4)VM(3~13.5 V)和VCC(2.7~5.5 V)分别为电机驱动电压输入和逻辑电平输入端

 上图和部分文字引用了博友的:TB6612FNG模块使用说明-CSDN博客

2.驱动方式

四拍单步:

正转步序AIN1AIN2BIN1BIN2
11000
20100
30010
40001

三。电路引脚与接线

MCUTB6612
PA1

AIN2

PA2AIN1
PA3BIN1
PA4BIN2
PA5STBY
PA6PWMA
PA7PWMB
3.3VCC
GNDGND

1.TB6612引脚图

2. MCU与驱动板连线

四。STM32CubeMX工程配置

1.GPIO配置

2.sys配置

3.TIM配置

4.时钟配置

5.工程配置

五。KEIL工程代码

1.main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 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 "main.h"
#include "tb6612.h"

#define 		LED_PIN GPIO_PIN_13

void SystemClock_Config(void);
static void LED_Init(void);

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* MCU Configuration--------------------------------------------------------*/

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

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

  /* Initialize all configured peripherals */
	LED_Init();
	STEP_MOTOR_init();
	
	int delay_time = 1;
	//STEP_MOTOR_Run(500,20,MOTOR_MODE_FORWORD, delay_time);
  while (1)
  {
    /* USER CODE END WHILE */		
	
		STEP_MOTOR_Run_Step4(10,10);
		delay_time+=2;
		//STEP_MOTOR_Run(100,50,MOTOR_MODE_FORWORD, delay_time++);
		//STEP_MOTOR_Run(1,50,MOTOR_MODE_FORWORD);
		HAL_GPIO_WritePin(GPIOC,LED_PIN,GPIO_PIN_SET);    // close led	
		HAL_Delay(500);			
		HAL_GPIO_WritePin(GPIOC,LED_PIN,GPIO_PIN_RESET);   //OPEN LED
		HAL_Delay(500);
		if(delay_time >100)
			break;
  }
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void LED_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */

  __HAL_RCC_GPIOC_CLK_ENABLE();
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
  /*Configure GPIO pin : PC13 */
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
/* USER CODE END 4 */


#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

2.tb6612.h

#ifndef __TB6612_H__
#define __TB6612_H__


#ifdef __cplusplus
extern "C" {
#endif

#include "stm32f1xx_hal.h"

/*
motor control pin
*/

#define 		AIN1 		GPIO_PIN_1
#define 		AIN2 		GPIO_PIN_2
#define 		BIN1 		GPIO_PIN_3
#define 		BIN2 		GPIO_PIN_4
#define			STBY		GPIO_PIN_5


#define MOTOR_MODE_FORWORD 0
#define MOTOR_MODE_REVERSE 1
#define MOTOR_MODE_BRAKE   2


void STEP_MOTOR_init(void);
void STEP_MOTOR_SetSpeed(int speed);
void STEP_MOTOR_SetMode(int mode);
void STEP_MOTOR_Step4(int step, int interval);
void STEP_MOTOR_Run(int step, int speed, int mode, int arg);
void STEP_MOTOR_Run_Step4(int steps,int interval);
void STEP_MOTOR_Stop(void);
void STEP_MOTOR_Brake(void);


void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
void Error_Handler(void);


#ifdef __cplusplus
}
#endif

#endif





 3.tb6612.c

#include "tb6612.h"


/* Private variables ---------------------------------------------------------*/
static TIM_HandleTypeDef g_htim3;
static int g_isBrake;
/* USER CODE BEGIN PV */

static TIM_OC_InitTypeDef gConfigOC = {0};


void STEP_MOTOR_init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */
  GPIO_InitTypeDef GPIO_InitStruct = {0};

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

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, AIN1|AIN2|BIN1|BIN2|STBY, GPIO_PIN_RESET);

  /*Configure GPIO pins : PA1 PA2 PA3 PA4 PA5 */
  GPIO_InitStruct.Pin = AIN1|AIN2|BIN1|BIN2|STBY;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  //TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */	
	
  /* USER CODE END TIM3_Init 1 */
	
  g_htim3.Instance = TIM3;
  //g_htim3.Init.Prescaler = 16;
  g_htim3.Init.Prescaler = 8-1;
  g_htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  //g_htim3.Init.Period = 65535;
  g_htim3.Init.Period = 10-1;    //TIMx->ARR
  g_htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  g_htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&g_htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&g_htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&g_htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&g_htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
	gConfigOC.OCMode = TIM_OCMODE_PWM1;
  gConfigOC.Pulse = 0;
  gConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  gConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&g_htim3, &gConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&g_htim3, &gConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */	
  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&g_htim3);
	
	HAL_GPIO_WritePin(GPIOA,STBY,GPIO_PIN_SET);    // enable MOTOR
	g_isBrake = 0;
	
	HAL_TIM_PWM_Start(&g_htim3,TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&g_htim3,TIM_CHANNEL_2);

}
void STEP_MOTOR_SetSpeed(int speed)
{
		gConfigOC.Pulse = speed;    
		if (HAL_TIM_PWM_ConfigChannel(&g_htim3, &gConfigOC, TIM_CHANNEL_1) != HAL_OK)//TIMx->CCR1
		{
			Error_Handler();
		}	
		if (HAL_TIM_PWM_ConfigChannel(&g_htim3, &gConfigOC, TIM_CHANNEL_2) != HAL_OK)//TIMx->CCR2
		{
			Error_Handler();
		}	
}
void STEP_MOTOR_SetMode(int mode)
{
	switch(mode)
	{
		case MOTOR_MODE_FORWORD:
			HAL_GPIO_WritePin(GPIOA, AIN1|BIN1, GPIO_PIN_RESET);	
			HAL_GPIO_WritePin(GPIOA, AIN2|BIN2, GPIO_PIN_SET);
		break;
		case MOTOR_MODE_REVERSE:
			HAL_GPIO_WritePin(GPIOA, AIN1|BIN1, GPIO_PIN_SET);	
			HAL_GPIO_WritePin(GPIOA, AIN2|BIN2, GPIO_PIN_RESET);
		break;
		case MOTOR_MODE_BRAKE:
			HAL_GPIO_WritePin(GPIOA, AIN1|AIN2|BIN1|BIN2, GPIO_PIN_SET);	
			
	}
}
//四拍单步驱动
void STEP_MOTOR_Step4(int step, int interval)
{
	switch(step)
	{
		case 0:
			HAL_GPIO_WritePin(GPIOA, AIN2|BIN1|BIN2, GPIO_PIN_RESET);
			HAL_GPIO_WritePin(GPIOA, AIN1, GPIO_PIN_SET);
			break;
		case 1:
			HAL_GPIO_WritePin(GPIOA, AIN1|BIN1|BIN2, GPIO_PIN_RESET);
			HAL_GPIO_WritePin(GPIOA, AIN2, GPIO_PIN_SET);
			break;
		case 2:
			HAL_GPIO_WritePin(GPIOA, AIN1|AIN2|BIN2, GPIO_PIN_RESET);
			HAL_GPIO_WritePin(GPIOA, BIN1, GPIO_PIN_SET);
			break;
		case 3:
			HAL_GPIO_WritePin(GPIOA, AIN1|AIN2|BIN1, GPIO_PIN_RESET);
			HAL_GPIO_WritePin(GPIOA, BIN2, GPIO_PIN_SET);
			break;
		default:
			break;
	}
	HAL_Delay(interval);
	STEP_MOTOR_Stop();
}
void STEP_MOTOR_Run(int steps, int speed, int mode, int arg)
{
	int i;
	if(0)
	{
		HAL_GPIO_WritePin(GPIOA,STBY,GPIO_PIN_SET);    // enable MOTOR
		g_isBrake = 0;
	}		
	for(i = 0; i<steps; i++)
	{
		STEP_MOTOR_SetMode(mode);
		STEP_MOTOR_SetSpeed(speed);
		HAL_Delay(arg);
	}
	STEP_MOTOR_SetSpeed(0);
	//STEP_MOTOR_Brake();
	
}
void STEP_MOTOR_Run_Step4(int steps,int interval)
{
	int i;
	for(i = 0; i < steps; i++)
	{
		g_step++;
		if(g_step>3)g_step=0;
		STEP_MOTOR_Step4(g_step, interval);
	}
}
void STEP_MOTOR_Stop(void)
{
  HAL_GPIO_WritePin(GPIOA, AIN1|AIN2|BIN1|BIN2, GPIO_PIN_RESET);
}

void STEP_MOTOR_Brake(void)
{
		HAL_GPIO_WritePin(GPIOA,STBY,GPIO_PIN_RESET);    // disable MOTOR
		g_isBrake = 1;
}



/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

六.调试曾经出现的问题:

电机不转,只有抖动,为了防止电机过热,main函数里面没有把步进放进while循环。为了方便调试步进延时,我在
    STEP_MOTOR_Run(500,20,MOTOR_MODE_FORWORD, delay_time);

添加了最后的那个参数。调试逻辑:把STEP_MOTOR_Run放进while里面调试,每循环一次增加一次延时,观察电机是否转动。

延时设到了最高100ms依然没有转动,电机只是发出电流震动声。

尝试过如下动作:

1.调换过一次电机线

2.电机驱动电源5V换到12V依然存在。

使用STEP_MOTOR_Run函数的方法是错误的,AB两组输出都是同时通电,并且PWM都是一样的,所以只能听见电流声,电机里面的电磁场还是平衡的,是无法转动的。在此记录一下这个坑。

七。参考:

步进电机 | 东芝半导体&存储产品中国官网 (toshiba-semicon-storage.com)

【资料分享】STM32配置TB6612驱动程序详解_stby引脚-CSDN博客

STM32驱动步进电机(原理、程序、解决电机只震动不转动问题)-CSDN博客

TB6612FNG模块使用说明-CSDN博客

stm32如何控制TB6612步进电机 - CSDN文库

Stm32-使用TB6612驱动电机及编码器测速-CSDN博客

STM32_HAL库—PWM输出_stm32 hal pwm-CSDN博客

STM32通过TB6612FNG模块驱动电机_tb6612 步进电机-CSDN博客

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值