找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3208|回复: 0
收起左侧

LabVIEW+51单片机驱动A4988步进电机做的十字滑台

[复制链接]
ID:906881 发表于 2021-11-3 20:27 | 显示全部楼层 |阅读模式
使用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为滑块位移的时间,该时间利用脉冲周期进行计算

单片机源程序如下:
  1. # include <Motor_Con.h>

  2. sbit KEY_XFOR = P2^6;         //X正转按键                                                   
  3. sbit KEY_XREV = P2^5;         //X反转按键
  4. sbit KEY_XUP  = P1^2;              //X加速按键  
  5. sbit KEY_XDOWN =P1^1;         //X减速按键

  6. sbit KEY_YFOR = P2^7;         //Y正转按键                                                   
  7. sbit KEY_YREV = P1^6;         //Y反转按键
  8. sbit KEY_YUP  = P1^5;              //Y加速按键  
  9. sbit KEY_YDOWN =P1^4;         //Y减速按键         

  10. sbit KEY_SET_UP   =P2^2;                  //位移加按键
  11. sbit KEY_SET_DOWN =P2^3;                  //位移减按键
  12. sbit KEY_SETX     =P2^0;                  //X位移设置按键
  13. sbit KEY_SETY     =P2^1;                  //Y位移设置按键

  14. sbit KEY_STOP   =P2^4;                  //启动停止按键

  15. extern char User_Data[];
  16. int Distance_X2,Distance_Y2;         //定时器所需取反的脉冲次数
  17. int Distance_X1,Distance_Y1;         //位移编号
  18. extern int num_x,num_y;                         //x、y速度
  19. int Order_X=10,Order_Y=10;       //初始化XY指令为电机停止
  20. int Distance[]={5,10,30,60,100}; //位移显示
  21. bit stop=0;                                                 //启动停止标志
  22. /*按键扫描函数*/
  23. void KEY_SCAN()
  24. {        
  25.                 if((KEY_XFOR == 0))  //X正转按键被按下 或 接收到X正转指令
  26.                         FOR(0);
  27.                 if((KEY_YFOR == 0))  //Y正转按键被按下 或 接收到Y正转指令
  28.                         FOR(1);
  29.                 if((KEY_XREV == 0))  //X反转按键被按下 或 接收到X反转指令
  30.                         REV(0);
  31.                 if((KEY_YREV == 0))  //Y反转按键被按下 或 接收到Y反转指令
  32.                         REV(1);
  33.                 if((KEY_XUP  == 0))   //X加速按键被按下 或 接收到X加速指令
  34.                 {        delay(300);                if((KEY_XUP  == 0))                Speed_UP(0); }while(!KEY_XUP);
  35.                 if((KEY_YUP  == 0) )   //Y加速按键被按下 或 接收到Y加速指令
  36.                 {        delay(300);                if((KEY_YUP  == 0))                Speed_UP(1); }while(!KEY_YUP);
  37.                 if((KEY_XDOWN  == 0))  //X减速按键被按下 或 接收到X减速指令
  38.                 {        delay(300);                if((KEY_XDOWN  == 0))        Speed_DOWN(0);}while(!KEY_XDOWN);
  39.                 if((KEY_YDOWN  == 0))  //Y减速按键被按下 或 接收到Y减速指令
  40.                 {        delay(300);                if((KEY_YDOWN  == 0) )         Speed_DOWN(1);}while(!KEY_YDOWN);

  41. }

  42. void Distance_Data()
  43. {
  44.         switch(Distance_Y1)
  45.         {
  46.                 case 1 :        Distance_Y2=500;        break;
  47.                 case 2 :        Distance_Y2=1000;        break;
  48.                 case 3 :        Distance_Y2=3000;        break;
  49.                 case 4 :        Distance_Y2=6000;        break;
  50.                 case 5 :        Distance_Y2=10000;        break;
  51.         }
  52.         switch(Distance_X1)
  53.         {
  54.                 case 1 :        Distance_X2=200;        break;
  55.                 case 2 :        Distance_X2=400;        break;
  56.                 case 3 :        Distance_X2=1200;        break;
  57.                 case 4 :        Distance_X2=2400;        break;
  58.                 case 5 :        Distance_X2=4000;        break;
  59.         }
  60. }
  61. void Distance_Set()
  62. {
  63.         int i=0;
  64.         Disp_Str(2,0,"SET_X:   mm",11);          //显示
  65.         Disp_Str(3,0,"SET_Y:   mm",11);
  66.         if(KEY_SETX==0)                                          //位移设置按键按下
  67.         {        
  68.                 delay(500);
  69.                 if(KEY_SETX==0)
  70.                 {
  71.                         while(!KEY_SETX);
  72.                         ET0=0;                                          //关定时器0,电机停止
  73.                         while(1)                                  //进入死循环,设置位移距离
  74.                         {                                
  75.                                 if(KEY_SET_UP==0)          //位移加按键按下
  76.                                 {
  77.                                         delay(100);
  78.                                         Distance_X1++;        
  79.                                         i++;
  80.                                         if(Distance_X1==6)//位移数组最大到6
  81.                                                 Distance_X1=1;
  82.                                         if(i==5)
  83.                                                 i=0;
  84.                                 }
  85.                                 if(KEY_SET_DOWN==0)
  86.                                 {
  87.                                         delay(100);
  88.                                         Distance_X1--;        
  89.                                         i--;
  90.                                         if(Distance_X1<1)
  91.                                                 Distance_X1=5;
  92.                                         if(i<0)
  93.                                                 i=4;
  94.                                 }
  95.                                 Write_Int(2,3,Distance[i]); //显示当前速度
  96.                                 Distance_Data();                    //位移设置
  97.                                 delay(500);
  98.                                 if(KEY_SETX==0)                                //位移设置按键再次按下退出循环
  99.                                 {
  100.                                         ET0=1;
  101.                                         return;
  102.                                 }
  103.                         }        
  104.                 }
  105.         }
  106.         if(KEY_SETY==0)
  107.         {        
  108.                 delay(500);
  109.                 if(KEY_SETY==0)
  110.                 {
  111.                         while(!KEY_SETY);
  112.                         ET0=0;
  113.                         while(1)
  114.                         {                                
  115.                                 if(KEY_SET_UP==0)
  116.                                 {
  117.                                         delay(100);
  118.                                         Distance_Y1++;        
  119.                                         i++;
  120.                                         if(Distance_Y1==6)
  121.                                                 Distance_Y1=1;
  122.                                         if(i==5)
  123.                                                 i=0;
  124.                                 }
  125.                                 if(KEY_SET_DOWN==0)
  126.                                 {
  127.                                         delay(100);
  128.                                         Distance_Y1--;        
  129.                                         i--;
  130.                                         if(Distance_Y1<1)
  131.                                                 Distance_Y1=5;
  132.                                         if(i<0)
  133.                                                 i=4;
  134.                                 }
  135.                                 Write_Int(3,3,Distance[i]);
  136.                                 Distance_Data();
  137.                                 if(KEY_SETY==0)
  138.                                 {
  139.                                         ET0=1;
  140.                                         return;
  141.                                 }
  142.                         }        
  143.                 }
  144.         }
  145. }
  146. /*限位开关扫描*/
  147. void RUN_SCAN()
  148. {
  149.         static uint Y,X;
  150.         if(EXTI1==0)     //Y轴                 
  151.         {
  152.                 delay(100);
  153.                 if(EXTI1==0)
  154.                 {
  155.                         DIR_Y=~DIR_Y;
  156.                         Y++;
  157.                         if(Y%2)                                   //每次取反之后变量加一,从而判断正反转
  158.                         {
  159.                                 Disp_Str(1,1,"RE",2);        //显示反转
  160.                                 Uart_String("B0002\r\n"); //发送反转指令
  161.                         }        
  162.                         else
  163.                         {
  164.                                 Disp_Str(1,1,"FO",2);
  165.                                 Uart_String("B0001\r\n");
  166.                         }        
  167.                 }while(!EXTI1);
  168.         }
  169.         if(EXTI0==0)                   //X轴
  170.         {
  171.                 delay(100);
  172.                 if(EXTI0==0)
  173.                 {
  174.                         DIR_X=~DIR_X;
  175.                         X++;
  176.                         if(X%2)
  177.                         {
  178.                                 Disp_Str(0,1,"RE",2);
  179.                                 Uart_String("A0002\r\n");        
  180.                         }
  181.                         else
  182.                         {
  183.                                 Disp_Str(0,1,"FO",2);
  184.                                 Uart_String("A0001\r\n");
  185.                         }         
  186.                 }while(!EXTI0);
  187.         }                        
  188. }
  189. /*启动停止按钮*/
  190. void Usert_receive()
  191. {
  192.         if(KEY_STOP==0)
  193.         {
  194.                 delay(200);
  195.                 if(KEY_STOP==0)
  196.                         stop=~stop;
  197.         }while(!KEY_STOP);
  198. }
  199. void main()
  200. {
  201.         Lcd_Init();           //LCD初始化
  202.         Timer0Init();  //定时器0初始化
  203.         UsartInit();   //串口初始化
  204.         while(1)
  205.         {
  206.                 Usert_receive();        //判断启动按键是否被按下
  207.                 while(!(stop==1))        //系统没有启动卡死在改循环中
  208.                 {
  209.                         Usert_receive();   //判断启动是否被按下
  210.                         ET0=0;                           //关闭定时器0
  211.                         Disp_Str(2,0,"    Welcome!    ",16);        //显示
  212.                         Disp_Str(3,0," Please Start!  ",16);
  213.                 }
  214.                 Distance_Set();         //位移设置按键扫描
  215.                 RUN_SCAN();                 //限位开关扫描
  216.                 ET0=1;                         //打开定时器
  217.                 KEY_SCAN();                 //控制按键扫描               
  218.         }
  219. }
复制代码

单片机代码与LabVIEW 51hei附件下载:
十字滑台.7z (67.93 KB, 下载次数: 90)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表