一、引言
步进电机是一种将电脉冲转化为角位移的执行机构。步进电机与普通电机最大的不同就是步进电机能很好地控制电机的旋转角度。
当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(及步进角)。您可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时您可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。步进电机原理说明请参考http://www.mcusy.cn/Article.asp?id=1699533 。
大家看到配单片机学习开发板的大多是小巧的那种两相步进电机(六线、也称四相),而实际上应用最广泛的就是工业或专用设备的24V/2~4A的步进电机,这类电机则需要专门制作或购买带细分功能的步进驱动器来驱动,所以了解和学会使用这种驱动器是单片机应用的必修课。不过无论电机大小,原理是一样的。
二、工业用步进电机典型介绍
看到网上不少单片机初学者不知道如何用驱动器去驱动大的步进电机,其实并不难,笔者前不久从仓库中翻出一个BS(白山牌)的步进驱动器和步进电机一套,特用单片机控制实验示范给狼友,下面是步进电机和驱动器外观及参数图。
电机主要参数:
步距角 ----- 1.8° (200步/1圈,即360° / 1.8° = 200)
保持转矩 ----- 0.9N.m
电压/电流 ----- 24V/3.0A
相电阻 ----- 0.75Ω
相电感 ----- 1.1mH
转子惯量 ----- 300g.cm2
步进驱动器主要参数: 反应频率 ----- 200Kpps(最高) 驱动电流 ----- 0.5~4A连续可调 电压范围 ----- DC12~40V
特殊功能: 双极恒流斩波方式; 步进脉冲停止超过100ms时,电机线圈自动减半。 |
设有12/8档等角度恒力矩细分,最高200细分。
细分数 |
1 |
2 |
4 |
8 |
16 |
32 |
64 |
128 |
D0 |
ON |
OFF |
ON |
OFF |
ON |
OFF |
ON |
OFF |
D1 |
ON |
ON |
OFF |
OFF |
ON |
ON |
OFF |
OFF |
D2 |
ON |
ON |
ON |
ON |
OFF |
OFF |
OFF |
OFF |
D3 |
无效 |
D4 |
ON, 双脉冲:PU为正向步进脉冲信号,DR为反向步进脉冲信号 |
OFF, 单脉冲:PU为步进脉冲信号,DR为方向控制信号 |
D5 |
自检测开关(OFF时接收外部脉冲,ON时驱动器内部发7.5KHz脉冲) | |
二、用单片机驱动步进电机
经过测试和电路了解,此驱动器内部各信号输入端具有光耦隔离电路,而且只需10MA左右即可驱动,因此单片机I/O直接接到驱动器即可。
其中驱动器有几个最重要的端口输入:
PU : 脉冲信号 ----- 改变脉冲个数就是控制步进电机要走的步数;而改变频率就是控制步进电机的速度;
(用步进驱动器的一个方便之处就是我们编程时不需要考虑A/B相的激励信号顺序,这些由驱动器内部分配完成,只需发脉冲。)
DR : 方向信号 ----- 若为0则顺时针运转,1为逆时针运转;
SM : 细分信号 ----- 若为0则内部默认的四相八拍(半步)运行,若为1按用户按D0-D3设定的细分运行;
MF : 电机释放信号 ----- 若为0则关断电机线圈电流,电机处于自由状态;若为1为锁定。
什么是细分?
如果步进电机是1.8°步距角的,就是200步/圈。采用2细分就是2*200=400步/圈,4细分就是800步/圈,以此类推...,细分越多精度越高(也能给编程带来麻烦),同时相数变得毫无意义(2相、4相等几乎没有差距)。但细分越多也有不好之处,如果不细分采用整步走,这样运转的力气最大,但震动噪音也大,细分越多运转越震动小、噪音小,但同时扭矩变小,所以通常细分要根据实际情况来设定。
驱动器另外还有几个很有用的输入和反馈输出信号端口(见上图),在这里我们只用PU、DR和SM这三个端口控制,做到控制细分步数和速度,以下实验还增加了带有步数设置存储及1602显示演示功能。
各个信号输入时序还是有小规定的,见下图:
以下是笔者在XY900开发板上做实验,用杜邦线引出几条信号线到步进驱动器,另外驱动器除了24VDC电源,还5V需要接入,并与单片机电路共GND,+5V和GND由单片机控制电路提供即可。
使用时,比如步进电机是3A的,那么在驱动器侧边有个小电位器可以调节的,调节时要实际要比3A略小,比如调到1.5A~2A即可,不过这个与你设置的细分有一定关系。
三、演示程序
//=======================================================
// 程序名称: 步进电机控制程序03
// 试验平台: XY900学习开发板
// (STC89C52RC /内部EEPROM /晶体跳接到24M)
// 主要外设: 步进电机-BS57(两相混合/200步一圈/1.8‘步距角)
// 驱 动 器- Q2HB(设为4细分,即800小步一圈)
// 液 晶 屏- LCD1602
// 可调参数: 200~1600(脉冲,0.25圈~2圈, 精度0.25步/ 0.45'步距角
// 功能操作: 每按一次开关按设定的步数运行一次
// 程序编写: 月夜听风 /mcusy_cn@126.com
//=======================================================
#include<reg52.h>
#include<intrins.h>
#include<stc51_eeprom.h> //EEPROM头文件
#define uint unsigned int
#define uchar unsigned char
//初始化显示 ---
uchar code tab0[] = " WWW.MCUSY.CN ";
uchar code tab1[] = " QQ : 479780666 ";
uchar code tab2[] = "SETUP EXTENT : ";
uchar code tab3[] = ">>> "; //设置步进脉冲数
uchar code tab4[] = ">>> Saved !! ";
uchar code tab5[] = " Run ... "; //运转中
uchar code tab6[] = " END ! "; //运转结束
//========== 定义I/O功能 ==========
#define DataPort P0 //数据口
sbit RS = P2^5;
sbit RW = P2^6;
sbit EN = P2^7;
sbit PU = P2^0; //步进脉冲
sbit DR = P2^1; //方向控制
sbit SM = P2^2; //细分信号
//sbit MF = P2^3; //电机释放
sbit BELL = P3^7; //无源蜂鸣器 - 脉冲有效
sbit Start_Pause = P3^5; //启动键
sbit SET = P3^4; //设置键
sbit INC = P3^3; //加1键
sbit DEC = P3^2; //减1键
//定义变量 ---
uchar num, k1num, k2num;
uint Count, SET_data,i,j,y,m ;
uchar SET_data_H , SET_data_L ;
//========== us级延时函数 ==========
void delay_50us()
{
uchar a,b,c;
for(a=0;a<1;a++)
for(b=0;b<1;b++)
for(c=0;c<25;c++);
}
//========== ms延时函数 ==========
void delay_ms(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=254;y>0;y--);
}
//========== 提示音函数 ==========
void BELL_alarm(uint m)//适合晶振24M
{
for(y=0;y<m;y++)
{BELL =~ BELL; for(j=0;j<55;j++);} //取反/频率
}
//写命令 -----
void write_com(uchar com)
{
RS=0;P0=com;delay_ms(1);delay_ms(1);RW=0;
EN=1;delay_ms(1);EN=0;
}
//写数据 -----
void write_date(uchar date)
{
RS=1;P0=date;delay_ms(1);delay_ms(1);RW=0;
EN=1;delay_ms(1);EN=0;
}
//========== LCD初始化函数 ==========
void LCD_init()
{
uchar num; //显示字符的个数
write_com(0x38); //16*2、5*7
write_com(0x0c); //光标
write_com(0x06); //光标加一
write_com(0x01); //清屏
write_com(0x80); //指向第一行/
for(num=0;num<16;num++)
{write_date(tab0[num]);delay_ms(60);}
write_com(0x80+0x40); //指向第二行/
for(num=0;num<16;num++)
{write_date(tab1[num]);delay_ms(60);}
delay_ms(800);
}
//========== 显示函数 ==========
void display(uchar add,uint date)
{
uchar q,b,s,g;
q=date/1000; //千
b=date/100%10; //百
s=date/10%10;//十
g=date%10;//个
write_com(0x80+0x40+add);
write_date(0x30+q);
write_date(0x30+b);
write_date(0x30+s);
write_date(0x30+g);
}
//========== T0初始化函数 ==========
void T0_init() //以下设初值3.0ms(晶体24M)
{
TMOD=0x01;//T0/工作方式1
TH0=0xE8; //3.0ms
TL0=0x90;
IE=0x82; //允许T0中断
}
//==========T0中断(脉冲)服务函数 ==========
void T0_src(void) interrupt 1
{
Count ++;
//简单5级启动加速
if( Count >=4 ) {TH0=0xE8; TL0=0x90;} //3.00ms
if( Count >=30 ) {TH0=0xEC; TL0=0x78;} //2.50ms
if( Count >=80 ) {TH0=0xF0; TL0=0x60;} //2.00ms
if( Count >=120) {TH0=0xF4; TL0=0x48;} //1.50ms
if( Count >=160) {TH0=0xF8; TL0=0x30;} //1.00ms
if( Count >=200) {TH0=0xFC; TL0=0x18;} //0.50ms/最快
PU=0; delay_50us(); PU=1; //发脉冲,不采用取反
}
//========== 按键设置脉冲函数 ==========
void keyscan(void)
{
if(SET==0) //设置键被按下
{
delay_ms(5);
if(SET!=1)
{
delay_ms(5);
while(!SET); //松手?
BELL_alarm(800); //提示音
k1num++; Count=0;
if(k1num==1)
{
write_com(0x80);
for(num=0;num<16;num++)
{write_date(tab2[num]);}
write_com(0x80+0x40);
for(num=0;num<16;num++)
{write_date(tab3[num]);}
write_com(0x0f);
}
display(4,SET_data); //显示参数
}
}
//脉冲参数设置 -----
if(k1num!=0)
{
if(INC==0) //加1键
{
delay_ms(10);
if(INC==0)
{
delay_ms(100);
//while(!INC); //松手?
if(SET_data==1600) //设置最大2圈
//因驱动器采用4细分,(200*4=1600个脉冲小步)
{SET_data=199;}
SET_data++;
display(4,SET_data);
}
BELL_alarm(50);
}
if(DEC==0) //减1键
{
delay_ms(10);
if(DEC==0)
{
delay_ms(100);
//while(!DEC); //松手?
SET_data--;
if(SET_data==199)
{SET_data=1600;}
display(4,SET_data);
}
BELL_alarm(50);
}
}
//存储确认 ------
if(k1num>=2)
{
k1num=0;
SET_data_H = SET_data/256; SET_data_L = SET_data;
SectorErase(0x2200); SectorErase(0x2000); //插除扇区
byte_write(0x2200,SET_data_H); byte_write(0x2000,SET_data_L);//写入EEPROM
BELL_alarm(1000);
write_com(0x80+0x40); //LCD
for(num=0;num<16;num++)
{write_date(tab4[num]);} //显示 " >>> Saved !! "
}
}
//=========== 运行控制函数 ===========
void key_Run(void)
{
if(Start_Pause==0) //按下了启动键?
{
delay_ms(10);
while(!Start_Pause); //松手?
SM=1; delay_50us(); //按设定的细分
DR=0; delay_50us(); //设方向顺时针
TR0=1; //启动T0
write_com(0x80); //LCD第一行/
for(num=0;num<16;num++)
{write_date(tab3[num]);}
write_com(0x80+0x40);
for(num=0;num<16;num++) //第二行/
{write_date(tab5[num]);} //显示 Run ...
}
//----------------------
if(Count==SET_data) //是否走到了设定的步数?
{
TR0=0; Count=0;
write_com(0x80+0x40);
for(num=0;num<16;num++)
{write_date(tab6[num]);} //显示 END ...
}
}
//=============== 主 函 数 ===============
//SET_data:一个实际脉冲变量
void main(void)
{
delay_ms(100);
T0_init();
LCD_init();
SET_data_H = byte_read(0x2200); //读回存储的数据
SET_data_L = byte_read(0x2000);
SET_data = SET_data_H*256 + SET_data_L;
// SET_data = 400; //调试用,实际取消
BELL_alarm(2000); //响一声
while(1)
{
keyscan();
key_Run();
}
}
四、结束语:
步进电机是民用尤其是工业最常见的驱动机构之一,是学习PLC和单片机的工程师必然会用到的。PLC控制的用得最多,但成本较高,所以选择单片机也有很大优势。
以上只是简单的应用演示,旨在让初学者看后有帮助,根据实际情况程序中还有很多需要改善的地方,比如要考虑启动加速和渐减速停止过程的自动控制,有些自动化机器还与各传感器位置等涉及精度的控制等,还有设置参数分配等,这些都需要参照总体方案去设计程序,同时离不开现场调试。