[资料] 51单片机三轴带直线圆弧插补运动控制代码

[复制链接]

实习生

发表于 2015-10-19 11:09:14   3486 查看 11 回复 显示全部楼层 倒序浏览
分享

单片机与mpc006运动控制芯片模块组成的运动控制系统

摘要:采用单片机stc89C2051和mpc006运动控制芯片模块作为控制系统的核心,控制三路步进电机做运动实验。单片机发送指令给mpc006微型运动控制模块,模块信号输出给步进驱动器作高速度运动。可以定点运动,直线插补和圆弧插补。

1.引言
运动控制的应用在国内已有十几年的历史,技术也相当成熟。通常运动控制都需要用到运动控制卡,运动控制器等产品,但这些产品价格高昂,使用复杂,也不适合由单片机构成的控制系统。而如果直接采用单片机来做运动控制,由于运动控制对系统性能要求非常高,单片机速度资源有限,难以设计出性能优良的运动控制模型。因此,本文采用单片机和专业的mpc006运动控制芯片模块构成运动控制系统。
MPC006运动控制芯片模块采用新型FPGA设计,集成实用运动控制功能,可与普通单片机通过串口通讯对步进电机和伺服电机控制。具有如下特点:
   串口通讯,仅需使用几条指令,简单可靠。
   单模块最高六轴输出,多个模块组网工作可达120轴。
   最大脉冲输出频率为2MHz,脉冲输出使用脉冲+方向方式。
   最高六轴独立运动控制,任意两轴直线插补,任意两轴圆弧插补。  
   每轴一路硬件回原点。
   模块带1000条指令缓存深度,指令先进先出,无需高速通讯。
  模块体积小巧,仅3.5*2.5*1.5cm,双排直插30脚封装
2,系统硬件设计
硬件系统由四部分构成:
(1)       单片机部分
单片机与模块只需三根线连接,用作串口通讯的RXDTXD,用作模块缓存满输出的BUSY信号。P3.7引出一按键作为测试使用。
file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image001.jpg
(2)      mpc006运动控制芯片模块部分
mpc006运动控制芯片模块采用5V电源供电,RXD,TXDBUSY与单片机连接。X0X1X2可作为三路电机的原点信号,P1D11轴的脉冲和方向信号。P2D22轴的脉冲和方向信号。P3D33轴的脉冲和方向信号。
file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image002.jpg
3原点信号输入部分
原点采用光藕隔离输入,输入端可接NPN型光电开关来作为原点信号。
file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image003.jpg
(4)       信号输出部分
输出采用NPN晶体管极电极开路输出,分别接到电机驱动器脉冲和方向信号输入端。
file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image004.jpg



3,系统软件设计
MPC006运动控制芯片模块与单片机串口通讯速率为115200bps,数据位为8位,停止位1位,无校验。
单片机与mpc006运动控制模块采用串口应答式通讯,单片机作主机,单片机每发送一条指令给mpc006运动控制芯片模块,mpc006运动控制芯片模块返回以0x68开始的固定长度为10个字节的数据串。单片机可以取出需要的数据。一般情况需接收到mpc006运动控制模块返回的数据后单片机才能发送下一条指令。如果程序中不接收模块返回的数据,需间隔5MS以上才能发送下一条指令。
单片机发送和接收指令的数据格式如下:
  
起始码
  
数据个数
模块地址
功能码
参数
校验和
0x68
1字节
1字节
1字节
1字节
起始码:为一条指令的起始字节内容,固定为0x68
数据个数:为从数据个数开始到校验和的数据长度。
模块地址:为控制器的通讯地址。地址0对所有控制器都有效。
功能码:表示指令的功能,每条指令的功能码都是唯一的。
参数:表示指令的参数,每条指令的参数字节数并不都是相同的。
校验和:为从数据个数开始到校验和前一个字节的校验和。
mpc006运动控制芯片模块默认地址为0,可以接收带任何地址的指令数据。如果单片机串口只连接了一个模块,地址可以不用设置。
mpc006运动控制芯片模块无需任何初使化。上电后只发一条pmove单轴运行指令对应轴都会有脉冲输出。
使用函数前先设置好单片机的串口功能,并将需要用到的函数的原型拷贝到当前程序内。本文所使用的函数原型为基础版本,已根据模块使用说明书中通讯协议将各指令通讯过程描述出来。用户可根据所使用单片机的资源在保证通讯格式正确的情况下作出适当优化。
试验程序如下,完整代码请下载附件

/*
函数名:    inp_move
功能:二轴直线插补
参数:
cardno    卡号
no1   X轴轴号
no2   Y轴轴号
pulse1,pulse2                       X-Y轴移动的距离,范围(-8388608~+8388607
mode  0:相对位移 1:绝对位移  
返回值:
0 失败           1 成功
*/
unsigned charinp_move(unsigned char cardno,unsigned char no1 ,unsigned char no2 , longpulse1  ,long pulse2 ,unsigned char mode)
{
unsigned charOutByte[25];
unsigned charinbuf[12];
OutByte[0] = 0x68;
OutByte[1] = 0x0F;
OutByte[2] = cardno;
OutByte[3] = 0x7;
OutByte[4] = no1;
OutByte[5] = no2;
OutByte[6] =pulse1>>24;
OutByte[7] = pulse1>>16;
OutByte[8] = pulse1>>8;
OutByte[9] = pulse1;
OutByte[10] = pulse2>>24;
OutByte[11] = pulse2>>16;
OutByte[12] = pulse2>>8;
OutByte[13] = pulse2;
OutByte[14] = mode;
OutByte[15]=OutByte[1] +OutByte[2] +OutByte[3] +OutByte[4]+OutByte[5] +OutByte[6]+OutByte[7] +OutByte[8] +OutByte[9] +OutByte[10] +OutByte[11] + \
OutByte[12]+OutByte[13] +OutByte[14];
USRAT_transmit(OutByte,16);
receive(inbuf);
return 1;
}
/*
函数名: inp_arc
功能:二轴圆弧插补
参数:
cardno     卡号
no1         参与插补X轴的轴号
no2         参与插补Y轴的轴号
x,y          圆弧插补的终点位置(相对于起点),范围(-8388608~+8388607                       
i,j           圆弧插补的圆心点位置(相对于起点),范围(-8388608~+8388607
mode      0:顺时针插补   1:逆时针插补
返回值:
0 失败           1 成功
*/
unsigned charinp_arc(unsigned char cardno ,unsigned char no1,unsigned char no2, long X ,long y, long i, long j,unsigned char mode )
{
unsigned char OutByte[25];
unsigned charinbuf[12];
OutByte[0] = 0x68;
OutByte[1] = 0x17;
OutByte[2] = cardno;
OutByte[3] = 0x8;
OutByte[4] = no1;
OutByte[5] = no2;
OutByte[6] = X>>24;
OutByte[7] = X>>16;
OutByte[8] = X>>8;
OutByte[9] = X ;
OutByte[10] = y>>24;
OutByte[11] = y>>16;
OutByte[12] = y>>8;
OutByte[13] = y ;
OutByte[14] = i>>24;
OutByte[15] = i>>16;
OutByte[16] = i>>8;
OutByte[17] = i ;
OutByte[18] = j>>24;
OutByte[19] = j>>16;
OutByte[20] = j>>8;
OutByte[21] = j ;
OutByte[22] = mode;
OutByte[23] =OutByte[1]+OutByte[2] +OutByte[3] +OutByte[4] +OutByte[5] +OutByte[6] +OutByte[7]+OutByte[8] +OutByte[9] +OutByte[10] +OutByte[11] + \
OutByte[12]+OutByte[13] +OutByte[14] +OutByte[15] +OutByte[16] +OutByte[17] +OutByte[18]+OutByte[19] +OutByte[20] +OutByte[21] +OutByte[22] ;
USRAT_transmit(OutByte,24);      
receive(inbuf);
return 1;
}
/*
函数名: set_speed
功能:设置轴速度
参数:
cardno     卡号
axis  轴号(1-6)
acc     加速时间(ms
dec     减速时间(ms
startv     启动频率为:值*频率倍率(Hz)
speed      运行频率为:值*频率倍率(Hz)
range      频率倍率(1-100)
返回值:
0 失败           1 成功
*/
unsigned charset_speed(unsigned char cardno ,unsigned char axis ,unsigned int acc  ,unsigned int dec  ,unsigned int startv ,unsigned int speed ,unsignedchar range)
{
unsigned charOutByte[25];
unsigned charinbuf[12];
OutByte[0] = 0x68;
OutByte[1] = 0xe;
OutByte[2] = cardno;
OutByte[3] = 1;
OutByte[4] = axis;
OutByte[5] = acc>>8;
OutByte[6] = acc ;
OutByte[7] = dec>>8;
OutByte[8] = dec ;
OutByte[9] = startv>>8;
OutByte[10] = startv;
OutByte[11] = speed>>8;
OutByte[12] = speed;
OutByte[13] = range;
OutByte[14]=OutByte[1] +OutByte[2] +OutByte[3] +OutByte[4] +OutByte[5] +OutByte[6]+OutByte[7] +OutByte[8] +OutByte[9] +OutByte[10] +OutByte[11] + OutByte[12] +OutByte[13];
USRAT_transmit(OutByte,15);
receive(inbuf);
return 1;
}




void main(void)  
{
   //initial();
   init_uart();
   //set_cardno(1);               //设卡号为1
       pmove(1,1,100000,0);   
   while(1)
        {
              
        if(!s1)//按键按下
         {
          set_speed(1 ,1,1000,1000,10,200,100);  // 1轴速度
        set_speed(1 ,2,1000,1000,10,200,100);   // 2轴速度
        set_speed(1 ,3,1000,1000,10,200,100);   // 3轴速度
         /*1轴回原点*/
         pmove(1,1,-1000000,0);              //   1轴运动
         wait_in(1,0,1);                           //   等待X0为高
         sudden_stop(1,1);                      //      1轴停止
        set_command_pos(1,1,0);             //        1轴此时坐标为0
              pmove(1,2,3200,0);               //   2轴运动
              wait_stop(1 ,2);               //等待2轴停止
              wait_delay(1,5000);           //延时5
              pmove(1,3,-3200,0);              // 3轴运动  
           while(!s1);
         }
        
        }
}


基于51单片机与mpc006运动控制芯片模块的三轴运动控制系统.pdf

237.51 KB, 下载次数: 142, 下载积分: 积分 -1 分

标签:51单片机

实习生

发表于 2016-3-17 09:36:53  
好东西,值得分享
回复

举报

技术员

发表于 2016-4-2 13:48:28  
谢谢楼主的无私分享
回复

举报

实习生

发表于 2016-4-15 19:18:56  
学习,谢谢分享~~~~~~~~
回复

举报

技术员

发表于 2016-6-8 10:48:06  
谢谢楼主分享的好资料
回复

点赞 举报

实习生

发表于 2016-6-15 13:39:37    楼主|
mpc003,mpc004,mpc006,mpc004s运动控制芯片模块直接插入底板就成运动控制器了,可与PLC电脑通讯了
回复

点赞 举报

发表于 2016-6-17 14:20:28  
51单片机三轴带直线圆弧插补运动控制代码
回复

点赞 举报

实习生

发表于 2016-11-12 23:09:25  
回复

举报

实习生

发表于 2017-3-20 19:38:25   来自手机
学习了
回复

举报

实习生

发表于 2017-5-19 17:01:50  
51单片机三轴带直线圆弧插补运动控制 好东西
回复

点赞 举报

技术员

发表于 2017-5-27 10:07:33  
感谢楼主分享。
回复

点赞 举报

实习生

发表于 2017-12-7 12:09:52    楼主|
两轴SPI通讯TSSOP20封装运动控制芯片mpc02t的程序

#include <reg52.h>
//-----STC89C2051-------
sfr IPH                =0XB7;               
sfr        CCON        =0XD8;
sfr        CMOD        =0XD9;
sfr        CL                =0XE9;
sfr        CH                =0XF9;
sfr        CCAP0L        =0XEA;
sfr        CCAP0H        =0XFA;
sfr        CCAPM0        =0XDA;
sfr        CCAPM1        =0XDB;
sfr P3M1= 0XB1;
sfr P3M0= 0XB2;
sfr P1M1= 0X91;
sfr P1M0= 0X92;
sfr WAKE_CLKO= 0X8f;
sfr BRT     =0x9c;
sfr AUXR     =0x8E;
sfr AUXR1   = 0xA2;     
sfr WDT_CONTR = 0xc1;               
sfr T2MOD  = 0xC9;                    
//////////////////
sbit s1 = P1^6;
sbit s2        =        P1^7;

sbit b1        =        P3^7;

sbit cs2         = P1^4;
sbit cs         = P1^3;
sbit sck = P1^2;
sbit out = P1^0;
sbit in         = P1^1;

#define SPI2_CSHIGH cs2=1 // CS2
#define SPI2_CSLOW         cs2=0
#define SPI_CSHIGH cs=1 // CS
#define SPI_CSLOW         cs=0
#define SPI_SCKHIGH sck=1 //SCLK
#define SPI_SCKLOW sck=0
#define SPI_OUTHIGH out=1
#define SPI_OUTLOW  out=0//MOSI
#define SPI_IN in//MISO

unsigned char inbuf[12];      

void initial()
{

SPI_CSHIGH;
SPI2_CSHIGH;                                               
}



void delay_nus(unsigned long n)
{
       unsigned long j;
       while(n--)

       {
              j=8;          
            while(j--);
       }
}

//延时n ms

void delay_nms(unsigned long n)

{
       while(n--)
              delay_nus(1100);                 

}



/*
函数名:   SPI_SendData
功能:软件模拟SPI通讯发送并接收一个8位字节数据。

*/
unsigned char SPI_SendData(unsigned char outdata)
{

unsigned char RecevieData=0,i;
               
for(i=0;i<8;i++)
{
SPI_SCKLOW;
if(outdata&0x80)
   {
   SPI_OUTHIGH;
    }
else
   {
  SPI_OUTLOW;
   }
outdata<<=1;
         
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();

SPI_SCKHIGH;

  RecevieData <<= 1;

if(SPI_IN)
   {
    RecevieData |= 1;
   }
         
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
  SPI_SCKLOW;
}

return RecevieData;

}

/*
函数名:  enabled_cs
功能:使能对应芯片的CS脚
参数:
cardno        卡号
用单片机不同引脚去控制不同芯片的CS脚,以便多个芯片关联使用。
*/
void enabled_cs(unsigned char cardno)
{
if(cardno==1)
{
SPI_CSLOW;
}
else if(cardno==2)
{
SPI2_CSLOW;
}



}

/*
函数名:  disabled_cs
功能:禁止对应芯片的CS脚
参数:
cardno        卡号
用单片机不同引脚去控制不同芯片的CS脚,以便多个芯片关联使用。
*/
void disabled_cs(unsigned char cardno)
{
        if(cardno==1)
{
SPI_CSHIGH;
}
else if(cardno==2)
{
SPI2_CSHIGH;
}

       
}




/*
函数名:  set_speed
功能:设置轴速度
参数:
cardno        卡号
axis        轴号(1-6)
acc     加速时间(ms)
dec     减速时间(ms)
startv     启动频率为:值*频率倍率(Hz)
speed      运行频率为:值*频率倍率(Hz)
range      频率倍率(1-100)

*/
unsigned char set_speed(unsigned char cardno ,unsigned char axis ,unsigned int acc  ,unsigned int dec  ,unsigned int startv ,unsigned int speed ,unsigned char range)
{
unsigned char OutByte[25];

OutByte[0] = 1;
OutByte[1] = axis;
OutByte[2] = acc >>8;
OutByte[3] = acc ;
OutByte[4] = dec >>8;
OutByte[5] = dec ;
OutByte[6] = startv >>8;
OutByte[7] = startv ;
OutByte[8] = speed >>8;
OutByte[9] = speed ;
OutByte[10] = range;

       
enabled_cs(cardno);
SPI_SendData(OutByte[0]);
SPI_SendData(OutByte[1]);
SPI_SendData(OutByte[2]);
SPI_SendData(OutByte[3]);
SPI_SendData(OutByte[4]);
SPI_SendData(OutByte[5]);
SPI_SendData(OutByte[6]);
SPI_SendData(OutByte[7]);
SPI_SendData(OutByte[8]);
SPI_SendData(OutByte[9]);
SPI_SendData(OutByte[10]);       
disabled_cs(cardno);               
       
       
}





/*
函数名: pmove
功能:单轴运行
参数:
cardno        卡号
axis                轴号(1-2)
pulse         输出的脉冲数 >0:正方向移动                 <0:负方向移动        范围(-268435455~+268435455)
mode      0:相对位移  1:绝对位移   2:连续位移

*/
unsigned char pmove(unsigned char cardno ,unsigned char axis,long pulse , unsigned char mode)
{
unsigned char OutByte[25];
OutByte[0] = 2        ;
OutByte[1] = axis;
OutByte[2] = pulse >>24;
OutByte[3] = pulse >>16;
OutByte[4] = pulse >>8;
OutByte[5] = pulse ;
OutByte[6] = mode ;
enabled_cs(cardno);
SPI_SendData(OutByte[0]);
SPI_SendData(OutByte[1]);
SPI_SendData(OutByte[2]);
SPI_SendData(OutByte[3]);
SPI_SendData(OutByte[4]);
SPI_SendData(OutByte[5]);
SPI_SendData(OutByte[6]);
SPI_SendData(0);       
disabled_cs(cardno);       
}


/*
函数名:        set_command_pos
功能: 设置轴逻辑位置

参数:
cardno        卡号
axis        轴号(1-2)
pulse         位置脉冲数,范围(-268435455~+268435455)

*/
unsigned char set_command_pos(unsigned char cardno ,unsigned char axis, long value )
{
unsigned char OutByte[25];

OutByte[0] = 0x12 ;
OutByte[1] = axis ;
OutByte[2] = value >>24;
OutByte[3] = value >>16;
OutByte[4] = value >>8;
OutByte[5] = value ;
       
enabled_cs(cardno);
SPI_SendData(OutByte[0]);
SPI_SendData(OutByte[1]);
SPI_SendData(OutByte[2]);
SPI_SendData(OutByte[3]);
SPI_SendData(OutByte[4]);
SPI_SendData(OutByte[5]);       
disabled_cs(cardno);               
               
       

}



/*
函数名: sudden_stop
功能: 轴停止
参数:
cardno        卡号
axis        停止的轴号(1-2)   1-2:1-2轴停  

*/
unsigned char sudden_stop(unsigned char cardno ,unsigned char axis)
{
unsigned char OutByte[25];

OutByte[0] = 0x17 ;
OutByte[1] = axis ;

enabled_cs(cardno);
SPI_SendData(OutByte[0]);
SPI_SendData(OutByte[1]);
disabled_cs(cardno);       
               
}

/*
函数名: get_command_pos
功能: 获取轴逻辑位置或状态。
本函数先发一条指令过去让芯片准备相应的数据,等待1MS后,再从芯片读取4个字节的相应数据。
参数:
cardno        卡号
axis         轴号   1,1轴  2,2轴   100,会返回两个轴的状态。0位为第一轴状态。1位为第二轴状态。0表示停止中,1表示运行中。
返回值:         位置脉冲数,范围(-268435455~+268435455)或者两个轴的状态
*/
long  get_command_pos( unsigned char cardno, unsigned char axis)
{       
unsigned char OutByte[25];
unsigned char inbuf[12];        
long tmp=0;
OutByte[0] = 0x06;
OutByte[1] = axis ;
enabled_cs(cardno);
SPI_SendData(OutByte[0]);
SPI_SendData(OutByte[1]);
disabled_cs(cardno);               

delay_nms(1);
       
enabled_cs(cardno);       
inbuf[0]=SPI_SendData(0);
inbuf[1]=SPI_SendData(0);
inbuf[2]=SPI_SendData(0);
inbuf[3]=SPI_SendData(0);
disabled_cs(cardno);       
delay_nms(1);       
       
        tmp= (long)inbuf[0]<<24;
tmp+= (long)inbuf[1]<<16;
tmp+= (long)inbuf[2]<<8;
tmp+= (long)inbuf[3];
return tmp;

        //return(((long)inbuf[0]<<24)+((long)inbuf[1]<<16)+((long)inbuf[2]<<8)+((long)inbuf[3]));
}



/*
函数名: set_special
功能:设置特别功能
参数:
cardno        卡号(1-128)芯片地址   
value  
       0xf1   停止时缓慢
       0xf2   停止时急速
       0xfa   重新启动
       0xfb    急停
*/
unsigned char set_special(unsigned char cardno,unsigned char value)
{
unsigned char OutByte[25];

OutByte[0] = 0xFA ;
OutByte[1] = value;
enabled_cs(cardno);
SPI_SendData(OutByte[0]);
SPI_SendData(OutByte[1]);
disabled_cs(cardno);               
       
}











void main(void)  
{
   initial();

   set_speed(1 ,1,1000,1000,10,200,100);          // 设1轴速度
   set_speed(1 ,2,1000,1000,10,200,100);          // 设2轴速度
  
   /*1轴2轴回原点*/
         pmove(1,1,-1000000,0);                  //         1轴多脉冲负方向运动
         pmove(1,2,-1000000,0);                  //         2轴多脉冲负方向运动                               
                   while(s1);                                 //检测1轴状态引脚电平,如变低表示已停,且在原点
                   while(s2);                               //检测2轴状态引脚电平,如变低表示已停,且在原点
                //while(get_command_pos(1, 100)) ;        //通过指令也能获取各轴状态 ,与S1,S2两个状态指示输入口功能相同。
        set_command_pos(1,1,0);                //           设1轴此时坐标为0
                set_command_pos(1,2,0);                //           设2轴此时坐标为0

   while(1)
         {
                  
         if((!b1)&&(!s1))//按键按下        ,并且1轴停止状态
           {
            
                pmove(1,1,32000,0);                  //         1轴正向运动 32000个脉冲
                          
             while(!b1);
           }
         
                         

            if((!b1)&&(inbuf[0]>0))//按键按下, 并且1轴在运动中
           {
                      
                  sudden_stop(1,1);                          //           1轴停止
             while(!b1);
           }
         }
       
}
回复

点赞 举报

高级模式
您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐 上一条 /7 下一条

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

推荐专区

技术干货集中营

专家问答

用户帮助┃咨询与建议┃版主议事

工程师杂谈

工程师创意

工程师职场

论坛电子赛事

社区活动专版

发烧友活动

-

嵌入式论坛

ARM技术论坛

Android论坛

Linux论坛

单片机/MCU论坛

FPGA|CPLD|ASIC论坛

DSP论坛

嵌入式系统论坛

-

电源技术论坛

电源技术论坛

无线充电技术

-

硬件设计论坛

PCB设计论坛

电路设计论坛

电子元器件论坛

控制|传感

总线技术|接口技术

-

测试测量论坛

LabVIEW论坛

Matlab论坛

测试测量技术专区

仪器仪表技术专区

-

EDA设计论坛

multisim论坛

PADS技术论坛

Protel|AD|DXP论坛

Allegro论坛

proteus论坛|仿真论坛

EasyEDA-中国人自已的EDA工具

Orcad论坛

-

综合技术与应用

电机控制

智能电网

光电及显示

参考设计中心

汽车电子技术论坛

医疗电子论坛

-

开源硬件

-

无线通信论坛

无线通信技术专区

天线|RF射频|微波|雷达技术

-

IC设计论坛

芯片测试与失效分析

Mixed Signal/SOC[数模混合芯片设计]

Analog/RF IC设计

设计与制造封装测试

-

厂商专区

TI论坛

TI Deyisupport社区

-

检测技术与质量

电磁兼容(EMC)设计与整改

安规知识论坛

检测与认证

-

消费电子论坛

手机技术论坛

平板电脑/mid论坛

音视/视频/机顶盒论坛

-

电子论坛综合区

聚丰众筹官方社区

新人报道区

聚丰供应链

-

论坛服务区

-

供求信息发布

供需广告

招聘┃求职发布区

电子展览展会专区