1) 可以直觀得看到到步進電機的運行軌跡,我們用了128×64LCD液晶顯示屏來直觀得顯示步進電機的實際運行軌跡。 (2) 能夠設定步進電機的運動軌跡半徑大小。 (3) 利用單片機AT89S52的控制,通過按鍵來控制步進電機的正反轉,使其能夠順時針(圓)或者逆時針(圓)運行。
(4) 隨時復位,同時做到在任意象限開始運行。 我不會幫人弄的。有沒有大神會改或者寫這個源程序。求思路
單片機源程序如下:
- #include "LCD12864.H"
- #include <math.H>
- #include <intrins.h>
- #define STEP 1 //定義步進值
- #define KEY_DATA P1 //P1口是按鍵
- #define KEY_NULL 0xff //默認是高電平,按鍵按下是低電平
- sbit F1 = P2^0; //控制電機1I/O口定義
- sbit F2 = P2^1; sbit F3 = P2^2; sbit F4 = P2^3;
- sbit F5 = P3^0; //控制電機2I/O口定義
- sbit F6 = P3^1; sbit F7 = P3^5; sbit F8 = P3^6;
- bit flag1 ; bit flag2 ;
- unsigned char code FFW[8]={0xfe,0xfc,0xfd,0xf9,0xfb,0xf3,0xf7,0xf6}; //反轉
- unsigned char code FFZ[8]={0xf6,0xf7,0xf3,0xfb,0xf9,0xfd,0xfc,0xfe}; //正轉
- char y_start,y_end; //畫線的y坐標起始和終點
- int x_start,x_end; //畫線的x坐標起始和終點
- /********************************************************/
- void motor1_ffw() //電機驅動反轉
- { unsigned char i;
- for (i=0; i<8; i++)
- { P2 = FFW[ i]&0x1f; //取數據
- delay(1000); }
- }
- void motor1_ffz() //電機驅動正轉
- { unsigned char i;
- for (i=0; i<8; i++) //一個周期轉30度
- { P2 = FFZ[ i]&0x1f; //取數據
- delay(1000); }
- }
- void motor2_ffw() //電機驅動反轉
- { F5=1;F6=1;F7=1;F8=0; delay(1000);
- F5=1;F6=1;F7=0;F8=0; delay(1000);
- F5=1;F6=1;F7=0;F8=1; delay(1000);
- F5=1;F6=0;F7=0;F8=1; delay(1000);
- F5=1;F6=0;F7=1;F8=1; delay(1000);
- F5=0;F6=0;F7=1;F8=1; delay(1000);
- F5=0;F6=1;F7=1;F8=1; delay(1000);
- F5=0;F6=1;F7=1;F8=0; delay(1000);
- }
- void motor2_ffz() //電機驅動正轉
- { F5=0;F6=1;F7=1;F8=0; delay(1000);
- F5=0;F6=1;F7=1;F8=1; delay(1000);
- F5=0;F6=0;F7=1;F8=1; delay(1000);
- F5=1;F6=0;F7=1;F8=1; delay(1000);
- F5=1;F6=0;F7=0;F8=1; delay(1000);
- F5=1;F6=1;F7=0;F8=1; delay(1000);
- F5=1;F6=1;F7=0;F8=0; delay(1000);
- F5=1;F6=1;F7=1;F8=0; delay(1000);
- }
- void xiangxian1ni()
- { int x0,j,f, y0,y1; x0=20;y0=20 ; y1=0; j=x0+y0; f=0;
- y_start=32;y_end=y_start; x_start=43 ;x_end=x_start;
- do { x_start=x_end; y_start=y_end;
- if (f>=0)
- { motor1_ffw(); flag2=0; delay(10000);
- x_end=x_end+STEP; y_end=y_end;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f-2*x0+1; x0=x0-1; delay(10000); }
- else
- { motor2_ffz(); flag1=0; delay(10000);
- x_end=x_end; y_end=y_end+STEP;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f+2*y1+1; y1=y1+1; delay(10000); }
- j=j-1; }
- while (j!=0);
- }
- void xiangxian2ni()
- { int x0,x1, j,f, y1; x0=20;x1=0; y1=20; j=x0+y1; f=0;
- y_start=53;y_end=y_start; x_start=64;x_end=x_start;
- do { x_start=x_end; y_start=y_end; flag1=1; flag2=1;
- if (f>=0)
- { motor2_ffw(); flag1=0; delay(10000);
- x_end=x_end; y_end=y_end-STEP;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f-2*y1+1; y1=y1-1; delay(10000); }
- else { motor1_ffw(); flag2=0; delay(10000);
- x_end=x_end+STEP; y_end=y_end;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f+2*x1+1; x1=x1+1; delay(10000); }
- j=j-1; }
- while (j!=0);
- }
- void xiangxian3ni()
- { int x0,y0, j,f, y1; x0=20; y1=20;y0=0; j=x0+y1; f=0;
- y_start=32;y_end=y_start; x_start=85;x_end=x_start;
- do { x_start=x_end; y_start=y_end; flag1=1; flag2=1;
- if (f>=0)
- { motor1_ffz(); flag2=0; delay(10000);
- x_end=x_end-STEP; y_end=y_end;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f-2*x0+1; x0=x0-1; delay(10000); }
- else
- { motor2_ffw(); flag1=0; delay(10000);
- x_end=x_end; y_end=y_end-STEP;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f+2*y0+1; y0=y0+1; delay(10000); }
- j=j-1; }
- while (j!=0);
- }
- void xiangxian4ni()
- { int x0,x1, j,f, y1; x0=20;x1=0; y1=20; j=x0+y1; f=0;
- y_start=11;y_end=y_start; x_start=64;x_end=x_start;
- do { x_start=x_end; y_start=y_end; flag1=1; flag2=1;
- if (f>=0)
- { motor2_ffz(); flag1=0; delay(10000);
- x_end=x_end; y_end=y_end+STEP;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f-2*y1+1; y1=y1-1; delay(10000); }
- else
- { motor1_ffz(); flag2=0; delay(10000);
- x_end=x_end-STEP; y_end=y_end;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f+2*x1+1; x1=x1+1; delay(10000); }
- j=j-1; }
- while (j!=0);
- }
- void xiangxian1shun()
- { int x0,x1, j,f, y1; x0=20;x1=0; y1=20; j=x0+y1; f=0;
- y_start=53;y_end=y_start; x_start=64;x_end=x_start;
- do { x_start=x_end; y_start=y_end; flag1=1; flag2=1;
- if (f>=0)
- { motor2_ffw(); flag1=0; delay(10000);
- x_end=x_end; y_end=y_end-STEP;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f-2*y1+1; y1=y1-1; delay(10000); }
- else
- { motor1_ffz(); flag2=0; delay(10000);
- x_end=x_end-STEP; y_end=y_end;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f+2*x1+1; x1=x1+1; delay(10000); }
- j=j-1; }
- while (j!=0);
- }
- void xiangxian4shun()
- { int x0,j,f, y0,y1; x0=20;y0=20 ; y1=0; j=x0+y0; f=0;
- y_start=32;y_end=y_start; x_start=43 ;x_end=x_start;
- do { x_start=x_end; y_start=y_end; flag1=1; flag2=1;
- if (f>=0)
- { motor1_ffw(); flag2=0; delay(10000);
- x_end=x_end+STEP; y_end=y_end;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f-2*x0+1; x0=x0-1; delay(10000); }
- else
- { motor2_ffw();flag1=0; delay(10000);
- x_end=x_end; y_end=y_end-STEP;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f+2*y1+1; y1=y1+1; delay(10000); }
- j=j-1; }
- while (j!=0);
- }
- void xiangxian3shun()
- { int x0,x1, j,f, y1; x0=20;x1=0; y1=20; j=x0+y1; f=0;
- y_start=11;y_end=y_start; x_start=64;x_end=x_start;
- do { x_start=x_end; y_start=y_end; flag1=1; flag2=1;
- if (f>=0)
- { motor2_ffz(); flag1=0; delay(10000);
- x_end=x_end; y_end=y_end+STEP;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f-2*y1+1; y1=y1-1; delay(10000); }
- else
- { motor1_ffw(); flag2=0; delay(10000);
- x_end=x_end+STEP; y_end=y_end;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f+2*x1+1; x1=x1+1; delay(10000); }
- j=j-1; }
- while (j!=0);
- }
- void xiangxian2shun()
- { int x0,j,f, y0,y1; x0=20;y0=20 ; y1=0; j=x0+y0; f=0;
- y_start=32;y_end=y_start; x_start=85;x_end=x_start;
- do { x_start=x_end; y_start=y_end; flag1=1; flag2=1;
- if (f>=0)
- { motor1_ffz(); flag2=0; delay(10000);
- x_end=x_end-STEP; y_end=y_end;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f-2*x0+1; x0=x0-1; delay(10000); }
- else
- { motor2_ffz(); flag1=0; delay(10000);
- x_end=x_end; y_end=y_end+STEP;
- GUI_Line(x_start,y_start,x_end,y_end,1);
- f=f+2*y1+1; y1=y1+1; delay(10000); }
- j=j-1; }
- while (j!=0);
- }
- //*********************************************************************************************
- //說明:程序主函數
- //*********************************************************************************************
- void main()
- {
- /***********************液晶初始化***************************/
- Display_Init();
- GUI_Fill_GDRAM(0x00);
- GUI_Line(0,32,127,32,1);
- GUI_Line(0,32,4,30,1);
- GUI_Line(0,32,4,34,1);
- GUI_Line(64,0,64,63,1);
- GUI_Line(62,60,64,63,1);
- GUI_Line(66,60,64,63,1);
- KEY_DATA=KEY_NULL;
- while(1)
- {
- delay(1000);
- switch(KEY_DATA)
- {
- case 0xfe:
- xiangxian1ni();
- KEY_DATA=0xff;
- break;
- case 0xfd:
- xiangxian2ni();
- KEY_DATA=0xff;
- break;
- case 0xfb:
- xiangxian3ni();
- KEY_DATA=0xff;
- break;
- case 0xf7:
- xiangxian4ni();
- KEY_DATA=0xff;
- break;
- case 0xef:
- xiangxian1shun();
- KEY_DATA=0xff;
- break;
- case 0xdf:
- xiangxian4shun();
- KEY_DATA=0xff;
- break;
- case 0xbf:
- xiangxian3shun();
- KEY_DATA=0xff;
- break;
- case 0x7f:
- xiangxian2shun();
- KEY_DATA=0xff;
- break;
- default:
- break; }
- }
- }
- 第二部分,調用LCD液晶屏程序部分:
- #include "LCD12864.h" //包含液晶端口定義的頭文件
- //********************************************************
- //延時函數
- //********************************************************
- void delay(unsigned int k)
- {
- unsigned int i; unsigned char j;
- for(i=0;i<k;i++)
- {
- for(j=0;j<10;j++);
- }
- }
- //********************************************************
- //延時1ms函數
- //********************************************************
- void delay_ms(unsigned int k) //延時0.994us,晶振12M
- {
- unsigned int x,y;
- for(x=k;x>0;x--)
- for(y=121;y>0;y--);
- }
- //********************************************************
- //寫命令函數
- //********************************************************
- void LcdWcom(unsigned char WCom)
- {
- delay(1);
- RS=0; //指明操作對象為指令寄存器
- RW=0; //指明為寫操作
- E=1;
- lcd_data=WCom; //將命令寫入總線
- E=0;
- }
- //********************************************************
- //寫數據函數
- //********************************************************
- void LcdWdata(unsigned char WData)
- {
- delay(1);
- RS=1; //指明操作對象為數據寄存器
- RW=0; //指明為寫操作
- E=1;
- lcd_data=WData; //將數據寫入總線
- E=0;
- }
- //********************************************************
- //顯示初始化函數
- //********************************************************
- void Display_Init(void)
- {
- delay_ms(45); //延時45ms
- RST=1;
- delay(1);
- RST=0;
- delay(1);
- RST=1;
- delay(1);
- LcdWcom(0x30); //設置為8位并行口,基本指令集
- delay(10);
- LcdWcom(0x30); //再次設置為8位并行口,基本指令集
- delay(5);
- LcdWcom(0x01);
- delay_ms(12); //延時12ms
- LcdWcom(0x06); //設置為游標右移,DDRAM位地址加1,畫面不移動
- delay(5);
- LcdWcom(0x0C); //開顯示
- }
- //********************************************************
- //讀數據函數
- //********************************************************
- unsigned char LcdRdata(void)
- {
- unsigned char LcdData;
- lcd_data=0xff; //釋放數據線
- RW=1; //指明為讀操作
- RS=1; //指明操作對象為數據寄存器
- E=1;
- delay(1);
- LcdData = lcd_data; //讀取數據線上的數據
- E=0;
- return (LcdData);
- }
- //********************************************************
- //填充GDRAM數據:
- //參數:dat為填充的數據
- //********************************************************
- void GUI_Fill_GDRAM(unsigned char dat)
- {
- unsigned char i; unsigned char j; unsigned char k;
- unsigned char bGDRAMAddrX = 0x80; //GDRAM水平地址
- unsigned char bGDRAMAddrY = 0x80; //GDRAM垂直地址
- for(i = 0; i < 2; i++)
- {
- for(j = 0; j < 32; j++)
- {
- for(k = 0; k < 8; k++)
- {
- LcdWcom(0x34); //設置為8位MPU接口,擴充指令集,繪圖模式關
- LcdWcom(bGDRAMAddrY+j); //垂直地址Y
- LcdWcom(bGDRAMAddrX+k); //水平地址X
- LcdWdata(dat);
- LcdWdata(dat); }
- }
- bGDRAMAddrX = 0x88;
- }
- LcdWcom(0x36); //打開繪圖模式
- LcdWcom(0x30); //恢復基本指令集,關閉繪圖模式
- }
- //********************************************************
- //打點函數
- //參數:color=1,該點填充1;color=0,該點填充白色0;
- //********************************************************
- void GUI_Point(unsigned char x,unsigned char y,unsigned char color)
- {
- unsigned char x_Dyte,x_byte; //定義列地址的字節位,及在字節中的哪1位
- unsigned char y_Dyte,y_byte; //定義為上下兩個屏(取值為0,1),行地址(取值為0~31)
- unsigned char GDRAM_hbit,GDRAM_lbit;
- LcdWcom(0x36); //擴展指令命令
- x_Dyte=x/16; //計算在16個字節中的哪一個
- x_byte=x&0x0f; //計算在該字節中的哪一位
- y_Dyte=y/32; //0為上半屏,1為下半屏
- y_byte=y&0x1f; //計算在0~31當中的哪一行
- LcdWcom(0x80+y_byte); //設定行地址(y坐標),即是垂直地址
- LcdWcom(0x80+x_Dyte+8*y_Dyte); //設定列地址(x坐標),并通過8*y_Dyte選定上下屏,即是水平地址
- LcdRdata(); //預讀取數據
- GDRAM_hbit=LcdRdata(); //讀取當前顯示高8位數據
- GDRAM_lbit=LcdRdata(); //讀取當前顯示低8位數據
- delay(1);
- LcdWcom(0x80+y_byte); //設定行地址(y坐標)
- LcdWcom(0x80+x_Dyte+8*y_Dyte); //設定列地址(x坐標),并通過8*y_Dyte選定上下屏
- delay(1);
- if(x_byte<8) //判斷其在高8位,還是在低8位
- {
- if(color==1)
- {
- LcdWdata(GDRAM_hbit|(0x01<<(7-x_byte))); //置位GDRAM區高8位數據中相應的點
- }
- else
- LcdWdata(GDRAM_hbit&(~(0x01<<(7-x_byte)))); //清除GDRAM區高8位數據中相應的點
- LcdWdata(GDRAM_lbit); //顯示GDRAM區低8位數據
- }
- else
- {
- LcdWdata(GDRAM_hbit);
- if(color==1)
- LcdWdata(GDRAM_lbit|(0x01<<(15-x_byte))); //置位GDRAM區高8位數據中相應的點
- else
- LcdWdata(GDRAM_lbit&(~(0x01<<(15-x_byte))));//清除GDRAM區高8位數據中相應的點
- }
- LcdWcom(0x30); //恢復到基本指令集
- }
- //**************************************************************
- //畫水平線函數
- //參數:color=1,填充1;color=0,填充0;
- // x0,x1為起始和終點的水平坐標值,y為垂直坐標值
- //**************************************************************
- void GUI_HLine(unsigned char x0, unsigned char x1, unsigned char y, unsigned char color)
- {
- unsigned char bak;
- if(x0>x1) // 對x0、x1大小進行排列,以便畫圖
- {
- bak = x1;
- x1 = x0;
- x0 = bak;
- }
- do
- {
- GUI_Point(x0, y, color); // 從左到右逐點顯示,描出垂直線
- x0++;
- }while(x1>=x0);
- }
- //********************************************************
- //畫豎直線函數
- //參數:color=1,填充黑色1;color=0,填充0;
- // x為起始和終點的水平坐標值,y0,y1為垂直坐標值
- //********************************************************
- void GUI_RLine(unsigned char x, unsigned char y0, unsigned char y1, unsigned char color)
- {
- unsigned char bak;
- if(y0>y1) // 對y0、y1大小進行排列,以便畫圖
- {
- bak = y1;
- y1 = y0;
- y0 = bak;
- }
- do
- {
- GUI_Point(x, y0, color); // 從上到下逐點顯示,描出垂直線
- y0++;
- }while(y1>=y0);
- }
- //********************************************************
- //任意兩點畫直線函數
- //參數:color=1,該線填充1;color=0,該線填充0;
- // x0:直線起點的x坐標值,y0:直線起點的y坐標值
- // x1:直線終點的x坐標值,y1:直線終點的y坐標值
- //********************************************************
- void GUI_Line(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char color)
- {
- char dx; // 直線x軸差值變量
- char dy; // 直線y軸差值變量
- char dx_sym; // x軸增長方向,為-1時減值方向,為1時增值方向
- char dy_sym; // y軸增長方向,為-1時減值方向,為1時增值方向
- char dx_x2; // dx*2值變量,用于加快運算速度
- char dy_x2; // dy*2值變量,用于加快運算速度
- char di; // 決策變量
- if(x0==x1) //判斷是否為垂直線
- {
- GUI_RLine(x0,y0,y1,color); //畫垂直線
- return;
- }
- if(y0==y1) //判斷是否為水平線
- {
- GUI_HLine(x0,x1,y0,color); //畫水平線
- return;
- }
- dx = x1-x0; // 求取兩點之間的差值
- dy = y1-y0;
- /* 判斷增長方向,或是否為水平線、垂直線、點 */
- if(dx>0) // 判斷x軸方向
- {
- dx_sym = 1; // dx>0,設置dx_sym=1
- }
- else
- {
- if(dx<0)
- {
- dx_sym = -1; // dx<0,設置dx_sym=-1
- }
- else
- {
- // dx==0,畫垂直線,或一點
- GUI_RLine(x0, y0, y1, color);
- return; }
- }
- if(dy>0) // 判斷y軸方向
- {
- dy_sym = 1; // dy>0,設置dy_sym=1
- }
- else
- {
- if(dy<0)
- { dy_sym = -1; // dy<0,設置dy_sym=-1 }
- else
- {
- // dy==0,畫水平線,或一點
- GUI_HLine(x0, y0, x1, color);
- return; }
- }
- /* 將dx、dy取絕對值 */
- dx = dx_sym * dx;
- dy = dy_sym * dy;
- /* 計算2倍的dx及dy值 */
- dx_x2 = dx*2;
- dy_x2 = dy*2;
- /* 使用Bresenham法進行畫直線 */
- if(dx>=dy) // 對于dx>=dy,則使用x軸為基準
- {
- di = dy_x2 - dx;
- while(x0!=x1)
- {
- GUI_Point(x0, y0, color);
- x0 += dx_sym;
- if(di<0)
- {
- di += dy_x2; // 計算出下一步的決策值 }
- else
- {
- di += dy_x2 - dx_x2; y0 += dy_sym; }
- }
- GUI_Point(x0, y0, color); // 顯示最后一點
- }
- else // 對于dx<dy,則使用y軸為基準
- {
- di = dx_x2 - dy; while(y0!=y1)
- {
- GUI_Point(x0, y0, color);
- y0 += dy_sym;
- if(di<0)
- { di += dx_x2; }
- else
- { di += dx_x2 - dy_x2; x0 += dx_sym; }
- }
- GUI_Point(x0, y0, color); // 顯示最后一點 }
- }
- unsigned char code DCB2HEX_TAB[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
復制代碼
|