51红外控制步进电机系统需要开发板和28BYJ-48步进电机,uln一套2003驱动板和红外遥控。
要实现:
(1)步进电机的正转、反转、加速、减速等物理量可由红外遥控器控制。
(2)角度信息可以通过数字管实时显示。
(3)实现电机90°真反转。
要实现这些功能,我们需要了解如何使用设备。
电机的分类方法有很多,从用途上可以分为驱动电机和控制电机。直流电机属于驱动电机,主要用于电钻、车轮、电风扇、洗衣机等设备。步进电机是一种控制电机。它是一种将脉冲信号转换为旋转角度的电机。电机的速度和停止位置仅取决于脉冲信号的频率和脉冲数量,主要用于自动仪表、机器人、自动生产线、空调叶片旋转等设备。
步进电机分为反应式、永磁式和混合式。
本设计采用28BYJ-48步进电机属于四相八拍电机,因此步进电机的输入脉冲信号也应为四相八拍。使用单片机定时器0,将工作模式设置为1。每次单片机中断,将脉冲电压输入步进电机绕组,步进电机将脉冲信号转换为线位移或角位移,并旋转角度。
28BYJ-48步进电机四相八拍工作原理
步序 |
控制位 |
工作状态 |
|||
A相 |
B相 |
C相 |
D相 |
||
1 |
1 |
0 |
0 |
0 |
A |
2 |
1 |
1 |
0 |
0 |
AB |
3 |
0 |
1 |
0 |
0 |
B |
4 |
0 |
1 |
1 |
0 |
BC |
5 |
0 |
0 |
1 |
0 |
C |
6 |
0 |
0 |
1 |
1 |
CD |
7 |
0 |
0 |
0 |
1 |
D |
8 |
1 |
0 |
0 |
1 |
DA |
表-四相八拍
ULN2003是大电流驱动阵列,多用于单片机、智能仪表、PLC、数字量输出卡等控制电路中。可直接驱动继电器等负载。
输入5VTTL电平,输出可达500mA/50V。
ULN2003是高耐压、大电流达林顿系列,由七个硅NPN达林顿管组成。 该电路的特点如下: ULN2003的每一对达林顿都串联一个2.7K的基极电阻,在5V的工作电压下它能与TTL和CMOS电路 直接相连,可以直接处理原先需要标准逻辑缓冲器来处理的数据。
ULN2003 是高压大电流达林顿晶体管阵列系列产品,具有电流增益高、工作电压高、温度范围宽、带负载能力强等特点,适应于各类要求高速大功率驱动的系统。
通信控制系统大多是发射与接收两部分组成,红外通信也不例外。发射系统对一个红外辐射源进行调制后发射红外信号,而接收系统用红外一体化接收头进行接收,两者联合构成了红外通信系统。红外通信的基本原理是:发送端将基带二进制信号调制为系列的脉冲串信号(载波信号),通过红外发射管发射红外信号。红外信号由接收端转换成电信号,并对其进行放大、滤波等处理,还原成二进制数字信号,并将其输出。
由于各遥控产品的不同,还有很多不同的遥控厂商,必须有一个通信协议来保障不同种类的红外产品获得最佳的通信效果。红外线的波长在750nm至1mm之间,红外通信-般采用红外波段内的近红外线,波长在0.75um至25um之间。红外数据协会将红外通信协议定为波长限定在850nm900nm范围之间。红外线的调制方法常用的有两种,一种是通过脉冲宽度来实现信号调制的脉宽调制(PWM),另一种是通过脉冲串之间的时间间隔来实现信号调制的脉冲调制(PPM)。
当TL1838接收到红外光信号时,内部的PIN红外接收管将其装换为电信号,又经过放大电路、解调电路的作用,由输出引脚输出与TTL电平兼容的电信号,该电信号可以直接送到微处理器中处理。
TL1838的输出波形如图3-12所示。当接收到频带内的红外信号时,TL1838接收器会输出低电平,否则数出高电平,从而“将时断时续”的红外信号解调成原来的连续方波信号。需要注意的一点是,它并没有把红外信号解码,因为它处理后发出的信号不是标准的1、0高低电平。不管是1还是0,都包含着高低电平,只是高低电平所持续的时间是不同的,这需要单片机自己通过程序来判断了。
TL1838如图所示,从左边开始,分别为1脚、2脚、3脚,分别为信号输出脚、接地和电源,其电平与TTL兼容。TL1838系列特性如下: 工作电压:2.7-5.5V 工作电流:1.4mA 距离:15M 频率:38K 角度:±45 波长:940nm
#include<AT89X51.H>
sbit MA=P1^2;
sbit MB=P1^3;
sbit MC=P1^4;
sbit MD=P1^5;
sbit P10=P1^0;
typedef unsigned int uint ;
typedef unsigned char uchar;
unsigned char mode=0;
float jiao=0.087890625;
unsigned int step,nangle1,drct1,c,k;//角度,正反转
unsigned int speed1=200;//转速
unsigned char Tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};//数码管数组
signed char p;
unsigned int t=50,u=31;//t正转次数,u反转次数
unsigned char x,j1,s,n,h;
uint IRtime;//定义高低电平持续的时间
uchar date;
uchar IRdata[33];
uchar IR_zijie[4];
bit IRok;
bit IRpro_ok;
uchar t100us,display;
void delay(int i) //延时i ms
{
int j,k;
for(j=i;j>0;j--)
for(k=110;k>0;k--);
}
void display1()
{
k++;
c=jiao*k;
if(c>=360)
{
k=0;
c = 0;
}
}
void delay1(unsigned int speed)
{
while(speed--);
}
void display2()
{
if(c==0 || c > 360)
{
k=4096;
}
k--;
c=jiao*k;
}
void teding()
{
if(x!=1)return;
t=1000,u=1000;//重装正反转次数
while(t--)//正转次数
{
switch(step)//8拍驱动
{
case 0:MA=0;MB=1;MC=0;MD=0;break;
case 1:MA=0;MB=1;MC=1;MD=0;break;
case 2:MA=0;MB=0;MC=1;MD=0;break;
case 3:MA=0;MB=0;MC=1;MD=1;break;
case 4:MA=0;MB=0;MC=0;MD=1;break;
case 5:MA=1;MB=0;MC=0;MD=1;break;
case 6:MA=1;MB=0;MC=0;MD=0;break;
case 7:MA=1;MB=1;MC=0;MD=0;break;
}
if(n==1){return;} //停止
delay1(speed1); //转数显示
display1(); //角度显示
if(t!=0)step++;//当正转结束后step值不变进入反转
if(step==8)step=0;//循环switch
}
while(u--)//反转次数
{
switch(step)//8拍驱动
{
case 2:MA=0;MB=1;MC=0;MD=0;break;
case 3:MA=0;MB=1;MC=1;MD=0;break;
case 4:MA=0;MB=0;MC=1;MD=0;break;
case 5:MA=0;MB=0;MC=1;MD=1;break;
case 6:MA=0;MB=0;MC=0;MD=1;break;
case 7:MA=1;MB=0;MC=0;MD=1;break;
case 0:MA=1;MB=0;MC=0;MD=0;break;
case 1:MA=1;MB=1;MC=0;MD=0;break;
}
if(n==1){return;}
delay1(speed1);
display2();
if(u!=0)step--;//当反转结束后step值不变进入正转
if(step==-1)step=7;
}
}
void MotorRun(unsigned int nangle, drct,speed)//正反转
{
if(x!=0)return;
if(drct==0)
{
while(nangle--)
{
switch(step)//8拍方式驱动
{
case 0:MA=0;MB=1;MC=0;MD=0;break;
case 1:MA=0;MB=1;MC=1;MD=0;break;
case 2:MA=0;MB=0;MC=1;MD=0;break;
case 3:MA=0;MB=0;MC=1;MD=1;break;
case 4:MA=0;MB=0;MC=0;MD=1;break;
case 5:MA=1;MB=0;MC=0;MD=1;break;
case 6:MA=1;MB=0;MC=0;MD=0;break;
case 7:MA=1;MB=1;MC=0;MD=0;break;
}
if(n==1){return;}
delay1(speed);
display1();
if(step==7)step=0;
else step++;
}
}
else
{
while(nangle--)
{
switch(step)
{
case 6:MA=0;MB=1;MC=0;MD=0;break;
case 5:MA=0;MB=1;MC=1;MD=0;break;
case 4:MA=0;MB=0;MC=1;MD=0;break;
case 3:MA=0;MB=0;MC=1;MD=1;break;
case 2:MA=0;MB=0;MC=0;MD=1;break;
case 1:MA=1;MB=0;MC=0;MD=1;break;
case 0:MA=1;MB=0;MC=0;MD=0;break;
case 7:MA=1;MB=1;MC=0;MD=0;break;
}
if(n==1){return;}
delay1(speed);
display2();
if(step==7)step=0;
else step++;
}
}
}
void init()
{
TMOD=0X12;TH0=0x38;TL0=0x38;TH1=0xfc;TL1=0xb0;
EA=1;EX0=1;IT0=1;ET0=1;TR0=1;ET1=1;TR1=1;
}
void t0() interrupt 1
{
t100us++;
if(t100us>2){t100us=0;IRtime++;} //300us
}
void t1() interrupt 3
{
TH1=0xfc;TL1=0xb0;
switch(s)
{
case 0:P0=0;P2=0x7f;P0=Tab[c%10];break;
case 2:P0=0;P2=0xdf;P0=Tab[c/100%10];break;
case 1:P0=0;P2=0xbf;P0=Tab[c/10%10];break; //数码管角度显示
case 3:P0=0;P2=0xfd;P0=Tab[speed1/100%10];break;
case 4:P0=0;P2=0xfb;P0=Tab[speed1/10%10];break;
case 5:P0=0;P2=0xf7;P0=Tab[speed1%10];break; //数码管速度显示
}
s++;
if(s==6)s=0;
}
void IRpro()
{
uchar i;//i是用于计数处理4个字节
uchar j;//j用于计数处理1个字节的8位数据
uchar k;//k用于计数处理33次脉宽
k = 1;//从第一位脉宽开始处理,丢掉起始码
for(i = 0; i < 4; i++)
{
for(j = 0; j < 8; j++)
{
//如果脉宽大于数据0标准的1125us那么就判定为数据1
if(IRdata[k] > 5) IR_zijie[i] |= 0x80;//写1
//只能右移7次,如果右移8次则会把第一位数据移出去
if(j < 7) IR_zijie[i] >>= 1;
k++; //处理下一次脉宽
}
}
IRpro_ok = 1;//解码完成
}
void int0() interrupt 0
{
static uchar i;//静态变量用于存入33次数据计数
static bit startflag;//开始储存脉宽标志位
if(startflag)
{
/*判断引导码,如果是引导码则从起始码开始存*/
if((IRtime < 53) && (IRtime >= 32)) i = 0;
IRdata[i] = IRtime;//以TO溢出的次数来计算脉宽把这个时间存放在数组中
IRtime = 0;//计数清零
i++;//计数脉宽存入次数自加
if(i == 33) //i等于33那么就表示已经存入了33次脉宽
{
IRok = 1; //脉宽检查完成
i = 0; //把脉宽计数清零准备下次存入
}
}
else
{
IRtime = 0; //定时器0计数清零
startflag = 1;//开始处理标志位置1
}
if(IRok) //判断33次脉宽是否提取完成
{
IRpro();//根据脉宽解码出4个字节的数据
IRok = 0;//清零脉宽检查完成标志位等待下一次脉宽检查
if(IRpro_ok)//判断解码是否完成
{
date = IR_zijie[2];
if(date == 0x45) {nangle1=0;mode=0;n=1;x=0;}
if(date == 0x44) {if(mode==0){drct1=0;nangle1=4096;n=1;}}
if(date == 0x07) {if(mode==0){drct1=1;nangle1=4096;n=1;}}
if(date == 0x09) {if(speed1<1000){speed1+=100;n=1;}}
if(date == 0x15) {if(speed1>200){speed1-=100;n=1;}}
if(date == 0x46) {mode=1;n=1;}
if(date == 0x47) {if(mode==1){x=1;n=1;}}
if(date == 0x40) {if(mode==1){h=0;}}
IRpro_ok = 0;//清零解码标志位
}
}
}
void main()
{
P10=0;
init();//初始化
while(1)
{
n=0;
teding();
MotorRun(nangle1,drct1,speed1);
}
}