我研究的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 commandreturn;}cmdbuffer[bufindw][serial_count] = 0; //terminate stringif(!comment_mode){comment_mode = false; //for new commandfromsd[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 SDSUPPORTif(card.saving)break;#endif //SDSUPPORTprintf(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 //sanseif(!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 commandreturn; //if empty line}cmdbuffer[bufindw][serial_count] = 0; //terminate string
// if(!comment_mode){fromsd[bufindw] = true;//sansebuflen += 1;bufindw = (bufindw + 1)%BUFSIZE;
// }comment_mode = false; //for new commandserial_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=128int 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 commandreturn;}cmdbuffer[bufindw][serial_count] = 0; //terminate stringif(!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 SDSUPPORTif(card.saving)break;#endif //SDSUPPORTprintf(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自加}}