使用A4988驅(qū)動模塊驅(qū)動42步進電機
一、結(jié)構(gòu)問題
1、兩個滑臺的尺寸不匹配,X絲杠滑塊與Y軸絲杠底座安裝不到一起
解決方案:將兩個絲杠模組全部解體,將X絲杠滑塊打穿,用螺絲固定,并用銼刀進行打磨。
潛在問題:①銼刀打磨過的螺絲可能不能使用,若后期拆卸,需另覓蹊徑;②由于結(jié)構(gòu)問題,X絲杠滑塊與Y絲杠底座固定處只用了兩個螺絲,連接不太穩(wěn)定,已用三秒固定。
2、限位開關(guān)與絲杠之前沒有連接零件
解決方案:手工打磨或采用3D打印該工件。
潛在問題:由于傳感器與控制系統(tǒng)均采用5V供電,因此金屬限位開關(guān)的有效檢測距離只有 ,所以連接必須可靠,并且必須保證滑塊必須在傳感器檢測的有效距離之內(nèi),否則會燒毀步進電機。
二、方案設(shè)計問題
1、上位機與下位機通訊協(xié)議的約定
最初打算采用幀頭+數(shù)據(jù)幀+幀尾的格式,但限于項目時間,故采用如下協(xié)議約定。
上位機接收指令如下表所示:
注:位移控制設(shè)置三個按鍵分別為:設(shè)置、加、減,采用光標跳轉(zhuǎn)進行不同軸的設(shè)置
②軟件:
采用定時器輸出A4988驅(qū)動的脈沖,從而控制步進電機的角速度、角位移;
采用2個外部中斷判斷金屬限位開關(guān)是否被觸發(fā),因為該中斷優(yōu)先級最高;
采用串口和上位機進行通訊。
3、金屬接近傳感器電路設(shè)計
由于51系別單片機外部中斷資源有限,所需傳感器有4個,故每一個絲杠模組兩端傳感器作為一組,作為“與門”的輸入,輸出信號傳給單片機的外部中斷,這樣可以保證任何一個傳感器輸出信號都可以觸發(fā)外部中斷。
4、步進電機的失能控制
雖然A4988驅(qū)動上有ENABLE端口,但是51單片機的硬件資源已經(jīng)使用完畢,因此,只能停止脈沖輸入,從而控制步進電機失能。
5、滑塊的速度、位移計算
本項目采用兩個步距角為1.8°的兩相四線步進電機,在1細分的驅(qū)動下,一個脈沖轉(zhuǎn)動1.8°,因此轉(zhuǎn)動一圈(360°)需要200個脈沖。由于絲杠的精度較高,所以步進電機的角位移轉(zhuǎn)換為滑塊的位移比例差距較大,電機每轉(zhuǎn)動一圈,滑塊位移()mm(還未測量),控制精度完全滿足要求,因此我們采用1細分進行驅(qū)動。
利用鋼尺測量出電機的角位移與滑塊線位移的關(guān)系為:
得出滑塊的速度為:
其中t為滑塊位移的時間,該時間利用脈沖周期進行計算
單片機源程序如下:
- # include <Motor_Con.h>
- sbit KEY_XFOR = P2^6; //X正轉(zhuǎn)按鍵
- sbit KEY_XREV = P2^5; //X反轉(zhuǎn)按鍵
- sbit KEY_XUP = P1^2; //X加速按鍵
- sbit KEY_XDOWN =P1^1; //X減速按鍵
- sbit KEY_YFOR = P2^7; //Y正轉(zhuǎn)按鍵
- sbit KEY_YREV = P1^6; //Y反轉(zhuǎn)按鍵
- 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位移設(shè)置按鍵
- sbit KEY_SETY =P2^1; //Y位移設(shè)置按鍵
- sbit KEY_STOP =P2^4; //啟動停止按鍵
- extern char User_Data[];
- int Distance_X2,Distance_Y2; //定時器所需取反的脈沖次數(shù)
- 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; //啟動停止標志
- /*按鍵掃描函數(shù)*/
- void KEY_SCAN()
- {
- if((KEY_XFOR == 0)) //X正轉(zhuǎn)按鍵被按下 或 接收到X正轉(zhuǎn)指令
- FOR(0);
- if((KEY_YFOR == 0)) //Y正轉(zhuǎn)按鍵被按下 或 接收到Y(jié)正轉(zhuǎn)指令
- FOR(1);
- if((KEY_XREV == 0)) //X反轉(zhuǎn)按鍵被按下 或 接收到X反轉(zhuǎn)指令
- REV(0);
- if((KEY_YREV == 0)) //Y反轉(zhuǎn)按鍵被按下 或 接收到Y(jié)反轉(zhuǎn)指令
- 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(jié)加速指令
- { 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(jié)減速指令
- { 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) //位移設(shè)置按鍵按下
- {
- delay(500);
- if(KEY_SETX==0)
- {
- while(!KEY_SETX);
- ET0=0; //關(guān)定時器0,電機停止
- while(1) //進入死循環(huán),設(shè)置位移距離
- {
- if(KEY_SET_UP==0) //位移加按鍵按下
- {
- delay(100);
- Distance_X1++;
- i++;
- if(Distance_X1==6)//位移數(shù)組最大到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(); //位移設(shè)置
- delay(500);
- if(KEY_SETX==0) //位移設(shè)置按鍵再次按下退出循環(huán)
- {
- 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;
- }
- }
- }
- }
- }
- /*限位開關(guān)掃描*/
- void RUN_SCAN()
- {
- static uint Y,X;
- if(EXTI1==0) //Y軸
- {
- delay(100);
- if(EXTI1==0)
- {
- DIR_Y=~DIR_Y;
- Y++;
- if(Y%2) //每次取反之后變量加一,從而判斷正反轉(zhuǎn)
- {
- Disp_Str(1,1,"RE",2); //顯示反轉(zhuǎn)
- Uart_String("B0002\r\n"); //發(fā)送反轉(zhuǎ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)) //系統(tǒng)沒有啟動卡死在改循環(huán)中
- {
- Usert_receive(); //判斷啟動是否被按下
- ET0=0; //關(guān)閉定時器0
- Disp_Str(2,0," Welcome! ",16); //顯示
- Disp_Str(3,0," Please Start! ",16);
- }
- Distance_Set(); //位移設(shè)置按鍵掃描
- RUN_SCAN(); //限位開關(guān)掃描
- ET0=1; //打開定時器
- KEY_SCAN(); //控制按鍵掃描
- }
- }
復(fù)制代碼
單片機代碼與LabVIEW 51hei附件下載:
十字滑臺.7z
(67.93 KB, 下載次數(shù): 90)
2021-11-4 04:13 上傳
點擊文件名下載附件
|