触摸单片机快两年了,不过仅仅十分业余的爱好,实践却不多,到现在还算是个初学者吧。这几天给自己的使命便是搞定步进电机的单片机操控。曾经曾看过有关步进电机原理和操控的材料,究竟自己没有做过,对其详细原理还不是很清楚。今日从淘宝网买了一个EPSON的UMX-1型步进电机,此步进电机为双极性四相,接线共有六根,外形如下图所示:
拿到步进电机,依据曾经看书对四相步进电机的了解,我对它进行了开端的测验,便是将5伏电源的正端接上最边上两根褐色的线,然后用5伏电源的地线别离和别的四根线(红、兰、白、橙)顺次触摸,发现每触摸一下,步进电机便滚动一个视点,来回五次,电机刚好转一圈,阐明此步进电机的步进视点为360/(4×5)=18度。地线与四线触摸的次序相反,电机的转向也相反。
假如用单片机来操控此步进电机,则只需别离顺次给四线必守时刻的脉冲电流,电机便可接连滚动起来。经过改动脉冲电流的时刻距离,就能够完成对转速的操控;经过改动给四线脉冲电流的次序,则可完成对转向的操控。所以,规划了如下电路图:
C51程序代码为:
代码一
#include
static unsigned intcount;
static unsigned intendcount;
voiddelay();
voidmain(void)
{
count = 0;
P1_0 = 0;
P1_1 = 0;
P1_2 = 0;
P1_3 = 0;
EA = 1;//答应CPU中止
TMOD = 0x11;//设守时器0和1为16位形式1
ET0 = 1;//守时器0中止答应
TH0 = 0xFC;
TL0 = 0x18;//设守时每隔1ms中止一次
TR0 = 1; //开端计数
startrun:
P1_3 = 0;
P1_0 = 1;
delay();
P1_0 = 0;
P1_1 = 1;
delay();
P1_1 = 0;
P1_2 = 1;
delay();
P1_2 = 0;
P1_3 = 1;
delay();
gotostartrun;
}
//守时器0中止处理
voidtimeint(void)interrupt1
{
TH0=0xFC;
TL0=0x18;//设守时每隔1ms中止一次
count++;
}
voiddelay()
{
endcount=2;
count=0;
do{}while(count
将上面的程序编译,用ISP下载线下载至单片机工作,步进电机便滚动起来了,开端告捷!
不过,上面的程序还仅仅完成了步进电机的开端操控,速度和方向的操控还不行灵敏,别的,我们没有使用步进电机内线圈之间的“中间状态”,步进电机的步进视点为18度。所以,我将程序代码改善了一下,如下:
代码二
#include
static unsigned intcount;
static intstep_index;
voiddelay(unsigned intendcount);
voidgorun(bitturn,unsigned intspeedlevel);
voidmain(void)
{
count = 0;
step_index = 0;
P1_0 = 0;
P1_1 = 0;
P1_2 = 0;
P1_3 = 0;
EA = 1;//答应CPU中止
TMOD = 0x11;//设守时器0和1为16位形式1
ET0 = 1;//守时器0中止答应
TH0 = 0xFE;
TL0 = 0x0C;//设守时每隔0.5ms中止一次
TR0 = 1;//开端计数
do{
gorun(1,60);
}while(1);
}
//守时器0中止处理
voidtimeint(void)interrupt1
{
TH0=0xFE;
TL0=0x0C;//设守时每隔0.5ms中止一次
count++;
}
voiddelay(unsigned intendcount)
{
count=0;
do{}while(count
voidgorun(bitturn,unsigned intspeedlevel)
{
switch(step_index)
{
case0:
P1_0 = 1;
P1_1 = 0;
P1_2 = 0;
P1_3 = 0;
break;
case1:
P1_0 = 1;
P1_1 = 1;
P1_2 = 0;
P1_3 = 0;
break;
case2:
P1_0 = 0;
P1_1 = 1;
P1_2 = 0;
P1_3 = 0;
break;
case3:
P1_0 = 0;
P1_1 = 1;
P1_2 = 1;
P1_3 = 0;
break;
case4:
P1_0 = 0;
P1_1 = 0;
P1_2 = 1;
P1_3 = 0;
break;
case5:
P1_0 = 0;
P1_1 = 0;
P1_2 = 1;
P1_3 = 1;
break;
case6:
P1_0 = 0;
P1_1 = 0;
P1_2 = 0;
P1_3 = 1;
break;
case7:
P1_0 = 1;
P1_1 = 0;
P1_2 = 0;
P1_3 = 1;
}
delay(speedlevel);
if(turn==0)
{
step_index++;
if(step_index>7)
step_index=0;
}
else
{
step_index–;
if(step_index<0)
step_index=7;
}
}
改善的代码能完成速度和方向的操控,并且,经过step_index静态全局变量能“记住”步进电机的步进方位,下次调用 gorun()函数时则可直接从前次步进方位持续滚动,然后完成准确步进;别的,我们使用了步进电机内线圈之间的“中间状态”,步进视点减小了一半,只为9度,低速工作也相对安稳一些了。
可是,在代码二中,步进电机的工作操控是在主函数中,假如程序还需碑文其它使命,则有可能使步进电机的工作收到影响,别的还有其它方面的不便利,总归不是很完美的操控。所以我又将代码再次改善:
代码三
#include
static unsigned intcount;//计数
static intstep_index;//步进索引数,值为0-7
static bitturn;//步进电机滚动方向
static bitstop_flag;//步进电机中止标志
static intspeedlevel;//步进电机转速参数,数值越大速度越慢,最小值为1,速度最快
static intspcount;//步进电机转速参数计数
voiddelay(unsigned intendcount);//延时函数,延时为endcount*0.5毫秒
voidgorun();//步进电机操控步进函数
voidmain(void)
{
count = 0;
step_index = 0;
spcount = 0;
stop_flag = 0;
P1_0 = 0;
P1_1 = 0;
P1_2 = 0;
P1_3 = 0;
EA = 1;//答应CPU中止
TMOD = 0x11;//设守时器0和1为16位形式1
ET0 = 1;//守时器0中止答应
TH0 = 0xFE;
TL0 = 0x0C;//设守时每隔0.5ms中止一次
TR0 = 1; //开端计数
turn = 0;
speedlevel = 2;
delay(10000);
speedlevel = 1;
do{
speedlevel = 2;
delay(10000);
speedlevel = 1;
delay(10000);
stop_flag=1;
delay(10000);
stop_flag=0;
}while(1);
}
//守时器0中止处理
void timeint(void) interrupt 1
{
TH0=0xFE;
TL0=0x0C;//设守时每隔0.5ms中止一次
count++;
spcount–;
if(spcount<=0)
{
spcount = speedlevel;
gorun();
}
}
voiddelay(unsigned intendcount)
{
count=0;
do{}while(count
voidgorun()
{
if(stop_flag==1)
{
P1_0 = 0;
P1_1 = 0;
P1_2 = 0;
P1_3 = 0;
return;
}
switch(step_index)
{
case0://0
P1_0 = 1;
P1_1 = 0;
P1_2 = 0;
P1_3 = 0;
break;
case1://0、1
P1_0 = 1;
P1_1 = 1;
P1_2 = 0;
P1_3 = 0;
break;
case2://1
P1_0 = 0;
P1_1 = 1;
P1_2 = 0;
P1_3 = 0;
break;
case3://1、2
P1_0 = 0;
P1_1 = 1;
P1_2 = 1;
P1_3 = 0;
break;
case4://2
P1_0 = 0;
P1_1 = 0;
P1_2 = 1;
P1_3 = 0;
break;
case5://2、3
P1_0 = 0;
P1_1 = 0;
P1_2 = 1;
P1_3 = 1;
break;
case6://3
P1_0 = 0;
P1_1 = 0;
P1_2 = 0;
P1_3 = 1;
break;
case7://3、0
P1_0 = 1;
P1_1 = 0;
P1_2 = 0;
P1_3 = 1;
}
if(turn==0)
{
step_index++;
if(step_index>7)
step_index=0;
}
else
{
step_index–;
if(step_index<0)
step_index=7;
}
}
在代码三中,我将步进电机的工作操控放在时刻中止函数之中,这样主函数就能很便利的参加其它使命的碑文,而对步进电机的工作不产生影响。在此代码中,不光完成了步进电机的转速和转向的操控,别的还加了一个中止的功用,,这肯定是需求的。
步进电机从中止到高速滚动需求一个加快的进程,不然电机很简单被“卡住”,代码一、二完成加快不是很便利,而在代码三中,加快则很简单了。在此代码中,当转速参数speedlevel 为2时,能够算出,此刻步进电机的转速为1500RPM,而当转速参数speedlevel 1时,转速为3000RPM。当步进电机中止,假如直接将speedlevel 设为1,此刻步进电机将被“卡住”,而假如先把speedlevel 设为2,让电机以1500RPM的转速转起来,几秒种后,再把speedlevel 设为1,此刻电机就能以3000RPM的转速高速滚动,这便是“加快”的作用。
在此电路中,考虑到电流的原因,我用的NPN三极管是S8050,它的电流最大可达1500mA,而在实践工作中,我用万用表测了一下,当转速为1500RPM时,步进电机的电流只要90mA左右,电机发热量较小,当转速为60RPM时,步进电机的电流为200mA左右,电机发热量较大,所以NPN三极管也能够选用9013,关于电机发热量大的问题,可加一个10欧到20欧的限流电阻,不过这样步进电机的功率将会变小。
我们鄙人浅陋,过错和问题不免,请各位不吝赐教!