使用A4988驱动模块驱动42步进电机
一、结构问题
1、两个滑台的尺寸不匹配,X丝杠滑块与Y轴丝杠底座安装不到一起
解决方案:将两个丝杠模组全部解体,将X丝杠滑块打穿,用螺丝固定,并用锉刀进行打磨。
潜在问题:①锉刀打磨过的螺丝可能不能使用,若后期拆卸,需另觅蹊径;②由于结构问题,X丝杠滑块与Y丝杠底座固定处只用了两个螺丝,连接不太稳定,已用三秒固定。
2、限位开关与丝杠之前没有连接零件
解决方案:手工打磨或采用3D打印该工件。
潜在问题:由于传感器与控制系统均采用5V供电,因此金属限位开关的有效检测距离只有 ,所以连接必须可靠,并且必须保证滑块必须在传感器检测的有效距离之内,否则会烧毁步进电机。
二、方案设计问题
1、上位机与下位机通讯协议的约定
最初打算采用帧头+数据帧+帧尾的格式,但限于项目时间,故采用如下协议约定。
上位机接收指令如下表所示:
注:位移控制设置三个按键分别为:设置、加、减,采用光标跳转进行不同轴的设置
②软件:
采用定时器输出A4988驱动的脉冲,从而控制步进电机的角速度、角位移;
采用2个外部中断判断金属限位开关是否被触发,因为该中断优先级最高;
采用串口和上位机进行通讯。
3、金属接近传感器电路设计
由于51系别单片机外部中断资源有限,所需传感器有4个,故每一个丝杠模组两端传感器作为一组,作为“与门”的输入,输出信号传给单片机的外部中断,这样可以保证任何一个传感器输出信号都可以触发外部中断。
4、步进电机的失能控制
虽然A4988驱动上有ENABLE端口,但是51单片机的硬件资源已经使用完毕,因此,只能停止脉冲输入,从而控制步进电机失能。
5、滑块的速度、位移计算
本项目采用两个步距角为1.8°的两相四线步进电机,在1细分的驱动下,一个脉冲转动1.8°,因此转动一圈(360°)需要200个脉冲。由于丝杠的精度较高,所以步进电机的角位移转换为滑块的位移比例差距较大,电机每转动一圈,滑块位移()mm(还未测量),控制精度完全满足要求,因此我们采用1细分进行驱动。
利用钢尺测量出电机的角位移与滑块线位移的关系为:
得出滑块的速度为:
其中t为滑块位移的时间,该时间利用脉冲周期进行计算
单片机源程序如下:
- # include <Motor_Con.h>
- sbit KEY_XFOR = P2^6; //X正转按键
- sbit KEY_XREV = P2^5; //X反转按键
- sbit KEY_XUP = P1^2; //X加速按键
- sbit KEY_XDOWN =P1^1; //X减速按键
- sbit KEY_YFOR = P2^7; //Y正转按键
- sbit KEY_YREV = P1^6; //Y反转按键
- sbit KEY_YUP = P1^5; //Y加速按键
- sbit KEY_YDOWN =P1^4; //Y减速按键
- sbit KEY_SET_UP =P2^2; //位移加按键
- sbit KEY_SET_DOWN =P2^3; //位移减按键
- sbit KEY_SETX =P2^0; //X位移设置按键
- sbit KEY_SETY =P2^1; //Y位移设置按键
- sbit KEY_STOP =P2^4; //启动停止按键
- extern char User_Data[];
- int Distance_X2,Distance_Y2; //定时器所需取反的脉冲次数
- int Distance_X1,Distance_Y1; //位移编号
- extern int num_x,num_y; //x、y速度
- int Order_X=10,Order_Y=10; //初始化XY指令为电机停止
- int Distance[]={5,10,30,60,100}; //位移显示
- bit stop=0; //启动停止标志
- /*按键扫描函数*/
- void KEY_SCAN()
- {
- if((KEY_XFOR == 0)) //X正转按键被按下 或 接收到X正转指令
- FOR(0);
- if((KEY_YFOR == 0)) //Y正转按键被按下 或 接收到Y正转指令
- FOR(1);
- if((KEY_XREV == 0)) //X反转按键被按下 或 接收到X反转指令
- REV(0);
- if((KEY_YREV == 0)) //Y反转按键被按下 或 接收到Y反转指令
- REV(1);
- if((KEY_XUP == 0)) //X加速按键被按下 或 接收到X加速指令
- { delay(300); if((KEY_XUP == 0)) Speed_UP(0); }while(!KEY_XUP);
- if((KEY_YUP == 0) ) //Y加速按键被按下 或 接收到Y加速指令
- { delay(300); if((KEY_YUP == 0)) Speed_UP(1); }while(!KEY_YUP);
- if((KEY_XDOWN == 0)) //X减速按键被按下 或 接收到X减速指令
- { delay(300); if((KEY_XDOWN == 0)) Speed_DOWN(0);}while(!KEY_XDOWN);
- if((KEY_YDOWN == 0)) //Y减速按键被按下 或 接收到Y减速指令
- { delay(300); if((KEY_YDOWN == 0) ) Speed_DOWN(1);}while(!KEY_YDOWN);
- }
- void Distance_Data()
- {
- switch(Distance_Y1)
- {
- case 1 : Distance_Y2=500; break;
- case 2 : Distance_Y2=1000; break;
- case 3 : Distance_Y2=3000; break;
- case 4 : Distance_Y2=6000; break;
- case 5 : Distance_Y2=10000; break;
- }
- switch(Distance_X1)
- {
- case 1 : Distance_X2=200; break;
- case 2 : Distance_X2=400; break;
- case 3 : Distance_X2=1200; break;
- case 4 : Distance_X2=2400; break;
- case 5 : Distance_X2=4000; break;
- }
- }
- void Distance_Set()
- {
- int i=0;
- Disp_Str(2,0,"SET_X: mm",11); //显示
- Disp_Str(3,0,"SET_Y: mm",11);
- if(KEY_SETX==0) //位移设置按键按下
- {
- delay(500);
- if(KEY_SETX==0)
- {
- while(!KEY_SETX);
- ET0=0; //关定时器0,电机停止
- while(1) //进入死循环,设置位移距离
- {
- if(KEY_SET_UP==0) //位移加按键按下
- {
- delay(100);
- Distance_X1++;
- i++;
- if(Distance_X1==6)//位移数组最大到6
- Distance_X1=1;
- if(i==5)
- i=0;
- }
- if(KEY_SET_DOWN==0)
- {
- delay(100);
- Distance_X1--;
- i--;
- if(Distance_X1<1)
- Distance_X1=5;
- if(i<0)
- i=4;
- }
- Write_Int(2,3,Distance[i]); //显示当前速度
- Distance_Data(); //位移设置
- delay(500);
- if(KEY_SETX==0) //位移设置按键再次按下退出循环
- {
- ET0=1;
- return;
- }
- }
- }
- }
- if(KEY_SETY==0)
- {
- delay(500);
- if(KEY_SETY==0)
- {
- while(!KEY_SETY);
- ET0=0;
- while(1)
- {
- if(KEY_SET_UP==0)
- {
- delay(100);
- Distance_Y1++;
- i++;
- if(Distance_Y1==6)
- Distance_Y1=1;
- if(i==5)
- i=0;
- }
- if(KEY_SET_DOWN==0)
- {
- delay(100);
- Distance_Y1--;
- i--;
- if(Distance_Y1<1)
- Distance_Y1=5;
- if(i<0)
- i=4;
- }
- Write_Int(3,3,Distance[i]);
- Distance_Data();
- if(KEY_SETY==0)
- {
- ET0=1;
- return;
- }
- }
- }
- }
- }
- /*限位开关扫描*/
- void RUN_SCAN()
- {
- static uint Y,X;
- if(EXTI1==0) //Y轴
- {
- delay(100);
- if(EXTI1==0)
- {
- DIR_Y=~DIR_Y;
- Y++;
- if(Y%2) //每次取反之后变量加一,从而判断正反转
- {
- Disp_Str(1,1,"RE",2); //显示反转
- Uart_String("B0002\r\n"); //发送反转指令
- }
- else
- {
- Disp_Str(1,1,"FO",2);
- Uart_String("B0001\r\n");
- }
- }while(!EXTI1);
- }
- if(EXTI0==0) //X轴
- {
- delay(100);
- if(EXTI0==0)
- {
- DIR_X=~DIR_X;
- X++;
- if(X%2)
- {
- Disp_Str(0,1,"RE",2);
- Uart_String("A0002\r\n");
- }
- else
- {
- Disp_Str(0,1,"FO",2);
- Uart_String("A0001\r\n");
- }
- }while(!EXTI0);
- }
- }
- /*启动停止按钮*/
- void Usert_receive()
- {
- if(KEY_STOP==0)
- {
- delay(200);
- if(KEY_STOP==0)
- stop=~stop;
- }while(!KEY_STOP);
- }
- void main()
- {
- Lcd_Init(); //LCD初始化
- Timer0Init(); //定时器0初始化
- UsartInit(); //串口初始化
- while(1)
- {
- Usert_receive(); //判断启动按键是否被按下
- while(!(stop==1)) //系统没有启动卡死在改循环中
- {
- Usert_receive(); //判断启动是否被按下
- ET0=0; //关闭定时器0
- Disp_Str(2,0," Welcome! ",16); //显示
- Disp_Str(3,0," Please Start! ",16);
- }
- Distance_Set(); //位移设置按键扫描
- RUN_SCAN(); //限位开关扫描
- ET0=1; //打开定时器
- KEY_SCAN(); //控制按键扫描
- }
- }
复制代码
单片机代码与LabVIEW 51hei附件下载:
十字滑台.7z
(67.93 KB, 下载次数: 90)
|