Marlin固件解析G代码部分分析
解析指令函数的主要作用就是提取命令缓冲区中命令的信息,完成解码工作,并将解码后的信息传递给其他程序块来执行。
解析指令具体的程序是通过的switch…case…结构实现的。通过读取缓冲区的命令置于switch case结构中解析,并将解码信息赋予相应的职能函数。
下面这三个对字符串操作进一步封装的函数在G指令解析中起着至关重要的作用。
/* 将strchr_pointer指针后的字符串中的数字转化为双精度数值 */
float code_value(void)
{
return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL));
}
/* 将strchr_pointer指针后的字符串中的数字按十进制数转化为数值 */
long code_value_long(void)
{
return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10));
}
/* 如果字符“code”被找到,返回值为true */
bool code_seen(char code)
{
strchr_pointer = strchr(cmdbuffer[bufindr], code);
return (strchr_pointer != NULL); //Return True if a character was found
}
process_commands()函数原本的代码量是上千行的,这里我为了说明问题只保留了代码框架的结构。仔细看下面这个代码结构便会发现他的巧妙所在。
/* 解析G代码和M代码 */
void process_commands(void)
{
unsigned long codenum; //throw away variable
char *starpos = NULL;
int8_t i;
if(code_seen('G')) //读取到了字符G
{
switch((int)code_value()) //读取G后面的数字
{
```
case 0: // G0 -> G1
case 1: // G1
if(Stopped == false) {
get_coordinates(); // For X Y Z E F
prepare_move();
return;
}
case 2: // G2 - CW ARC
if(Stopped == false) {
get_arc_coordinates();
prepare_arc_move(true);
return;
}
case 3: // G3 - CCW ARC
if(Stopped == false) {
get_arc_coordinates();
prepare_arc_move(false);
return;
}
case 4: // G4 dwell
codenum = 0;
if(code_seen('P')) codenum = code_value(); //毫秒等待
if(code_seen('S')) codenum = code_value() * 1000; //秒等待
st_synchronize(); //synchronize使……合拍,同步
codenum += millis(); //当开始等待时保持轨迹
previous_millis_cmd = millis(); //记录历史值
while(millis() < codenum )
{
manage_heater();
manage_inactivity();
}
break;
/*......*/ //略去了该部分程序
}
```
}
else if(code_seen('M'))
{
switch( (int)code_value() )
{
/*......*/ //略去了该部分程序
}
}
else if(code_seen('T'))
{
/*......*/ //略去了该部分程序
}
else
{
SERIAL_ECHO_START;
printf(MSG_UNKNOWN_COMMAND);
printf("%s",cmdbuffer[bufindr]);
printf("\"");
}
ClearToSend();
}
上面保留了一些case部分,仔细看就会发现它像极了数控系统中的G1、G2、G3、G4,这便是其中的巧妙所在。
巧妙的利用了switch case结构来实现庞大的功能体系,同时也为新功能的增添提供了巨大的便利。