Grbl在51单片机上的验证 STC12C5A60S2

来源:互联网 发布:手机连接电脑软件 编辑:程序博客网 时间:2024/06/07 01:53

纵观网络上各位大神在数控方面的神作,却没有什么人做一些分享,那么,从我开始好了,这里只做了STC12C5A60S2这种51单片机成功对接Grbl上位机软件以及将接受到的G代码转换为float型坐标,验证这么一个功能,为以后深入编写电机控制,做一个基础铺垫。

这里所完成的功能很简单,所以代码也不难,主要是了解Grbl通信协议,以及G代码解析两个点,下面,我带大家来解读这两个点。

1、了解Grbl

在百度文库上,我上传了基本的协议,可以点击查看

http://wenku.baidu.com/link?url=Mu-JK2FGfv9pStTQqdVxxTF4I7PfQG8PdMl-zhS7tkEWjyNFvraf9uLpgAh7CS28bGrck3vxgHp5r262d6N9WGxBj9CvipySgCYm3v1nhje


这里我就不赘述了。

但是有一点,通信就是,你问我一句,我回你一句,所以是上位机先问下单片机:你是不是Grbl设备啊?,然后单片机得回答说:是啊,我是Grbl xx,然后上位机收到回复后才开始建立通信,这一点,在下面程序里的setup();完成

通信完全建立好后,就进入loop();函数里面,这时就等待上位机发送G代码了,上位机每次发送一行代码,单片机接受后,处理完成后,回复ok,上位机才会发送下一句。

基本就是这些了,其实很简单是不是。


2、将通信协议写入程序代码中,并完成G代码解析:


首先你应该有一点编程基础,然后应该就不难了。


其中动用的主要子函数是

Echo_Position(float x,float y, float z);
用来反馈当前坐标的

Analysis_Gcode(unsigned char *p_buffer);
用来解析G代码的


以下是函数的主体。

#include"STC12C5A60S2.h"#include"UART.h"#include"M_string.h"#include"stdio.h"enum axis{X_AXIS=0,Y_AXIS,Z_AXIS,E_AXIS};xdata float Machine_Coordinates[4]={0.0,0.0,0.0,0.0};xdata float Work_Coordinates[4]={0.0,0.0,0.0,0.0};const unsigned char code ECHO_GRBL[]="Grbl";const unsigned char code ECHO_POS[]="<Idle,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000>";const unsigned char code ECHO_ERROR[]="error";#define R_POS11const unsigned char code ECHO_OK[]="ok";void Echo_Position(float x,float y, float z){#define CLR_BUF() do{\for(i=0;i<12;i++)\{\Buffer[i]=0x00;\}\}while(0)unsigned char i;unsigned char Buffer[12];//1+5+1+3+1+1Clear_Uart_sendBuffer();for(sendBuffer_Index=0;sendBuffer_Index<R_POS;sendBuffer_Index++){Uart_sendBuffer[sendBuffer_Index]=ECHO_POS[sendBuffer_Index];}_ftos_5_3(x,Buffer);Buffer[_strlen_(Buffer)]=',';//将浮点数x转换成5.3位有符号字符串,再尾部添加逗号_strcat_(Uart_sendBuffer,Buffer);CLR_BUF();//每次用完之后,都要清空一下,就像马桶一样_ftos_5_3(y,Buffer);Buffer[_strlen_(Buffer)]=',';_strcat_(Uart_sendBuffer,Buffer);CLR_BUF();_ftos_5_3(z,Buffer);Buffer[_strlen_(Buffer)]=',';_strcat_(Uart_sendBuffer,Buffer);CLR_BUF();sendBuffer_Index=_strlen_(Uart_sendBuffer);for(i=29;ECHO_POS[i]!='0';sendBuffer_Index++,i++){Uart_sendBuffer[sendBuffer_Index]=ECHO_POS[i];}_ftos_5_3(x,Buffer);Buffer[_strlen_(Buffer)]=',';_strcat_(Uart_sendBuffer,Buffer);CLR_BUF();_ftos_5_3(y,Buffer);Buffer[_strlen_(Buffer)]=',';_strcat_(Uart_sendBuffer,Buffer);CLR_BUF();_ftos_5_3(z,Buffer);_strcat_(Uart_sendBuffer,Buffer);CLR_BUF();sendBuffer_Index=_strlen_(Uart_sendBuffer);Uart_sendBuffer[sendBuffer_Index]='>';Uart_sendBuffer[sendBuffer_Index+1]=0x00;Serial_println(Uart_sendBuffer);}void setup(){bit can_out=0;bit Index=1;unsigned char *pbuffer=Uart_recvBuffer;unsigned long i=0;Serial_begin(115200);while((_strchr_(pbuffer,0x18))==0 && recvBuffer_Index<128);Serial_println(ECHO_GRBL);Clear_Uart_recvBuffer();do{if(_strchr_(pbuffer,0x0D)){if(_strchr_(pbuffer,'?')){Echo_Position(Machine_Coordinates[X_AXIS],Machine_Coordinates[Y_AXIS],Machine_Coordinates[Z_AXIS]);Serial_println(ECHO_OK);}else if(_strstr_(pbuffer,"$13")!=0xFF){Serial_println(ECHO_OK);}else if(_strchr_(pbuffer,'$')){Serial_println("[G0 G54 G17 G21 G90 G94 M0 M5 M9 T0 F250.000]");Serial_println(ECHO_OK);Clear_Uart_recvBuffer();}else if(_strchr_(pbuffer,'G')){can_out=1;Serial_println(ECHO_OK);}Clear_Uart_recvBuffer();}}while(!can_out);Clear_Uart_recvBuffer();}void Analysis_Gcode(unsigned char *p_buffer){if(_strchr_(p_buffer,'?')){recvBuffer_Index=0;Echo_Position(Machine_Coordinates[X_AXIS],Machine_Coordinates[Y_AXIS],Machine_Coordinates[Z_AXIS]);//Clear_Uart_recvBuffer();Serial_println(ECHO_OK);}else if(_strchr_(p_buffer,'G') || _strchr_(p_buffer,'M')){switch(*p_buffer++){case 'G':switch(*p_buffer){case '0'://和G1不区别case '1':if((p_buffer=_strichr_(p_buffer,'x'))){p_buffer++;Machine_Coordinates[X_AXIS]=_strtof_(p_buffer);}if((p_buffer=_strichr_(p_buffer,'y'))){p_buffer++;Machine_Coordinates[Y_AXIS]=_strtof_(p_buffer);}if((p_buffer=_strichr_(p_buffer,'z'))){p_buffer++;Machine_Coordinates[Z_AXIS]=_strtof_(p_buffer);}if((p_buffer=_strichr_(p_buffer,'e'))){p_buffer++;Machine_Coordinates[E_AXIS]=_strtof_(p_buffer);}break;//G0,G1case '2':break;}break;//case 'M':switch(*p_buffer++)break;}recvBuffer_Index=0;//Clear_Uart_recvBuffer();Serial_println(ECHO_OK);}else{recvBuffer_Index=0;//Clear_Uart_recvBuffer();Serial_println(ECHO_ERROR);}}sbit LED = P1^0;unsigned long i=0;void loop(void){//for(i=0;i<500;i++);//if(_strchr_(Uart_recvBuffer,0x0D))if(Uart_recvBuffer[recvBuffer_Index-1]==0x0D){Uart_recvBuffer[recvBuffer_Index]=0x00;Analysis_Gcode(Uart_recvBuffer);}//LED = !LED;}void main(void){setup();while(1){loop();}}



然后涉及到串口的设置,这里使用的是方式3,注意,1验证(我忘记调整这个点了,所以导致Grbl上位机对回复的位置无法处理,因为乱码嘛,坐标显示就一直为0)


#include"STC12C5A60S2.h"#include"intrins.h"#include"UART.H"xdata unsigned char Uart_sendBuffer[128];xdata unsigned char Uart_recvBuffer[128];xdata unsigned char sendBuffer_Index=0;xdata unsigned char recvBuffer_Index=0;bit Uart_busy=0;#define FOSC 11095200//默认11.0592MHz晶振//TH1=256-(FOSC/32/baud_rate);#define UART_PARYTY3#message "Uart mode 3"#message "Use this Uart.h will occupy Timer1"void Clear_Uart_sendBuffer(){sendBuffer_Index=0;while(sendBuffer_Index<128){Uart_sendBuffer[sendBuffer_Index]=0;sendBuffer_Index++;}sendBuffer_Index=0;}void Clear_Uart_recvBuffer(){recvBuffer_Index=0;while(recvBuffer_Index<128){Uart_recvBuffer[recvBuffer_Index]=0;recvBuffer_Index++;}recvBuffer_Index=0;}void Serial_begin(unsigned long baud_rate){Clear_Uart_sendBuffer();Clear_Uart_recvBuffer();#ifdef UART_PARYTY3AUXR|=0x40;SCON=0xDA;//9bit 奇校验TMOD=0x20;//T1 8位自动重装模式TH1=0xFF-(FOSC/32/baud_rate)+1;//初值TL1=TH1;TR1=1;ES=1;REN=1;TI=0;RI=0;EA=1;#else#endif}void Uart_SendByte(unsigned char chr){TI=0;Uart_busy=1;SBUF=chr;while(Uart_busy);}void Serial_println(unsigned char *str){unsigned char i;while(*str && i<128){Uart_SendByte(*str);str++;i++;}Uart_SendByte(0x0D);Uart_SendByte(0x0A);}void Uart_Recv(void) interrupt 4 using 0{//ES=0;//关闭串口中断if(RI && recvBuffer_Index<128)//如果是接收引发中断,且接收缓冲没有占满{Uart_recvBuffer[recvBuffer_Index]=SBUF;//将SBUF数据放入接收缓冲recvBuffer_Index++;}RI=0;//清除接收中断标志TI=0;Uart_busy=0;//ES=1;//打开串口中断}
Uart.c的头文件,用来引用Uart.c里的函数

#ifndef UART_h#define UART_hextern bit Uart_busy;extern xdata unsigned char Uart_sendBuffer[128];extern xdata unsigned char Uart_recvBuffer[128];extern xdata unsigned char sendBuffer_Index;extern xdata unsigned char recvBuffer_Index;#include"STC12C5A60S2.h"void Serial_begin(unsigned long boundrate);#define Serial_end()do{REN = 0;}void Clear_Uart_sendBuffer();void Clear_Uart_recvBuffer();void Uart_SendByte(unsigned char chr);void Serial_print(unsigned char *str);void Serial_println(unsigned char *str);#endif

还有两个文件,M_string.h,M_string.lib,都不能少,这是两个处理字符串的函数。

其中string.lib是我自己做的库,主要是为了不出现UNCALLED SEGMENT这样的经典WARNING,点击下载(http://pan.baidu.com/s/1i43PSSt),其中包含库,头文件,以及函数原型,有些可能有错误,希望大家发现后能指出,这样,也不枉我共享这些东西。

最后再说一点,也是很重要的一点,波特率115200,不是原先默认的9600,记得改。

2 0