标题:
LabVIEW+51单片机驱动A4988步进电机做的十字滑台
[打印本页]
作者:
fengyalong20052
时间:
2021-11-3 20:27
标题:
LabVIEW+51单片机驱动A4988步进电机做的十字滑台
使用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)
2021-11-4 04:13 上传
点击文件名下载附件
下载积分: 黑币 -5
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1