我研究的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自加
}
}