51单片机实现双步进电机独立正反转、固定角度内转的控制

两个光电管,两个步进电机独立控制,互不干扰。


简单介绍下,步进电机常态是不动的,我需要控制步进电机在某个角度内转动,当光电管被遮挡时,步进电机就要向后退,但是最多退90度,当光电管没有遮挡时,步进电机就尝试复位到原来位置。

为了达到某个角度内转动,我设计了加法器,步进电机的位移被存储起来,往前移动一个步机单位就加1,往后移动一个单位就减1,始终检测加法器的值,确保值在确定角度之间,在此之间做判断和移动。

我用数码管显示步进电机的状态,用不同的字母和数字表示。

增加了蜂鸣器报警,如果超过转动角度,蜂鸣器就被触发,直到角度在正常范围内。

两个电机的控制是不干扰的,并行控制,因为切换的很快,好像是同时控制的,其实就像cpu时间切片控制一样,短时间内在两个任务之间不断往返。如果需要更快更高精度、连接控制单元更多的控制,考虑换更快、io端口更多的芯片。


















 

 //功能:光电管被遮住,步进电机转90度;无遮挡,步进电机逆转90度。
 #include <reg52.h>
#include <intrins.h>
#define	uchar unsigned char
#define uint unsigned int

sbit motor = P1^0;//位定义步进电机1脉冲信号端口
sbit block = P1^1;  //位定义接收光电开关1遮挡信号的端口
sbit dir = P1^2;//位定义步进电机1方向控制端口

sbit motor2 = P3^0;//位定义步进电机2脉冲信号端口
sbit block2 = P3^1;  //位定义接收光电开关2遮挡信号的端口		 
sbit dir2 = P3^2;//位定义步进电机2方向控制端口

sbit WE = P2^7;
sbit DU = P2^6;	
sbit beep = P2^3;

uchar i;	   //电机转动角度,i = 1 表示转动1.8度 
uint maxSum = 1600;	   //步进电机1能转到的最大步数,一步为1.8度		  1600
uint maxSum2 = 1600;	   //步进电机2能转到的最大步数,一步为1.8度		  1600
int sumDegree;		   //记录步进电机1转过的角度数
int sumDegree2;		   //记录步进电机2转过的角度数

void delay(void)   //误差 -0.217013888889us
{
    uchar a,b;
    for(b=20    ;b>0;b--)		//初值80
        for(a=10;a>0;a--);
}

//void delay_ms(uchar i)   //误差 -0.000000000227us,延时0.1秒
//{
//    uchar a,b,c;
//    for(c=13*i;c>0;c--)
//        for(b=247;b>0;b--)
//            for(a=142;a>0;a--);
//    _nop_;  //if Keil,require use intrins.h
//}

void motor_degree(uchar i)	   // i取值0-255
{
	dir = 0;	 //方向设置为正转
	while(i--)		//i个脉冲,步进电机转动i*1.8度
	{
		motor = 0;
		delay();
		motor = 1;
		delay();		//1个脉冲,步进电机转动1.8度	
	}
}

void invert_motor_degree(uchar i)	// i取值0-255
{
 	dir = 1; //方向设置为反转
	while(i--)		 //i个脉冲,步进电机转动i*1.8度
	{
		motor = 0;
		delay();
		motor = 1;
		delay();	  //1个脉冲,步进电机转动1.8度
	}
}

///步进电机2正反转/
void motor2_degree(uchar i)	   // i取值0-255
{
	dir2 = 0;	 //方向设置为正转
	while(i--)		//i个脉冲,步进电机转动i*1.8度
	{
		motor2 = 0;
		delay();
		motor2 = 1;
		delay();		//1个脉冲,步进电机转动1.8度	
	}
}

void invert_motor2_degree(uchar i)	// i取值0-255
{
 	dir2 = 1; //方向设置为反转
	while(i--)		 //i个脉冲,步进电机转动i*1.8度
	{
		motor2 = 0;
		delay();
		motor2 = 1;
		delay();	  //1个脉冲,步进电机转动1.8度
	}
}

前四个数码管显示机械臂1的状态/

void shumaguanShow1()
{
	WE = 1;	  //打开位选锁存器
	P0 = 0xfe;	 //选中数码管1111 1110
	WE = 0;  //	  锁存位选数据

	DU = 1;
	P0 = 0x06;	 //数码管显示1
	DU = 0;
	beep = 0;  //报警提示
	delay();	
}

void shumaguanShow0()
{
	WE = 1;	  //打开位选锁存器
	P0 = 0xfe;	 //选中第一位数码管1111 1110
	WE = 0;  //	  锁存位选数据

	DU = 1;
	P0 = 0x3f;	 //数码管显示0
	DU = 0;
	beep = 1;
	delay();
}

void shumaguanShowError()
{
    WE = 1;	  //打开位选锁存器
	P0 = 0xf0;	 //选中数码管1111 0000
	WE = 0;  //	  锁存位选数据

 	DU = 1;
	P0 = 0x79;	//数码管显示字母E
	DU = 0;	
	beep = 0;   //报警提示
	delay();
}

void shumaguanShowStraight()
{
	WE = 1;//打开位选
	P0 = 0xf0;//选中数码管1111 0000
	WE = 0;	//关闭位选	

	DU = 1;	//打开段选
	P0 = 0x40; //显示-
	DU = 0;	//关闭段选
	beep = 1;
	delay();
}

//后四个数码管显示机械臂2状态///

void shumaguan2Show1()
{
	WE = 1;	  //打开位选锁存器
	P0 = 0x7f;	 //选中数码管1110 1111
	WE = 0;  //	  锁存位选数据

	DU = 1;
	P0 = 0x06;	//数码管显示1 
	DU = 0;
	beep = 0;  //报警提示
	delay();
}

void shumaguan2Show0()
{
	WE = 1;	  //打开位选锁存器
	P0 = 0x7f;	 //选中数码管1110 1111
	WE = 0;  //	  锁存位选数据

	DU = 1;
	P0 = 0x3f; //数码管显示0	 
	DU = 0;
	beep = 1;
	delay();
}

void shumaguan2ShowError()
{
    WE = 1;	  //打开位选锁存器
	P0 = 0x0f;	 //选中数码管0000 1111
	WE = 0;  //	  锁存位选数据

 	DU = 1;
	P0 = 0x79;	//数码管显示字母E
	DU = 0;	
	beep = 0;   //报警提示
	delay();
}

void shumaguan2ShowStraight()
{
	WE = 1;//打开位选
	P0 = 0x0f;//选中数码管0000 1111 
	WE = 0;	//关闭位选	

	DU = 1;	//打开段选
	P0 = 0x40; //显示-
	DU = 0;	//关闭段选
	beep = 1;
	delay();
}

void main()
{
	while(1)
	{

///步进电机1的控制算法/

	   	 if(sumDegree <= maxSum && sumDegree >= 0 )  //如果步数和大于0,小于等于最大步数,可以继续后退
	     {
		 	if(block == 0)		   //光电开关被遮挡,反转1步
			{	
				shumaguanShow1();  //数码管显示1
				invert_motor_degree(1);//   反转1步
				sumDegree--; 	//总步数减1
			}
  		   	else			//光电开关无遮挡
			{     		   
				shumaguanShow0();  //数码管显示0		  
				motor_degree(1);//	无遮挡,正转1步
				sumDegree++;    //总步数加1
			}
		 }                                     //如果步数和等于0,说明在最前方,任何情况都不前进,有遮挡后退
		else if(sumDegree < 0)	//如果步数和小于0,则不能后退了,有遮挡不动,无遮挡前进。
		{
			if(block == 0)	   //光电开关被遮挡,电机不动
			{
			 	shumaguanShowError();  //报警提示
			}
			else   //光电开关无遮挡,电机正转
			{
				shumaguanShow0();
				motor_degree(1);	//正转1步
				sumDegree++;	//总步数加1
			}
		}
		else  //如果步数和大于50,则不能前进了,无遮挡不动,有遮挡反转。
		{
	 		if(block == 0) 	//光电开关有遮挡,电机反转
			{
				 	shumaguanShow1();
					invert_motor_degree(1);
					sumDegree--;
			}
			else	//光电管无遮挡,电机不动,显示机械臂伸直状态----
			{
				 	shumaguanShowStraight();
			}
		}

步进电机2的控制算法/

		if(sumDegree2 <= maxSum2 && sumDegree2 >= 0 )  //如果步数和大于0,小于  最大步数,可以继续后退
	     {
		 	if(block2 == 0)		   //光电开关被遮挡,反转1步
			{	
				shumaguan2Show1();  //数码管显示1
				invert_motor2_degree(1);//   反转1步
				sumDegree2--; 	//总步数减1
			}
  		   	else		//光电开关无遮挡
			{     		   
				shumaguan2Show0();  //数码管显示0		  
				motor2_degree(1);//	无遮挡,正转1步
				sumDegree2++;    //总步数加1
			}
		 }                                     //如果步数和等于0,说明在最前方,任何情况都不前进,有遮挡后退
		else if(sumDegree2 < 0)	//如果步数和小于0,则不能后退了,有遮挡不动,无遮挡前进。
		{
			if(block2 == 0)	   //光电开关被遮挡,电机不动
			{
			 	shumaguan2ShowError();  //报警提示
			}
			else	   //光电开关无遮挡,电机正转
			{
				shumaguan2Show0();
				motor2_degree(1);	//正转1步
				sumDegree2++;	//总步数加1
			}
		}
		else  //如果步数和大于50,则不能前进了,无遮挡不动,有遮挡反转。
		{
	 		if(block2 == 0) 	//光电开关有遮挡,电机反转
			{
				 	shumaguan2Show1();
					invert_motor2_degree(1);
					sumDegree2--;
			}
			else	//光电管无遮挡,电机不动,显示机械臂伸直状态----
			{
				 	shumaguan2ShowStraight();
			}
		}
	}		
}	











			

 

一次控制两个电机#include #define GPIO_MOTOR P1 sbit K1=P3^6; sbit K2=P3^5; sbit K3=P3^4; sbit K4=P3^3; unsigned char code ZHENG1 [8]={0xf1,0xf3,0xf2,0xf6,0xf4,0xfc,0xf8,0xf9}; //转顺序编码 unsigned char code FAN1 [8]={0xf9,0xf8,0xfc,0xf4,0xf6,0xf2,0xf3,0xf1}; //反转顺序编码 unsigned char code ZHENG2 [8]={0x1f,0x3f,0x2f,0x6f,0x4f,0xcf,0x8f,0x9f}; //转顺序编码 unsigned char code FAN2 [8]={0x9f,0x8f,0xcf,0x4f,0x6f,0x2f,0x3f,0x1f}; //反转顺序编码 char Motor1_Step,Motor2_Step,Speed,Speed2; void Delay(unsigned int t); void Motor1_zheng(); void Motor1_fan(); void Motor2_zheng(); void Motor2_fan(); void main() { unsigned int i; Motor1_Step=1; Motor2_Step=3; Speed=10; Speed2=40; while(1) { while(K1==0) { for(i=0;i<10;i++) { Motor1_zheng(); } } while(K2==0) { for(i=0;i<10;i++) { Motor1_fan(); } } while(K3==0) { for(i=0;i<10;i++) { Motor2_zheng(); } } while(K4==0) { for(i=0;i<10;i++) { Motor2_fan(); } } } } void Motor1_fan() { unsigned int i; for(i=0;i<8;i++) { //GPIO_MOTOR = FFW[i]&0x1f; //取数据 GPIO_MOTOR = FAN1[i]; Delay(Speed); //调节转速 } } void Motor1_zheng() { unsigned int i; for(i=0;i<8;i++) { //GPIO_MOTOR = FFZ[i]&0x1f; GPIO_MOTOR = ZHENG1[i]; Delay(Speed); //调节转速 } } void Motor2_fan() { unsigned int i; if(Motor1_Step==0) { for(i=0;i<8;i++) { //GPIO_MOTOR = FFW2[i]&0xf1; //取数据 GPIO_MOTOR = FAN2[i]; Delay(Speed2); //调节转速 } } Motor1_Step=1; } void Motor2_zheng() { unsigned int i; if(Motor1_Step==1) { for(i=0;i<8;i++) { //GPIO_MOTOR = FFZ2[i]&0xf1; GPIO_MOTOR = ZHENG2[i]; Delay(Speed2); //调节转速 } } Motor1_Step=0; } void Delay(unsigned int t) { unsigned int k; while(t--) { for(k=0; k<80; k++) { } } }
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值