本章用到两个功能,推荐反复练习,重点是代码部分和步进电机原理部分
1 步进电机简介
步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件。
2 步进电机工作原理
通常步进电机的转子为永磁体,当电流流过定子绕组时,定子绕组产生一矢
量磁场。磁场会带动转子旋转一定的角度,使得转子的一对磁场方向与定子的磁
场方向一致。当定子的矢量磁场旋转一个角度。转子也随着该磁场转步距角。每
输入一个电脉冲,电动机转动一个角度前进一步。
步进电机又分为单极性的步进电机和双极性的步进电机;具体简易图如下图
所示:
其中左侧为单极性步进电机,右侧为双极性的步进电机.
双极性步进电机驱动原理:
在双相激励的过程中,也可以在换相位时加一个关闭相位的状态而产生走半
步的现象,这将步进电机的整个步距角一分为二,例如,一个 90°的步进电机
将每半步移动 45°,具体见下图。
1. A 相通电,B 相不通电
2. A、B 相全部通电,且电流相同,产生相同磁性
3. B 相通电,A 断电
4. B 相通电,A 相通电,且电流相等,产生相同磁性
5. A 相通电,B 断电
6. A、B 相全部通电,且电流相同,产生相同磁性
7. B 相通电,A 断电
8. B 相通电,A 相通电,且电流相等,产生相同磁性
其中 1~4 步与 5~8 步的电流方向相反(电流相反,电磁的极性就相反)这
样就产生了顺时针旋转,同理逆时针是将通电顺序反过来即可。
注:单相与双相基本相同,理解原理即可
3 步进电机技术指标 :
包括静态指标和动态指标,此处不是重点,不再赘述.
4. 软件设计
本章所要实现的功能是:通过 ULN2003 驱动模块控制 28BYJ48 步进电机运行
方向及速度,当按下 KEY1 键可调节电机旋转方向;当按下 KEY2 键,电机加速;
当按下 KEY3 键,电机减速。
step_motor_28BYJ48_send_pulse 函数用于输出一个数据给 ULN2003,从而 实现向步进电机发送一个脉冲信号。它有两个形参,第一个为 step,指定步进 序号,可选值为 0-7,代表步进电机控制信号的 8 个节拍。第二个为 dir,指定电机的旋转方向,可选 1:顺时针,0:逆时针。这里指的顺时针逆时针是两个不 同方向。
函数先判断 dir 参数值,如果为 0,则为逆时针旋转,将 step 值变为 8 的互补数,其实就是将 8 个节拍反向输出。
主函数实现的功能很简单,首先定义一些变量,进入循环,检测是否有按键
按下,当KEY1 按下,切换步进电机方向;当 KEY2 按下,使电机加速;当 KEY3
按下,使电机减速。
程序中所用 STEPMOTOR_MAXSPEED 和 STEPMOTOR_MINSPEED 在开头已定义,表
示步进电机最大运行速度和最低运行速度,当然可以根据实际现象适当调整这两
个值。
5.原始代码如下:
(注:代码部分不建议直接复制粘贴,要多次理解,更要自己敲出来,复制粘贴容易眼高手低)
#include "reg52.h" typedef unsigned char u8; typedef unsigned int u16; //定义 ULN2003 控制步进电机管脚 sbit IN1_A=P1^0; sbit IN2_B=P1^1; sbit IN3_C=P1^3; sbit IN4_D=P1^4; //定义 ULN2003 控制步进电机管脚 sbit KEY1=P3^1; sbit KEY2=P3^0; sbit KEY3=P3^2; sbit KEY4=P3^3; //使用宏定义独立按键按下的键值 #define KEY1_PRESS 1 #define KEY2_PRESS 2 #define KEY3_PRESS 3 #define KEY4_PRESS 4 #define KEY_UNPRESS 0 // 定义步进电机速度,值越小,速度越快 // 最小不能小于 1 #define STEPMOTOR_MAXSPEED 1 #define STEPMOTOR_MINSPEED 5 //延时函数,ten_us=1 时,大约延时 10us void delay_10us(u16 ten_us) { while(ten_us--); } //ms 延时函数,ms=1 时,大约延时 1ms void delay_ms(u16 ms) { u16 i,j; for(i=ms;i>0;i--) { for(j=110;j>0;j--) { ; } } } //独立按键扫描函数.mode的返回值是判断是不是多次扫描 u8 key_scan(u8 mode) { static u8 key=1; if(mode)key=1;//等于1,多次扫描 if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0)) { delay_10us(1000);//消抖 key=0; //返回值,否则第二次无法进入循环 if(KEY1==0) return KEY1_PRESS; else if(KEY2==0) return KEY2_PRESS; else if(KEY3==0) return KEY3_PRESS; else if(KEY4==0) return KEY4_PRESS; } else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) { key=1;//防止第二次无法进入循环 } return KEY_UNPRESS ; } //输出一个数据给 ULN2003 从而实现向步进电机发送 //一个脉冲 //step:指定步进序号,可选值 0~7 //dir:方向选择,1:顺时针,0:逆时针 void step_motor_28BYJ48_send_pulse(u8 step,u8 dir) { u8 temp=step;//默认顺时针 if(dir==0)//逆时针旋转情况 temp=-step; //8 个节拍控制:A->AB->B->BC->C->CD->D->DA switch(temp) { case 0:IN1_A=1;IN2_B=0;IN3_C=0;IN4_D=0;break; case 1:IN1_A=1;IN2_B=1;IN3_C=0;IN4_D=0;break; case 2:IN1_A=0;IN2_B=1;IN3_C=0;IN4_D=0;break; case 3:IN1_A=0;IN2_B=0;IN3_C=1;IN4_D=0;break; case 4:IN1_A=1;IN2_B=0;IN3_C=1;IN4_D=0;break; case 5:IN1_A=1;IN2_B=0;IN3_C=1;IN4_D=1;break; case 6:IN1_A=1;IN2_B=0;IN3_C=0;IN4_D=1;break; case 7:IN1_A=1;IN2_B=0;IN3_C=0;IN4_D=1;break; } }//只要理解步进电机自传原理,就很简单 //不能为了敲代码而敲代码! void main() { u8 key=0; u8 dir=0;//默认逆时针方向 u8 speed=STEPMOTOR_MAXSPEED;//默认最大速度旋转 u8 step=0; while(1) { key=key_scan(0); if(key==KEY1_PRESS) { dir=!dir; } else if(key==KEY2_PRESS)//返回值为:加速 { if(speed>STEPMOTOR_MAXSPEED) speed-=1; } else if(key==KEY2_PRESS)//返回值为:减速 { if(speed<STEPMOTOR_MAXSPEED) speed+=1; } //执行步进电机的循环(A-->AB-->B-->....-->A) step_motor_28BYJ48_send_pulse(step++,dir); if(step==8)step=0; delay_ms(speed); } }
错误修正:
1.在主循环的while循环中,第三个else if的返回值判断是减速的时候,应该改为
else if(key=KEY3_PRESS)
逻辑是如果按键3按下,就执行speed--,减速命令.
2.#define KEY1_PRESS 4和#define KEY_UNPRESS 0在此函数中均未被使用,可直接不进行宏定义,不影响代码的执行
6.实验现象
使用 USB 线将开发板和电脑连接成功后(电脑能识别开发板上 CH340 串口),
把编译后产生的.hex 文件烧入到芯片内,实现现象如下:当按下 KEY1 键可调节
电机旋转方向;当按下 KEY2 键,电机加速;当按下 KEY3 键,电机减速。
注意:将步进电机红色线对接到“步进电机模块”输出端子 J47 的 5V 上,如图