步进电机简介:
步进电机是将电脉冲信号转变为角位移或多线位移的开源控制元件。在非超载的情况下,电机的转速,停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,即给电机加一个脉冲信号,电机则转过一个步距角。这一线性的关系的存在,加上步进电机只有周期性的误差而无累计误差等特点。使得在速度,位置等控制领域用步进电机来控制变的非常简单。虽然步进电机已经被广泛的应用,但步进电机并不像普通电机,交流电机在常规下使用,它必须由双环形脉冲信号,功率驱动电路等组成控制系统方可使用。因此用好步进电机也并非易事,它涉及到机械,电机,电子及计算机等多专业知识。下图即为混合式步进电机图。
步进电机工作原理:
通常步进电机的转子为永磁体,当电流流过定子绕组时,定子绕组产生一失量的磁场。磁场会带动转子旋转一定的角度,使的转子的一对磁场方向与定子的磁场方向一致。当定子的矢量磁场旋转一个角度。转子也随着该磁场转步距角。每输入一个电脉冲,电动机转动一个角度前进一步。它输入的角位移与输入的脉冲数成正比,转速与脉冲频率成正比。改变绕组通电顺序,电机就会反转。所以可以控制脉冲数量,频率及电机各相绕组的通电顺序来控制步进电机的转动。具体看下图:
步进电机极性区分:
步进电机又分为单极性的步进电机和双极性的步进电机:具体如下图所示:
其中左侧为单极性步进电机,右侧为双极性步进电机,单双极性是指一个步进电机里面有几种电流的方向,左侧的五线四相步进电机就是单极性的步进电机,图中的红色箭头为电流的方向,四根线的电流走向汇总到公共线,所以称之位单极性电机;但是右侧则不同,电机中有两个回路,两个电流的回路就是双极性,所以称之为双极电机。
单机性绕组
单极性步进电机使用的是单极性绕组。其一个电机上有两个绕组,这种联连方式位当一个绕组通电时,产生一个北极磁场;另一个绕组通电,则产生一个南极磁场。因为从驱动器到线圈的电流不会反向,所以可称其为单机绕组。
双极性绕组
双极性步进电机使用的是双极性绕组。每组用一个绕组,通过将绕组中电流反向,电磁极性被反向。典型的两相双极驱动的输出步骤在电气原理图和下图中的步进顺序中进一步阐述。按图所示,转换只利用绕组简单地改变电流方向就能改变该组的极性。
永磁步进电机包括一个永磁转子,线圈绕组和导磁定子,只要将线圈通电根据电磁铁的原理就会产生磁场,分为南北极,见上图所示;通过改变步进电机定子的磁场,转子就会因为磁场的变化而发生转动,同理,一次改变通电的顺序就可以使得电机转动起来
双极性步进电机驱动原理
单极性步进电机驱动原理
单极性与双极性步进电机驱动类似,都可以分为整步与半步的驱动方式,不 同的是,双极性的步进电机可以通过改变电流的方向来改变每相的磁场方向,但是单极性的就不可以了,它有一个公共端,这就直接决定了,电流方向。具体旋 转顺序详见下图:
静态技术指标
• 相数:产生不同对极 N、S 磁场的激磁线圈对数,也可以理解为步进电机中线圈的组数,其中两相步进电机步距角为 1.8°,三相的步进电机步距角为 1.5°,相数越多的步进电机,其步距角就越小。
• 拍数:完成一个磁场周期性变化所需脉冲数或导电状态用 n 表示,或指 电机转过一个齿距角所需脉冲数,以四相电机为例,有四相四拍运行方式即 AB-BC-CD-DA-AB,四相八拍运行方式即 A-AB-B-BC-C-CD-D-DA-A。• 步距角:一个脉冲信号所对应的电机转动的角度,可以简单理解为一个脉 冲信号驱动的角度,电机上都有写,一般 42 步进电机的步距角为 1.8°• 定位转矩:电机在不通电状态下,电机转子自身的锁定力矩(由磁场齿形 的谐波以及机械误差造成的)。• 静转矩:电机在额定静态电压作用下,电机不作旋转运动时,电机转轴的 锁定力矩。此力矩是衡量电机体积的标准,与驱动电压及驱动电源等无关。
动态技术指标
• 步距角精度:步进电机转动一个步距角度的理论值与实际值的误差。用百 分比表示:误差/步距角 *100%。• 失步:电机运转时运转的步数,不等于理论上的步数。也可以叫做丢步, 一般都是因负载太大或者是频率过快。• 失调角:转子齿轴线偏移定子齿轴线的角度,电机运转必存在失调角,由 失调角产生的误差,采用细分驱动是不能解决的。• 最大空载起动频率:在不加负载的情况下,能够直接起动的最大频率。• 最大空载的运行频率:电机不带负载的最高转速频率。• 运行转矩特性:电机的动态力矩取决于电机运行时的平均电流(而非静态 电流),平均电流越大,电机输出力矩越大,即电机的频率特性越硬。• 电机正反转控制:通过改变通电顺序而改变电机的正反转。
硬件设计
开发板上的步进电机驱动模块电路如下图所示:
软件设计
/****************** 实验名称:步进电机实验
接线说明:
实验现象:下载程序后,当按下 KEY1 键可调节电机旋转方向;当按下 KEY2 键,电机加速;
当按下 KEY3 键,电机减速 当按下 KEY4 键,电机启动暂停
注意事项:将步进电机红色线对接到“步进电机模块”输出端子 J47 的 5V 上,其它相序依次接
入。
*********************************************************************
******************/
#include "reg52.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
//定义 ULN2003 控制步进电机管脚
sbit IN1_A=P1^0;
sbit IN2_B=P1^1;
sbit IN3_C=P1^2;
sbit IN4_D=P1^3;
//定义独立按键控制脚
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
//使用宏定义独立按键按下的键值
/*
使用宏定义独立按键按下返回的键值
为什么要定义这个宏呢?是为了方便与我们在程序当中直接使用这个返回值,这样
后期在调用这个函数扫描的时候,得到它的返回值可以直接用KEY1_PRESS来代表,而
不是直接用1 2 3 4来表示 。1 2 3 4在我们用户在看着这个程序的时候,不知道1代表什么
2代表什么,现在KEY1_PRESS 通过英文字母我们可以知道是K1按键按下
当然觉得能看懂,也可以不用宏定义,直接用1 2 3 4 0 来表示这几个
*/
#define KEY1_PRESS 1
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY_UNPRESS 0
// 定义步进电机速度,值越小,速度越快
#define STEPMOTOR_MAXSPEED 1 // 最小延时不能小于 1ms
#define STEPMOTOR_MINSPEED 5 //最大延时不能大于5ms
/********************************************************************
***********
* 函 数 名 : delay_10us
* 函数功能 : 延时函数,ten_us=1 时,大约延时 10us
* 输 入 : ten_us
* 输 出 : 无
*********************************************************************
**********/
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
/********************************************************************
***********
* 函 数 名 : delay_ms
* 函数功能 : ms 延时函数,ms=1 时,大约延时 1ms
* 输 入 : ten_us
* 输 出 : 无
*********************************************************************
**********/
void delay_ms(u16 ms)
{
u16 i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
/********************************************************************
***********
* 函 数 名 : step_motor_28BYJ48_send_pulse
* 函数功能 : 输出一个数据给 ULN2003 从而实现向步进电机发送一个脉冲
* 输 入 : step:指定步进序号,可选值 0~7
dir:方向选择,1:顺时针,0:逆时针
* 输 出 : 无
*********************************************************************
**********/
void step_motor_28BYJ48_send_pulse(u8 step,u8 dir)
{
u8 temp=step;
//这里定义temp=step是因为,当dir==1,是顺时针,不执行if(dir==0) ,传入switch(temp)的
//不变,如果dir==0 temp=7-step;调换传入的节拍顺序,变成逆时针,所以想要改变方向只用改变
//dir 的值就可以
if(dir==0) //逆时针旋转
temp=7-step;//调换节拍信号
switch(temp)//8 个节拍控制:A->AB->B->BC->C->CD->D->DA
{
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=1;IN3_C=1;IN4_D=0;break;
case 4: IN1_A=0;IN2_B=0;IN3_C=1;IN4_D=0;break;
case 5: IN1_A=0;IN2_B=0;IN3_C=1;IN4_D=1;break;
case 6: IN1_A=0;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;
}
}
/********************************************************************
***********
* 函 数 名 : key_scan
* 函数功能 : 检测独立按键是否按下,按下则返回对应键值
* 输 入 : mode=0:单次扫描按键
mode=1:连续扫描按键
* 输 出 : KEY1_PRESS:K1 按下
KEY2_PRESS:K2 按下
KEY3_PRESS:K3 按下
KEY4_PRESS:K4 按下
KEY_UNPRESS:未有按键按下
*********************************************************************
**********/
u8 key_scan(u8 mode)
{
static u8 key=1;//static 修饰符,key的值不会被改变,会保存上次的值
//if(mode)key=1;同if(mode==1)key=1,mode=1为真,就进入这个if,key=1,就是连续检测
//mode=1时候 mode==1不成立,为假,就不执行这个if语句,是单次检测
if(mode)key=1;
if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))//任意按键按下的时候为低电平
{
delay_10us(1000);//延时进行消抖处理
/*按键按下后key=0,不松开就不会在进入这个if,再次进行扫描按键,不会在返回这个简
return KEY1_PRESS......这几个键值了,如果没有这个key=0,不松开程序就不停的在进入
这个if在进行扫描
*/
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=0,如果没有这个key=1,下次按键按下的时候key=0就不满足if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))这个,不能进行扫描,不采集的,所以在按键松开后(就是没有按键按下的时候)会执行else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) 扫描后把赋值,更改为key=1退出程序,下次按键在按下的时候key=1,继续执行if里面的语句。
*/
key=1;
}
//如果按键按下,执行完return KEY1_PRESS 这条语句,返回的函数直接返回出去了,就直接
//退出这个函数了,自然后面的语句就不会在执行,如果没有按键按下,第二个if语句有而不会
//执行下去,直接就执行后面的语句,所以这条语句放在else if 的里面或者外面都可以
return KEY_UNPRESS;
}
/********************************************************************
***********
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void main()
{
u8 key=0;
u8 dir=0;//默认逆时针方向
u8 speed=STEPMOTOR_MAXSPEED;//默认最大速度旋转
u8 step=0;
u8 stop=0;//电机默认暂停
while(1)
{
key=key_scan(0);
if(key==KEY1_PRESS)//换向
{
dir=!dir;
}
else if(key==KEY2_PRESS)//加速
//当speed大于STEPMOTOR_MAXSPEED(1),已经最大值speed-=1同speed=speed-1,
//还回到最大速度,速度不变
{
if(speed>STEPMOTOR_MAXSPEED)
speed-=1;
}
else if(key==KEY3_PRESS)//减速
//当speed小于STEPMOTOR_MINSPEED(5),speed+=1同speed=speed+1,继续减速,当大于
//STEPMOTOR_MINSPEED时候,则不在执行speed+=1,速度不变
{
if(speed<STEPMOTOR_MINSPEED)
speed+=1;
}
else if(key==KEY4_PRESS)//启动暂停
{
stop=!stop;
}
if(stop==1)//当stop=1时候执行下面语句,不等于1不执行,没参数传入电机不启动
{
//serp和dir参数传入函数step_motor_28BYJ48_send_pulse,每次循环step++同step=step+1
step_motor_28BYJ48_send_pulse(step++,dir);
//当step==8时候,把step=0从新开始,这里 step不能等于7,如果等于7,就会把最后一步丢掉,
//所以不能和7比较
if(step==8)step=0;
delay_ms(speed);
}
}
}
step_motor_28BYJ48_send_pulse 函数用于输出一个数据给 ULN2003,从而 实现向步进电机发送一个脉冲信号。它有两个形参,第一个为 step,指定步进 序号,可选值为 0-7,代表步进电机控制信号的 8 个节拍。第二个为 dir,指定电机的旋转方向,可选 1:顺时针,0:逆时针。这里指的顺时针逆时针是两个不 同方向。函数先判断 dir 参数值,如果为 0,则为逆时针旋转,将 step 值变为 8 的互 补数,其实就是将 8 个节拍反向输出。主函数实现的功能很简单,首先定义一些变量,进入循环,检测是否有按键 按下,当 KEY1 按下,切换步进电机方向;当 KEY2 按下,使电机加速;当 KEY3 按下,使电机减速,当 KEY4 按下,使电机启动暂停。程序中所用 STEPMOTOR_MAXSPEED 和 STEPMOTOR_MINSPEED 在开头已定义,表 示步进电机最大运行速度和最低运行速度,当然可以根据实际现象适当调整这两 个值