问题由来
在综合实例利用ZigBee模块实现智能家居的远程语音控制中,用到了步进电机,有的网友问我,应该买一个什么样的步进电机呢?
其实底板上的L298N电路是一个步进电机驱动的通用电路,不一定要买跟我一模一样的步进电机。
我们随便选择一个步进电机都是可以的,为了控制方便,我们这里选择一个常见的5V的步进电机:28BYJ-48。
内部拆解图:
正是因为内部有这么多齿轮,所以此步进电机为一个减速电机。
解决问题
- 28BYJ-48步进电机与L298N驱动芯片的接法
- 改进综合实例中步进电机的驱动方式
开发环境与工具
- Keil 5
- 主芯片为STM32F103RET6
- 电路使用的是202008综合实例的底板
- 下载工具为JLINK
- PC为Win10
- 步进电机的型号为:28BYJ-48
主要技术参数
步进电机28BYJ-48为5线4相八拍电机,额定电压为5V,还有6V、12V、24V的。
其中:
28:步进电机的直径为28mm
48:表示四相八拍
电机的减速比:1/64
步距角:5.625°/64=0.08789度(因为减速比是1/64)
所以对于此步进电机,4096个脉冲转一圈(64×64)。
驱动方法
此步进电机一共有5根线,红色是公共端,接5V电源,4橙(A),3黄(B),2粉(C),1蓝(D)。
步进电机要想转动,必须加驱动,步进电机的驱动信号必须为脉冲信号,没有脉冲的时候,步进电机静止。
加上适当的脉冲信号,步进电机就会以一定的角度转动,转动的速度和脉冲的频率成正比。
八拍步进电机控制时序为:A-AB-B-BC-C-CD-D-DA-A ... ,一拍转一个步距角,如此反复。
对应各个线的高低电平如下所示:
由上我们可以定义旋转相序:
uchar code CCW[8]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09}; //逆时针旋转相序表
uchar code CW[8]={0x09,0x01,0x03,0x02,0x06,0x04,0x0c,0x08}; //正时针旋转相序表
原理图
橙、黄、粉、蓝四根线分别与 StepMotor_OUT1、 StepMotor_OUT2、 StepMotor_OUT3、 StepMotor_OUT4 相连,通过改变StepMotor_IN1~StepMotor_IN4 引脚的高低电平,StepMotor_OUT1~StepMotor_OUT4 对应输出同向高低电平。
因为步进电机上为XH2.54-5P的胶壳插头,而底板是XH2.54-6P的胶壳直针座,所以我们要对其进行一下改造。
因为步进电机的红线需要连接5V,即VCC连接5V,L298N的VS也需要连接5V,所以我们要将板子上的JP8三个引脚短接到一起。
改造后的结果展示如下:
代码实现
定时器初始化
随便选择STM32的一个定时器即可,我们这里以定时器3为例:
//定时器3初始化
//arr:定时重装值
//psc:分频值
void TIM3_Init(uint16_t arr, uint16_t psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3时钟
//定时器3配置,重载值、分频值、分频系数、计数模式
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = psc;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //允许定时更新中断
//中断配置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3, ENABLE); //使能定时器3
}
main函数中,调用上面的函数对定时器进行初始化:
TIM3_Init(19,7199); //2ms中断
TIM3_Set(0); //定时器初始状态为关闭状态
定时器中断处理函数
定时器3每2ms执行一次中断服务函数,在中断服务函数中,改变L298N四个输入引脚的状态,完成步进电机的一拍,如果想要让28BYJ-48型步进电机旋转一圈,需要执行下面中断服务函数64*64次,即步进电机运转64*64拍。
//定时器3中断服务程序
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)//是更新中断
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIM3更新中断标志
nCurrentMotorStepCount++;
if(nCurrentMotorStepCount <= MOTOR_STEP_COUNT)
{
SetMotor(PhaseCW[nCurrentMotorStepCount%8]);
//SetMotor(PhaseCCW[nCurrentMotorStepCount%8]);
}
if(nCurrentMotorStepCount >= MOTOR_STEP_COUNT)
{
TIM_Cmd(TIM3, DISABLE); //关闭TIM3
L298N_12ENA = 0; //只有转的时候使能,否则持续供电,芯片和电机过热。
L298N_34ENA = 0;
nCurrentMotorStepCount = 0;
}
}
}
当步进电机行进了预定拍数MOTOR_STEP_COUNT(改变此值可以控制步进电机的旋转角度)之后,关闭定时器,并将L298N芯片的两个使能引脚置为低电平,步进电机将停止运动。
步进电机行进一拍
每一拍中我们都需要改变一次L298N四个输出引脚的状态,即需要改变L298N的四个输入引脚状态,下面封装了一拍状态下,对与L298N芯片相连的STM32的四个引脚进行赋值的函数:
void SetMotor(unsigned char InputData)
{
if(InputData&0x01)
{
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
else
{
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
if(InputData&0x02)
{
GPIO_SetBits(GPIOC,GPIO_Pin_1);
}
else
{
GPIO_ResetBits(GPIOC,GPIO_Pin_1);
}
if(InputData&0x04)
{
GPIO_SetBits(GPIOC,GPIO_Pin_2);
}
else
{
GPIO_ResetBits(GPIOC,GPIO_Pin_2);
}
if(InputData&0x08)
{
GPIO_SetBits(GPIOA,GPIO_Pin_0);
}
else
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
}
}
使能步进电机启动
要想步进电机启动,我们只需要开启定时器,并将L298N芯片的两个使能引脚置为高电平,步进电机将开始运动。
TIM3_Set(1);
nCurrentMotorStepCount = 0;
L298N_12ENA = 1;
L298N_34ENA = 1;