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};
复制代码
|