Marlin关于如何接收Gcode指令的详解

我研究的Marlin是1.0版本的.想用在的地方是stm32

Marlin关于接收Gcode命令最主要的函数就是: get_command()

get_command()函数说实话对于我这样的学生来说程度还是挺复杂的.
为了节省大家理清代码和阅读文章的时间, 我全文用字力求精简, 别人已经写了的知识我就不会写

先上函数全文:

void get_command(void)
{ int16_t n;
  char time[30];
  unsigned long t;
  int hours, minutes;
  while( MYSERIAL_available() > 0  && buflen < BUFSIZE)
  {	//	LCD_ShowString(5,5,240,320,12, ".1.");	
    serial_char = MYSERIAL_read();
//		printf(" serial_char: %c\n\r",serial_char);
    if(serial_char == '\n' ||serial_char == '\r' ||(serial_char == ':' && comment_mode == false) ||serial_count >= (MAX_CMD_SIZE - 1) )//sanse 冒号
    {
      if(!serial_count)  //if empty line
	    {
        comment_mode = false; //for new command
        return;
      }
      cmdbuffer[bufindw][serial_count] = 0; //terminate string
      if(!comment_mode)
	    {
        comment_mode = false; //for new command
        fromsd[bufindw] = false;
        if(strchr(cmdbuffer[bufindw], 'N') != NULL)	                                                                    
        {
          strchr_pointer = strchr(cmdbuffer[bufindw], 'N');
          gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10));
          if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], PSTR("M110")) == NULL) )  
		      {                                                                          
            SERIAL_ERROR_START;
            printf(MSG_ERR_LINE_NO);
            printf("%ld",gcode_LastN);
            //Serial.println(gcode_N);
            FlushSerialRequestResend();
            serial_count = 0;
            return;
          }

          if(strchr(cmdbuffer[bufindw], '*') != NULL)
          {
            u8 checksum = 0;
            u8 count = 0;
            while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++];
            strchr_pointer = strchr(cmdbuffer[bufindw], '*');
                                                        
            if( (u8)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum)
							{                                                                 
									SERIAL_ERROR_START;
									printf(MSG_ERR_CHECKSUM_MISMATCH);
									printf(" checksum: %d\n\r",checksum);
									count = 0;
								  printf(" '");
									while(cmdbuffer[bufindw][count] != '*')
									{
										printf("%c",cmdbuffer[bufindw][count++]);
									}
									printf(" '\n\r ");
									checksum = 0;
									count = 0;
									while(cmdbuffer[bufindw][count] != '*')
									{ 
										printf("cmdbuffer:%d;",cmdbuffer[bufindw][count]);
										checksum = checksum^cmdbuffer[bufindw][count++];
									  printf(" checksum:%d \n\r",checksum);
									}
									///	printf("\n\r ");
						
									printf("%ld",gcode_LastN);
									FlushSerialRequestResend();
									serial_count = 0;
									return;
            }
            //if no errors, continue parsing
          }
          else
          {
            SERIAL_ERROR_START;
            printf(MSG_ERR_NO_CHECKSUM);
            printf("%ld",gcode_LastN);
            FlushSerialRequestResend();
            serial_count = 0;
            return;
          }

          gcode_LastN = gcode_N;
          //if no errors, continue parsing
        }
        else  // if we don't receive 'N' but still see '*'
        {
          if((strchr(cmdbuffer[bufindw], '*') != NULL))                                                            
          {
            SERIAL_ERROR_START;
            printf(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
            printf("%ld",gcode_LastN);
            serial_count = 0;
            return;
          }
        }
        if((strchr(cmdbuffer[bufindw], 'G') != NULL))                                                                
		    {
          strchr_pointer = strchr(cmdbuffer[bufindw], 'G');
          switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL))))
						{
							case 0:
							case 1:
							case 2:
							case 3:
								if(Stopped == false) { // If printer is stopped by an error the G[0-3] codes are ignored.
							#ifdef SDSUPPORT
									if(card.saving)
										break;
							#endif //SDSUPPORT
					
									printf(MSG_OK);
									printf("\n");
								}
								else {
									printf(MSG_ERR_STOPPED);
								 // LCD_MESSAGEPGM(MSG_STOPPED);
								}
								break;
							default:
								break;
             }
        }
        bufindw = (bufindw + 1)%BUFSIZE;
        buflen += 1;//sanse
      }
      serial_count = 0; //clear buffer
    }
    else
    {
      if(serial_char == ';') comment_mode = true;
      if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
    }
  }

  #ifdef SDSUPPORT   //sanse
  if(!card.sdprinting || serial_count!=0)
		{ 
 //	LCD_ShowString(20,5,240,320,12, ".2.");
    return;
   }
  while( !card_eof()  && buflen < BUFSIZE) 
  {	//LCD_ShowString(50,5,240,320,12, ".3.");
    n=card_get();
    serial_char = (BYTE)n;
    if(serial_char == '\n' ||
       serial_char == '\r' ||
       (serial_char == ':' && comment_mode == false) ||
       serial_count >= (MAX_CMD_SIZE - 1)||
			 n==-1)
    { 
      if(card_eof())//sanse
			{
        printf(MSG_FILE_PRINTED);
	    	printf("\n");
        stoptime=millis();
        t=(stoptime-starttime)/1000;
        minutes=(t/60)%60;
        hours=t/60/60;
        sprintf(time, PSTR("%i hours %i minutes"),hours, minutes);
        SERIAL_ECHO_START;
        printf("%s",time);
     //   lcd_setstatus(time);
        card_printingHasFinished();
       // card_checkautostart(true);

      }
      if(!serial_count)
      {
        comment_mode = false; //for new command
        return; //if empty line
      }
      cmdbuffer[bufindw][serial_count] = 0; //terminate string
//      if(!comment_mode){
        fromsd[bufindw] = true;//sanse
        buflen += 1;
        bufindw = (bufindw + 1)%BUFSIZE;
//      }
      comment_mode = false; //for new command
      serial_count = 0; //clear buffer
    }
    else
    {
      if(serial_char == ';') comment_mode = true;
      if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
    }
  }
  #endif //SDSUPPORT

}


get_command()牵涉到的主要变量为: serial_char, cmdbuffer, bufindw, serial_count, comment_mode

static char serial_char: 相当于串口数据的中转站, 依靠MYSERIAL_read()读取 从串口中断中得到的rx_buffer 来获取命令数据

static char cmdbuffer[8] [128]:存储命令的功能, 从serial_char获取命令数据

static int bufindw: 全名buffer_index_write, 指示作用, 作为cmdbuffer的下标, 在代码中会 +1

static int serial_count: 指示作用, 作为cmdbuffer的下标, 在代码中会自+

static bool comment_mode = false: 判断模式(判断为动词), 为false就执行get_command函数, 为true就结束get_command()

static int buflen:计算缓冲区字节数量的功能, 在代码中会+1

再讲个结构体, 下面有用

typedef struct ring_buffer
{
  unsigned char buffer[RX_BUFFER_SIZE]; //RX_BUFFER_SIZE=128
  int head;
  int tail;
}ring_buffer;
extern  ring_buffer rx_buffer;	

ring_buffer rx_buffer  =  { { 0 }, 0, 0 };

我们例如要将" G1 X1000 Y1000 Z250 "录入command_buffer中, 他是这样变的:

" G1 X1000 Y1000 Z250 "先由串口进入rx_buffer, rx_buffer的结构体中的第一位unsigned char buffer[RX_BUFFER_SIZE]中,结构体的第二,三位起下标作用.

再由get_command()函数使得: cmdbuffer[0]为G1 , cmdbuffer[1]为X1000, 以此类推, 以Z250为例, 那么
cmdbuffer[3] [2]就为5了

代码结构一张思维导图即可理清 (如有纰漏, 还望不吝赐教, 在评论区提出改正):
我只画了关于串口的读取Gcode的那一段, 如果想研究从SD卡读Gcode, 道理是一样的, 不做过多解释

请添加图片描述
温馨提示: 别看左边那一列有那么多, 其实执行最多的是右面一列:
请添加图片描述

我再送上我做过注释的, 根据思维导图截取了部分的代码:


  while( MYSERIAL_available() > 0  && buflen < BUFSIZE)
  {	//	LCD_ShowString(5,5,240,320,12, ".1.");	
    serial_char = MYSERIAL_read();
//		printf(" serial_char: %c\n\r",serial_char);
    if(serial_char == '\n' ||serial_char == '\r' ||(serial_char == ':' && comment_mode == false) ||serial_count >= (MAX_CMD_SIZE - 1) )//sanse 冒号
    {
      if(!serial_count)  //if empty line
	    {
        comment_mode = false; //for new command
        return;
		}
      cmdbuffer[bufindw][serial_count] = 0; //terminate string
      if(!comment_mode)
	    {
        comment_mode = false; //for new command 	确保处于读模式, 避免执行命令模式
        fromsd[bufindw] = false;	// 避免从SD卡读取
        if(strchr(cmdbuffer[bufindw], 'N') != NULL)	                                                                    
        {
          strchr_pointer = strchr(cmdbuffer[bufindw], 'N');		
          // strchr函数功能为在一个串中查找给定字符的第一个匹配之处	
          gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10));	
          // strtol函数会将参数nptr字符串根据参数base来转换成长整型数,参数类型范围从2至36。
          if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], PSTR("M110")) == NULL) ) 
           // strstr(str1,str2) 返回字符串中首次出现子串的地址	pstr表示一个指向字符串的指针变量
		  {                                                                          
            SERIAL_ERROR_START;   // 报错
            printf(MSG_ERR_LINE_NO);
            printf("%ld",gcode_LastN);	// %ld: long int
            //Serial.println(gcode_N);
            FlushSerialRequestResend();
            serial_count = 0;
            return;
          }

          if(strchr(cmdbuffer[bufindw], '*') != NULL)
          {
            u8 checksum = 0;
            u8 count = 0;
            while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++];	
            // 计算从字符串起始位到'*'的checksum, cheaksum用^运算是为了尽可能地大
            strchr_pointer = strchr(cmdbuffer[bufindw], '*');
                                                        
            if( (u8)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum)	
			// strtod:将字符串转换成浮点数	一般来说checksum为0, "strchr_pointer - cmdbuffer[bufindw] + 1"为1, 不等于说明内存出问题了 呼应 ↑
							{                                                                 
									SERIAL_ERROR_START;
									printf(MSG_ERR_CHECKSUM_MISMATCH);
									printf(" checksum: %d\n\r",checksum);
									count = 0;
								  printf(" '");
									while(cmdbuffer[bufindw][count] != '*')
									{
										printf("%c",cmdbuffer[bufindw][count++]);
									}
									printf(" '\n\r ");
									checksum = 0;
									count = 0;
									while(cmdbuffer[bufindw][count] != '*')
									{ 
										printf("cmdbuffer:%d;",cmdbuffer[bufindw][count]);
										checksum = checksum^cmdbuffer[bufindw][count++];
									  printf(" checksum:%d \n\r",checksum);
									}
									///	printf("\n\r ");
						
									printf("%ld",gcode_LastN);
									FlushSerialRequestResend();
									serial_count = 0;
									return;
							}
            //if no errors, continue parsing
          }
          else
          {
            SERIAL_ERROR_START;
            printf(MSG_ERR_NO_CHECKSUM);
            printf("%ld",gcode_LastN);
            FlushSerialRequestResend();
            serial_count = 0;
            return;
          }

          gcode_LastN = gcode_N;
          //if no errors, continue parsing
			}
        else  // if we don't receive 'N' but still see '*'
        {
          if((strchr(cmdbuffer[bufindw], '*') != NULL))                                                            
          {
            SERIAL_ERROR_START;
            printf(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
            printf("%ld",gcode_LastN);
            serial_count = 0;
            return;
          }
        }
        if((strchr(cmdbuffer[bufindw], 'G') != NULL))                                                                
		{
          strchr_pointer = strchr(cmdbuffer[bufindw], 'G');
          switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL))))
						{
							case 0:
							case 1:
							case 2:
							case 3:
								if(Stopped == false) { // If printer is stopped by an error the G[0-3] codes are ignored.
							#ifdef SDSUPPORT
									if(card.saving)
										break;
							#endif //SDSUPPORT
					
									printf(MSG_OK);
									printf("\n");
								}
								else {
									printf(MSG_ERR_STOPPED);
								 // LCD_MESSAGEPGM(MSG_STOPPED);
								}
								break;
							default:
								break;
             }
        }
        bufindw = (bufindw + 1)%BUFSIZE;
        buflen += 1;//sanse
      }
      serial_count = 0; //clear buffer
    }
    else
    {
      if(serial_char == ';') comment_mode = true;
      if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; //注意serial_count自加
    }
  }
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Marlin是一款开源的3D打印机固件,支持多种硬件平台和多种3D打印机类型。它具有高度的可定制性和易用性,是自制3D打印机和开源3D打印机的最佳选择之一。下面我们来详解一下Marlin固件的中文特性与使用方法。 Marlin固件中文特性 1. 支持中文界面。Marlin固件提供了中文界面,可以方便地进行参数设置和操作。 2. 支持中文字符。Marlin固件可以通过配置文件开启支持中文字符的功能,打印机便可以打印出中文字符。 3. 支持中文提示。Marlin固件提供了丰富的中文提示信息,方便用户进行操作和调试。 Marlin固件中文使用方法 1. 下载Marlin固件代码库。用户可以通过GitHub等开源代码库下载Marlin固件的代码。 2. 编译Marlin固件。用户可以使用Arduino IDE等开发工具编译Marlin固件,得到相关的固件文件。 3. 配置Marlin固件。用户需要对Marlin固件进行相关的配置,包括电机步进角度、传感器类型等参数。 4. 刷入Marlin固件。用户可以通过USB连接将Marlin固件刷入3D打印机的控制器。 5. 测试Marlin固件。用户可以测试Marlin固件的功能和特性,如打印质量、运动控制等。 总结 Marlin固件是一款功能强大、易用性高的开源3D打印机固件。它提供了丰富的中文特性和使用方法,方便用户进行配置和操作。Marlin固件的中文支持也为国内用户在3D打印领域的研究和实践提供了便利。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡萝卜要削皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值