【STM32】使用HAL库对ULN2003控制28BYJ-48步进电机

3 篇文章 0 订阅

步进电机是将电脉冲信号转变为角位移或线位移,通过控制施加在电机线圈上的电脉冲顺序、频率和数量,可以控制步进电机的转向、速度和旋转角度。

配合以直线运动执行机构(螺纹丝杆)或齿轮箱装置,更可以实现更加复杂、精密的线性运动控制要求。

在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响。

当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度,称为“步距角”。

它的旋转是以固定的角度一步一步运行的,可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的。同时可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。

步进电机28BYJ-48名称含义:

28:表示步进电机的有效最大外径为28毫米

B:表示步进电机“步”字汉语拼音首字母

Y:表示永磁式“永”字汉语拼音首字母,永磁式表示转子为永磁体

J:表示减速型“减”字汉语拼音首字母

BYJ:组合即为永磁式减速步进电机

48:表示四相八拍,后续介绍

5V:表示额定电压为5V,且为直流电压

此步进电机有五根线(12345),5为公共端,假设5接VCC,1-4接GND。那么1-5、2-5、3-5、4-5为四条通路,称为五线四相。

如果1-5导通,然后1-5断开的同时2-5导通,接着2-5断开,3-5导通,之后3-5断开,4-5导通,之后4-5断开,1-5导通。如此循环下去,称之为四拍。

因为四拍的步距角过大,所以可以选择在两路交接的时候,让两路都导通一段时间,可以减少步距角。如下表八拍的表示方法:

若假设正转的分配顺序是1-8,则反转的分配顺序就是8-1。

查阅28BYJ-48的手册,其步距角是5.625/64度,减速比是1/64。

控制步进电机,说白了就是控制GPIO的高低电平。

此步进电机需要驱动板驱动,使用ULN2003,实物如下图所示。

当IN输入为0时,控制引脚不工作;当IN输入为1时,控制引脚输出为1。

只需要对IN1-4分别设置不同的电平,便可实现电机的运转和方向控制。

通过cubeMX设置外部时钟还有GPIO输出,使用STM32F407ZGT6。

 设置时钟树

生成代码。

最终代码: 

//为了编程方便,首先宏定义一些代码
#define MOTOR_A_H HAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, GPIO_PIN_SET);
#define MOTOR_A_L HAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, GPIO_PIN_RESET);
	
#define MOTOR_B_H HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_SET);
#define MOTOR_B_L HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_RESET);
	
#define MOTOR_C_H HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_SET);
#define MOTOR_C_L HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET);
	
#define MOTOR_D_H HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_SET);
#define MOTOR_D_L HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_RESET);

void MOTOR_CONTROL(uint16_t direction)//对电机进行控制,使用八拍
{
	static uint8_t step=0;
	if(1== direction)//控制电机方向
	{
		if(0==step)
		{
			step=8;
		}
		step--;
	}	
	else if(0== direction)
	{
		step++;
		if(8==step)
		{
			step=0;
		}
	}
	if(0==step)
	{
		MOTOR_A_H;
		MOTOR_B_L;
		MOTOR_C_L;
		MOTOR_D_L;
	}
	else if(1==step)
	{
		MOTOR_A_H;
		MOTOR_B_H;
		MOTOR_C_L;
		MOTOR_D_L;
	}
	else if(2==step)
	{
		MOTOR_A_L;
		MOTOR_B_H;
		MOTOR_C_L;
		MOTOR_D_L;
	}
	else if(3==step)
	{
		MOTOR_A_L;
		MOTOR_B_H;
		MOTOR_C_H;
		MOTOR_D_L;
	}
	else if(4==step)
	{
		MOTOR_A_L;
		MOTOR_B_L;
		MOTOR_C_H;
		MOTOR_D_L;
	}
	else if(5==step)
	{
		MOTOR_A_L;
		MOTOR_B_L;
		MOTOR_C_H;
		MOTOR_D_H;
	}
	else if(6==step)
	{
		MOTOR_A_L;
		MOTOR_B_L;
		MOTOR_C_L;
		MOTOR_D_H;
	}
	else if(7==step)
	{
		MOTOR_A_H;
		MOTOR_B_L;
		MOTOR_C_L;
		MOTOR_D_H;
	}
}

void Step_MOTOR_Start(uint16_t angle,uint8_t direction)//电机启动
{
	int i=0;
	int pulse =(int)((float)(angle*64/5.625));//脉冲与步距角的关系
	for(i=0;i<pulse;i++)
	{
		MOTOR_CONTROL(direction);
		HAL_Delay(2);
	}
}

void Step_MOTOR_Stop(void)//四相都是低电平代表电机停止
{
	MOTOR_A_L;
	MOTOR_B_L;
	MOTOR_C_L;
	MOTOR_D_L;
}
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();
  /* USER CODE BEGIN 2 */
	Step_MOTOR_Start(360,0);
	Step_MOTOR_Stop();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
步进电机驱动的实现可以采用28BYJ-48步进电机驱动板,驱动板上自带 ULN2003 驱动芯片,可以方便地使用基于 STM32控制器进行控制。在使用 STM32 HAL 库驱动步进电机时,可以按照以下步骤进行: 1. 初始化 GPIO 端口和定时器。在 HAL 库中,可以使用 HAL_GPIO_Init 和 HAL_TIM_Base_Init 函数进行初始化。 2. 配置 GPIO 端口的输出模式,设置为推挽输出模式。可以使用 HAL_GPIO_WritePin 函数将 GPIO 端口输出设置为高电平或低电平,从而控制步进电机的转向。 3. 配置定时器的计数值和分频值,以控制步进电机的速度。可以使用 HAL_TIM_Base_Start_IT 函数启动定时器,以产生中断并控制步进电机的转动。 4. 在定时器中断服务函数中,根据步进电机的转向和步长控制 GPIO 端口的输出状态,从而实现步进电机的正转、反转和速度控制。 下面是一个示例代码,可以实现控制28BYJ-48步进电机的正转、反转和速度控制功能: ```c #include "stm32f1xx_hal.h" #define STEPPER_PORT GPIOA #define STEPPER_IN1_PIN GPIO_PIN_0 #define STEPPER_IN2_PIN GPIO_PIN_1 #define STEPPER_IN3_PIN GPIO_PIN_2 #define STEPPER_IN4_PIN GPIO_PIN_3 #define STEPPER_SPEED 1000 TIM_HandleTypeDef htim2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); void stepper_forward(void); void stepper_reverse(void); void stepper_stop(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); HAL_TIM_Base_Start_IT(&htim2); while (1) { stepper_forward(); HAL_Delay(2000); stepper_reverse(); HAL_Delay(2000); } } void stepper_forward(void) { HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN1_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN2_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN3_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN4_PIN, GPIO_PIN_RESET); } void stepper_reverse(void) { HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN1_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN2_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN3_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN4_PIN, GPIO_PIN_SET); } void stepper_stop(void) { HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN1_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN2_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN3_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN4_PIN, GPIO_PIN_RESET); } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { static int step = 0; static int dir = 1; if (dir == 1) { switch (step) { case 0: stepper_forward(); break; case 1: HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN1_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN2_PIN, GPIO_PIN_SET); break; case 2: HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN3_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN4_PIN, GPIO_PIN_SET); break; case 3: HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN2_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN3_PIN, GPIO_PIN_SET); break; default: break; } } else { switch (step) { case 0: stepper_reverse(); break; case 1: HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN2_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN3_PIN, GPIO_PIN_SET); break; case 2: HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN1_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN2_PIN, GPIO_PIN_SET); break; case 3: HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN3_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(STEPPER_PORT, STEPPER_IN4_PIN, GPIO_PIN_SET); break; default: break; } } step += dir; if (step >= 4) { step = 0; } else if (step < 0) { step = 3; } TIM2->ARR = STEPPER_SPEED; } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); 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; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } static void MX_TIM2_Init(void) { TIM_MasterConfigTypeDef sMasterConfig; htim2.Instance = TIM2; htim2.Init.Prescaler = 7200 - 1; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = STEPPER_SPEED; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } HAL_TIM_MspPostInit(&htim2); } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = STEPPER_IN1_PIN | STEPPER_IN2_PIN | STEPPER_IN3_PIN | STEPPER_IN4_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(STEPPER_PORT, &GPIO_InitStruct); } void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_InitStruct; if (htim->Instance == TIM2) { __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM2 GPIO Configuration PA1 ------> TIM2_CH2 */ GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } } void Error_Handler(void) { while (1) { } } #ifdef USE_FULL_ASSERT void assert_failed(uint8_t *file, uint32_t line) { } #endif ``` 需要注意的是,步进电机控制需要按照一定的步序进行,因此在定时器中断服务函数中需要控制每一步的输出状态,从而实现步进电机的正转、反转和速度控制。在上述代码中,步进电机控制采用了半步控制方式,可以根据需要进行调整。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值