28BYJ-48 步进电机驱动代码
步进电机是一种将电脉冲转化为角位移的执行机构。通俗一点讲:当步进驱动器接收到 一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(及步进角)。可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时也可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。
步进电机 28BYJ-48 型四相八拍电机,电压为 DC5V---DC12V。当对步进电机施加一系列连续不断的控制脉冲时,它可以连续不断地转动。每一个脉冲信号对应步进电机的某一相或两相绕组的通电状态改变一次,也就对应转子转过一定的角度(一个步距角)。当通电状态的改变完成一个循环时,转子转过一个齿距。四相步进电机可以在不同的通电方式下运行,常见的通电方式有单(单相绕组通电) 四拍(A-B-C-D-A- · · ·),双(双相绕组通电)四拍(AB-BC- CD-DA-AB- · · ·),八拍 (A-AB-B-BC-C-CD-D-DA-A- · · ·)
四相步进电机有两种运行方式,一、四相四拍;二、四相八拍。要想搞清楚四相八拍运行方式下步进电机的转速如果计算,需要先清楚两个基本概念。
1、拍数: 完成一个磁场周期性变化所需脉冲数用 n 表示,或指电机转过一个齿距角所需脉冲数,以四相电机为例,有四相四拍运行方式即AB-BC-CD-DA-AB,四相八拍运行方式即 A-AB-B-BC-C-CD-D-DA-A. (拍数 = 走完一整圈磁场循环,需要多少种通电组合状态)
2、步距角: 对应一个脉冲信号,电机转子转过的角位移用θ表示。θ=360 度(转子齿数 J * 运行拍数),以常规二、四相,转子齿为50 齿电机为例。四拍运行时步距角为θ=360 度 /(50 * 4)=1.8 度 (俗称整步),八拍运行时步距角为θ=360度 /(50 * 8)=0.9 度(俗称半步)。 这两个概念清楚后,再来计算转速,以基本步距角 1.8°的步进电机为例(现在市场上常规的二、 四相混合式步进电机基本步距角都是 1.8°),四相八拍运行方式下,每接收一个脉冲信号,转过0.9°,如果每秒钟接收 400 个脉冲,那么转速为每秒 400X0.9°=360°,相当与每秒钟转一圈,每分钟 60 转。(给电机发 1 个脉冲、走 1 拍,电机实际转过的角度,就是步距角。)
总结如下:
拍数:电机通电有多少种组合状态,越多走得越细。
步距角:每走一拍转过的角度,拍数越多、步距角越小、精度越高。
28BYJ-48 五线四相步进电机的 8 拍驱动通电顺序图(代码中写作 MOTOR_Rhythm_4_1_8)

4-1-2 相驱动 ,就是常说的 半步 / 8 拍驱动
意思是:1 相通电(单拍)和 2 相通电(双拍)交替进行
- 单拍(1 相):比如节拍 1、3、5、7
- 双拍(2 相):比如节拍 2、4、6、8
这样交替的好处:
- 步距角减半,精度高一倍
- 运行更顺滑,抖动和噪音更小
- 力矩比纯单拍模式更均匀
电路原理图

驱动代码:
stepmotor.c
c
#include "stepmotor.h"
/**
* @brief 步进电机GPIO初始化函数
* @param 无
* @retval 无
*/
void MOTOR_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(MOTOR_CLK, ENABLE); //使能步进电机GPIO端口时钟
GPIO_InitStructure.GPIO_Pin = MOTOR_A|MOTOR_B|MOTOR_C|MOTOR_D;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //配置电机4相引脚为推挽输出模式
GPIO_Init(MOTOR_PROT,&GPIO_InitStructure);
GPIO_ResetBits(GPIOA, MOTOR_A|MOTOR_D|MOTOR_B|MOTOR_C); //初始化所有相输出低电平
}
/**
* @brief 4相单4拍驱动函数(每次只导通一相)
* @param step: 当前节拍序号(1~4)
* @param dly: 节拍延时时间(ms)
* @retval 无
*/
void MOTOR_Rhythm_4_1_4(uint8_t step,uint8_t dly)
{
switch(step)
{
case 1 :
MOTOR_A_HIGH;MOTOR_B_LOW;MOTOR_C_LOW;MOTOR_D_LOW; //A相导通
break;
case 2 :
MOTOR_A_LOW;MOTOR_B_HIGH;MOTOR_C_LOW;MOTOR_D_LOW; //B相导通
break;
case 3 :
MOTOR_A_LOW;MOTOR_B_LOW;MOTOR_C_HIGH;MOTOR_D_LOW; //C相导通
break;
case 4 :
MOTOR_A_LOW;MOTOR_B_LOW;MOTOR_C_LOW;MOTOR_D_HIGH; //D相导通
break;
}
delay_ms(dly); //延时控制电机转速
}
/**
* @brief 4相双4拍驱动函数(每次同时导通两相)
* @param step: 当前节拍序号(1~4)
* @param dly: 节拍延时时间(ms)
* @retval 无
*/
void MOTOR_Rhythm_4_2_4(uint8_t step,uint8_t dly)
{
switch(step)
{
case 0 :
;;
break;
case 1 :
MOTOR_A_HIGH;MOTOR_B_LOW;MOTOR_C_LOW;MOTOR_D_HIGH; //A、D相导通
break;
case 2 :
MOTOR_A_HIGH;MOTOR_B_HIGH;MOTOR_C_LOW;MOTOR_D_LOW; //A、B相导通
break;
case 3 :
MOTOR_A_LOW;MOTOR_B_HIGH;MOTOR_C_HIGH;MOTOR_D_LOW; //B、C相导通
break;
case 4 :
MOTOR_A_LOW;MOTOR_B_LOW;MOTOR_C_HIGH;MOTOR_D_HIGH; //C、D相导通
break;
}
delay_ms(dly); //延时控制电机转速
}
/**
* @brief 4相8拍驱动函数(单双相交替导通,精度更高)
* @param step: 当前节拍序号(1~8)
* @param dly: 节拍延时时间(ms)
* @retval 无
*/
void MOTOR_Rhythm_4_1_8(uint8_t step,uint8_t dly)
{
switch(step)
{
case 0 :
;;
break;
case 1 :
MOTOR_A_HIGH;MOTOR_B_LOW;MOTOR_C_LOW;MOTOR_D_LOW; //A相导通
break;
case 2 :
MOTOR_A_HIGH;MOTOR_B_HIGH;MOTOR_C_LOW;MOTOR_D_LOW; //A、B相导通
break;
case 3 :
MOTOR_A_LOW;MOTOR_B_HIGH;MOTOR_C_LOW;MOTOR_D_LOW; //B相导通
break;
case 4 :
MOTOR_A_LOW;MOTOR_B_HIGH;MOTOR_C_HIGH;MOTOR_D_LOW; //B、C相导通
break;
case 5 :
MOTOR_A_LOW;MOTOR_B_LOW;MOTOR_C_HIGH;MOTOR_D_LOW; //C相导通
break;
case 6 :
MOTOR_A_LOW;MOTOR_B_LOW;MOTOR_C_HIGH;MOTOR_D_HIGH; //C、D相导通
break;
case 7 :
MOTOR_A_LOW;MOTOR_B_LOW;MOTOR_C_LOW;MOTOR_D_HIGH; //D相导通
break;
case 8 :
MOTOR_A_HIGH;MOTOR_B_LOW;MOTOR_C_LOW;MOTOR_D_HIGH; //A、D相导通
break;
}
delay_ms(dly); //延时控制电机转速
}
/**
* @brief 步进电机方向控制函数
* @param dir: 旋转方向 1-正转 0-反转
* @param num: 驱动节拍模式 0-8拍 1-单4拍 2-双4拍
* @param dly: 节拍延时时间(ms)
* @retval 无
*/
void MOTOR_Direction(uint8_t dir,uint8_t num,uint8_t dly) //方向 节拍 频率
{
if(dir) //正转:节拍序号递增
{
switch(num)
{
case 0:for(uint8_t i=1;i<9;i++){MOTOR_Rhythm_4_1_8(i,dly);}break; //8拍模式
case 1:for(uint8_t i=1;i<5;i++){MOTOR_Rhythm_4_1_4(i,dly);}break; //单4拍模式
case 2:for(uint8_t i=1;i<5;i++){MOTOR_Rhythm_4_2_4(i,dly);}break; //双4拍模式
default:break;
}
}
else //反转:节拍序号递减
{
switch(num)
{
case 0:for(uint8_t i=8;i>0;i--){MOTOR_Rhythm_4_1_8(i,dly);}break; //8拍模式
case 1:for(uint8_t i=4;i>0;i--){MOTOR_Rhythm_4_1_4(i,dly);}break; //单4拍模式
case 2:for(uint8_t i=4;i>0;i--){MOTOR_Rhythm_4_2_4(i,dly);}break; //双4拍模式
default:break;
}
}
}
/**
* @brief 步进电机指定角度旋转函数
* @param dir: 旋转方向 1-正转 0-反转
* @param num: 驱动节拍模式 0-8拍 1-单4拍 2-双4拍
* @param angle: 旋转角度(°)
* @param dly: 节拍延时时间(ms)
* @retval 无
*/
void MOTOR_Direction_Angle(uint8_t dir,uint8_t num,u16 angle,uint8_t dly) //方向 节拍 角度 频率
{
//28BYJ-48电机减速比64:1,一圈需要64组8拍,计算对应角度的运行次数
for(u16 i=0;i<(64*angle/45);i++)
{
MOTOR_Direction(dir,num,dly);
}
}
/**
* @brief 步进电机停止转动函数
* @param 无
* @retval 无
*/
void MOTOR_STOP(void)
{
GPIO_ResetBits(GPIOA, MOTOR_A|MOTOR_B|MOTOR_C|MOTOR_D); //所有相输出低电平,电机断电停止
}
stepmotor.h
c
#ifndef __STEPMOTOR_H
#define __STEPMOTOR_H
#include "stm32f10x.h"
#include "delay.h"
#include "sys.h"
/***************根据自己需求更改****************/
// 步进电机 GPIO宏定义
#define MOTOR_CLK RCC_APB2Periph_GPIOA
#define MOTOR_A GPIO_Pin_1
#define MOTOR_B GPIO_Pin_2
#define MOTOR_C GPIO_Pin_3
#define MOTOR_D GPIO_Pin_4
#define MOTOR_PROT GPIOA
#define MOTOR_A_LOW GPIO_ResetBits(MOTOR_PROT,MOTOR_A)
#define MOTOR_A_HIGH GPIO_SetBits(MOTOR_PROT,MOTOR_A)
#define MOTOR_B_LOW GPIO_ResetBits(MOTOR_PROT,MOTOR_B)
#define MOTOR_B_HIGH GPIO_SetBits(MOTOR_PROT,MOTOR_B)
#define MOTOR_C_LOW GPIO_ResetBits(MOTOR_PROT,MOTOR_C)
#define MOTOR_C_HIGH GPIO_SetBits(MOTOR_PROT,MOTOR_C)
#define MOTOR_D_LOW GPIO_ResetBits(MOTOR_PROT,MOTOR_D)
#define MOTOR_D_HIGH GPIO_SetBits(MOTOR_PROT,MOTOR_D)
/*********************END**********************/
void MOTOR_Init(void);
void MOTOR_Rhythm_4_1_4(u8 step,u8 dly);
void MOTOR_Direction(u8 dir,u8 num,u8 dly);
void MOTOR_Direction_Angle(u8 dir,u8 num,u16 angle,u8 dly);
void MOTOR_STOP(void);
#endif
main.c
c
#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "stepmotor.h"
int main(void)
{
SystemInit(); // 配置系统时钟为72M
delay_init(72);
LED_Init();
LED_On();
MOTOR_Init(); // 步进电机初始化
USART1_Config(); // 串口初始化
OLED_Init();
printf("Start \n");
delay_ms(1000);
OLED_Clear();
while (1)
{
// 正转 8拍模式 延时1ms (1ms最快,数值越大转速越慢)
MOTOR_Direction(1, 0, 1);
// 反转 8拍模式 延时1ms (1ms最快,数值越大转速越慢)
//MOTOR_Direction(0, 0, 1);
// // 正转 90度,8拍模式,速度5ms
// MOTOR_Direction_Angle(1,0,90,5);
// // 停一下
// delay_ms(1000);
// // 反转 90度,8拍模式,速度5ms
// MOTOR_Direction_Angle(0,0,90,5);
// delay_ms(1000);
//MOTOR_STOP(); // 电机断电停止
}
}
使用步骤:
- 先用
MOTOR_Init()初始化 - 连续转用
MOTOR_Direction(方向,0,速度) - 转固定角度用
MOTOR_Direction_Angle(方向,0,角度,速度) - 停止用
MOTOR_STOP()
关于调速:
5ms:较快10ms:适中20ms:很慢
数值越大,电机转得越慢!
节拍选择:
- num = 1:单 4 拍 1 相通电
- num = 2:双 4 拍 2 相同时通电
- num = 0:8 拍 单双相交替通电
模式 0:8 拍 → 最稳、力矩大、精度最高(常用)
模式 1:单 4 拍 → 噪音大、抖动大、力矩小
模式 2:双 4 拍 → 力矩大、平稳一般、精度一般