程序功能
单极性步进电机
极性
单极性:电流只有一个方向。用ULN2003A驱动(内含反相器),比较简单。
双极性:电流有两个方向,桥路驱动。
步进电机原理
步进电机驱动方法
步进电机不能直接使用电流源来工作,必须使用专用的步进电机驱动器,它由脉冲发生控制单元,功率驱动单元,保护单元等组成。
28BYJ-48步进电机
28:步进电机的有效最大外径是28毫米
B:表示是步进电机
Y:表示是永磁式
J:表示是减速型(减速比1:64)
48:表示四相八拍
此电机部分参数如图
根据百度搜索和b站视频理解,我认为步进角度就是电机一个脉冲转动的角度,结合下面所讲的驱动方式和后续代码,可以理解为步进电机转动一个脉冲,即1拍,也就转动了一个步进角。减速比我没有理解清楚,根据查询的资料,我感觉应该是,电机内部的某个转动部位转动了64圈后,外部的转轴才转动一圈。
驱动方式
单四拍和双四拍转一周需要2048个脉冲,八拍需要4096个脉冲。
转动位置和通电情况如图(图为自画,比较粗糙)
接线方式
红5接5V电源,其他四个色接驱动的输出端,单片机输出接驱动输入。
皆从红5流入,从各自相中流出
步进电机原理图
ULN2003A驱动
左边为输入,右边为输出,当输入1时,输出0;输入0时,输出1.中间是达林顿管,可以放大微小信号
代码部分
cubemx初始化
各GPIO口配置好相应的标签,利于代码编写。
使用定时器中断每隔5ms控制输出脉冲。
Unipolar_Step_Motor.h
步进电机结构体类型
宏定义4个相的置高置低电平函数
#define SET_Motor_A HAL_GPIO_WritePin(Step_Motor_A_GPIO_Port,Step_Motor_A_Pin,GPIO_PIN_SET);
#define CLR_Motor_A HAL_GPIO_WritePin(Step_Motor_A_GPIO_Port,Step_Motor_A_Pin,GPIO_PIN_RESET);
#define SET_Motor_B HAL_GPIO_WritePin(Step_Motor_B_GPIO_Port,Step_Motor_B_Pin,GPIO_PIN_SET);
#define CLR_Motor_B HAL_GPIO_WritePin(Step_Motor_B_GPIO_Port,Step_Motor_B_Pin,GPIO_PIN_RESET);
#define SET_Motor_C HAL_GPIO_WritePin(Step_Motor_C_GPIO_Port,Step_Motor_C_Pin,GPIO_PIN_SET);
#define CLR_Motor_C HAL_GPIO_WritePin(Step_Motor_C_GPIO_Port,Step_Motor_C_Pin,GPIO_PIN_RESET);
#define SET_Motor_D HAL_GPIO_WritePin(Step_Motor_D_GPIO_Port,Step_Motor_D_Pin,GPIO_PIN_SET);
#define CLR_Motor_D HAL_GPIO_WritePin(Step_Motor_D_GPIO_Port,Step_Motor_D_Pin,GPIO_PIN_RESET);
Unipolar_Step_Motor.c
控制电机正反转
static void Direction_Adjust(void)
{
if(Unipolar_Step_Motor.Status == Start_State)
{
//调整电机运行方向
if(Unipolar_Step_Motor.Direction == Reverse_State)
{
Unipolar_Step_Motor.Direction = Forward_State;
}
else
{
Unipolar_Step_Motor.Direction = Reverse_State;
}
Unipolar_Step_Motor.Circle = Circle_Set_Value;
Unipolar_Step_Motor.Pulse_Cnt = 0;
Display.Disp_HEX(Disp_NUM_6,Unipolar_Step_Motor.Circle,Disp_DP_OFF);
}
}
控制电机转动速度
static void Speed_Adjust(Speed_Change_t Speed_Change)
{
uint8_t temp;
if(Unipolar_Step_Motor.Status == Start_State)
{
if(Speed_Change == Speed_up)
{
//加速
switch(Unipolar_Step_Motor.Speed)
{
case Speed_1: Unipolar_Step_Motor.Speed = Speed_2; temp = 2; break;
case Speed_2: Unipolar_Step_Motor.Speed = Speed_3; temp = 3; break;
case Speed_3: Unipolar_Step_Motor.Speed = Speed_4; temp = 4; break;
case Speed_4: Unipolar_Step_Motor.Speed = Speed_5; temp = 5; break;
case Speed_5: Unipolar_Step_Motor.Speed = Speed_6; temp = 6; break;
case Speed_6: Unipolar_Step_Motor.Speed = Speed_7; temp = 7; break;
case Speed_7: Unipolar_Step_Motor.Speed = Speed_8; temp = 8; break;
case Speed_8: Unipolar_Step_Motor.Speed = Speed_9; temp = 9; break;
case Speed_9: Unipolar_Step_Motor.Speed = Speed_9; temp = 9; break;
default:Unipolar_Step_Motor.Speed = Speed_6; temp = 6;
}
}
else
{
//减速
switch(Unipolar_Step_Motor.Speed)
{
case Speed_1: Unipolar_Step_Motor.Speed = Speed_1; temp = 1; break;
case Speed_2: Unipolar_Step_Motor.Speed = Speed_1; temp = 1; break;
case Speed_3: Unipolar_Step_Motor.Speed = Speed_2; temp = 2; break;
case Speed_4: Unipolar_Step_Motor.Speed = Speed_3; temp = 3; break;
case Speed_5: Unipolar_Step_Motor.Speed = Speed_4; temp = 4; break;
case Speed_6: Unipolar_Step_Motor.Speed = Speed_5; temp = 5; break;
case Speed_7: Unipolar_Step_Motor.Speed = Speed_6; temp = 6; break;
case Speed_8: Unipolar_Step_Motor.Speed = Speed_7; temp = 7; break;
case Speed_9: Unipolar_Step_Motor.Speed = Speed_8; temp = 8; break;
default:Unipolar_Step_Motor.Speed = Speed_6; temp = 6;
}
}
//重置ARR,改变频率
TIM7 ->ARR = Unipolar_Step_Motor.Speed;
//显示速度
Display.Disp_HEX(Disp_NUM_1,temp,Disp_DP_OFF);
}
}
步进一个脉冲
static void Step_One_Pulse(void)
{
static uint8_t Position = 0; //起始位置
//单四拍模式
if(Unipolar_Step_Motor.Drive_Mode == Drive_Mode_Single_4_Beats)
{
if(Unipolar_Step_Motor.Direction == Forward_State)
{
//正转 A - D - C - B
switch(Position)
{
case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
case 1: CLR_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
case 2: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; CLR_Motor_D; break;
case 3: CLR_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
default: System.Error_Handler();
}
}
else
{
//反转 A - B - C - D
switch(Position)
{
case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
case 1: CLR_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
case 2: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; CLR_Motor_D; break;
case 3: CLR_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
default: System.Error_Handler();
}
}
//更新起始位置
if((++Position) == 4)
Position = 0;
}
if(Unipolar_Step_Motor.Drive_Mode == Drive_Mode_Double_4_Beats)
{
if(Unipolar_Step_Motor.Direction == Forward_State)
{
switch(Position)
{
case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
case 1: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; SET_Motor_D; break;
case 2: CLR_Motor_A; SET_Motor_B; SET_Motor_C; CLR_Motor_D; break;
case 3: SET_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
default: System.Error_Handler();
}
}
else
{
switch(Position)
{
case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
case 1: SET_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
case 2: CLR_Motor_A; SET_Motor_B; SET_Motor_C; CLR_Motor_D; break;
case 3: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; SET_Motor_D; break;
default: System.Error_Handler();
}
}
if((++Position) == 4)
Position = 0;
}
if(Unipolar_Step_Motor.Drive_Mode == Drive_Mode_8_Beats)
{
if(Unipolar_Step_Motor.Direction == Forward_State)
{
switch(Position)
{
case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
case 1: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
case 2: CLR_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
case 3: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; SET_Motor_D; break;
case 4: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; CLR_Motor_D; break;
case 5: CLR_Motor_A; SET_Motor_B; SET_Motor_C; CLR_Motor_D; break;
case 6: CLR_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
case 7: SET_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
default:System.Error_Handler();
}
}
else
{
switch(Position)
{
case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
case 1: SET_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
case 2: CLR_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
case 3: CLR_Motor_A; SET_Motor_B; SET_Motor_C; CLR_Motor_D; break;
case 4: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; CLR_Motor_D; break;
case 5: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; SET_Motor_D; break;
case 6: CLR_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
case 7: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
default: System.Error_Handler();
}
}
if((++Position) == 8)
Position = 0;
}
}
定时器中断函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == htim7.Instance)
{
//判断圈数
if(Unipolar_Step_Motor.Circle > 0)
{
//电机转动一个脉冲
Unipolar_Step_Motor.Step_One_Pulse();
//判断电机脉冲计数是否转动了一圈
if(++Unipolar_Step_Motor.Pulse_Cnt == Unipolar_Step_Motor.One_Circle_Pulse)
{
Unipolar_Step_Motor.Pulse_Cnt = 0;
//圈数减1
Unipolar_Step_Motor.Circle--;
Display.Disp_HEX(Disp_NUM_6,Unipolar_Step_Motor.Circle,Disp_DP_OFF);
}
}
//关闭电机
else
{
Unipolar_Step_Motor.Status = Stop_State;
CLR_Motor_A;
CLR_Motor_B;
CLR_Motor_C;
CLR_Motor_D;
LED.LED_OFF(LED3);
}
}
}
通过4个Key实现功能的外部中断函数可参考此前文章STM32物联网——DC直流电机
其他类型步进电机也可在此章编写代码之上略加改变实现功能。