ULN2003的工作原理
28BYJ48可以用ULN2003来驱动,STM32使用开漏模式外接5V上拉电阻也可以产生5V电压,为什么不直接使用单片机的
GPIO来驱动的原因是虽然电压符合电机的驱动要求,但单片机引脚产生的驱动电流太小,因此驱动步进电机要使用专门的电机驱动模块来进行驱动。
IN1、IN2、IN3、IN4分别接STM32的4个GPIO引脚,用4个引脚要控制驱动模块。
具体驱动程序
stepmotor.h
#ifndef __STEPPING_MOTOR_H
#define __STEPPING_MOTOR_H
#include "./SYSTEM/sys/sys.h"
/******************************************************************************************/
/* MOTOR IO操作函数 定义 */
#define MOTOR_A GPIO_PIN_3
#define MOTOR_B GPIO_PIN_4
#define MOTOR_C GPIO_PIN_5
#define MOTOR_D GPIO_PIN_6
#define MOTOR_A_H HAL_GPIO_WritePin(GPIOG, GPIO_PIN_3, GPIO_PIN_SET)
#define MOTOR_A_L HAL_GPIO_WritePin(GPIOG, GPIO_PIN_3, GPIO_PIN_RESET)
#define MOTOR_B_H HAL_GPIO_WritePin(GPIOG, GPIO_PIN_4, GPIO_PIN_SET)
#define MOTOR_B_L HAL_GPIO_WritePin(GPIOG, GPIO_PIN_4, GPIO_PIN_RESET)
#define MOTOR_C_H HAL_GPIO_WritePin(GPIOG, GPIO_PIN_5, GPIO_PIN_SET)
#define MOTOR_C_L HAL_GPIO_WritePin(GPIOG, GPIO_PIN_5, GPIO_PIN_RESET)
#define MOTOR_D_H HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_SET)
#define MOTOR_D_L HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET)
/******************************************************************************************/
/* MOTOR 函数 定义 */
void StepMotor_init(void);
void StepMotor_Move(uint8_t dir);
void StepMotor_Stop(void);
#endif
stepmotor.c
#include "./BSP/STEPPING_MOTOR/stepping_motor.h"
#include "./SYSTEM/delay/delay.h"
//此程序用来控制步进电机旋转固定角度后停下来。
//设置定时器的PSC和ARR可以控制步进电机运行的频率/速度
//此程序利用定时器更新中断和静态变量的方法使主程序中某一时刻置标志位后就使电机旋转固定角度。
extern uint8_t lastmove; //lastmove=0电机正转一定角度,lastmove=1电机反转一定角度
TIM_HandleTypeDef g_tim_handle;
extern uint32_t pulse; //设置要转的角度(运行多少个脉冲数量),每个脉冲转5.625/64度
void StepMotor_init(void)
{
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_TIM2_CLK_ENABLE();
GPIO_InitTypeDef gpio_struct;
gpio_struct.Pin = MOTOR_A | MOTOR_B | MOTOR_C | MOTOR_D;
gpio_struct.Mode = GPIO_MODE_OUTPUT_PP;//推挽输出
gpio_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOC, &gpio_struct);
g_tim_handle.Instance = TIM1;
g_tim_handle.Init.Prescaler = 19;
g_tim_handle.Init.Period = 7199;
g_tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_Base_Init(&g_tim_handle);
HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
HAL_TIM_Base_Start_IT(&g_tim_handle);
//HAL_TIM_Base_Stop_IT(&g_tim_handle);
}
//步进电机驱动函数: dir:1表示电机正转;0表示反转
void StepMotor_Move(uint8_t dir)
{
static uint8_t step = 0;
if(dir == 0)
{
if(step == 0)
step = 8;
step--;
}
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;
}
if(dir == 1)
{
step++;
if(step == 8)
{
step = 0;
}
}
}
void StepMotor_Stop(void)
{
MOTOR_A_L;
MOTOR_B_L;
MOTOR_C_L;
MOTOR_D_L;
}
void TIM1_UP_IRQHandler(void)
{
/* 以下代码没有使用定时器HAL库共用处理函数来处理,而是直接通过判断中断标志位的方式 */
if(__HAL_TIM_GET_FLAG(&g_tim_handle, TIM_FLAG_UPDATE) != RESET)
{
static uint32_t i = 0;
i++;
if(lastmove == 0)
{
StepMotor_Move(1);
if(i > pulse)
{
StepMotor_Stop();
lastmove = 2;
i = 0;
}
}
else if(lastmove == 2)
{
i = 0;
StepMotor_Stop();
}
else if(lastmove == 1)
{
StepMotor_Move(0);
if(i > pulse)
{
StepMotor_Stop();
lastmove = 2;
i = 0;
//HAL_TIM_Base_Stop_IT(&g_tim_handle);
}
}
__HAL_TIM_CLEAR_IT(&g_tim_handle, TIM_IT_UPDATE); /* 清除定时器溢出中断标志位 */
}
}