Marlin固件具有很强大的功能,支持非常多G代码命令(参考:http://reprap.org/wiki/Gcode )。但很多朋友还是有特殊定制的需求,在这里简单写一个例子来说明一下如何添加或修改自己定制的G代码命令。
所有的G代码列表在Marlin_main.cpp文件中。
所有的相关代码都在process_commands这个函数里面。G开头的(G1、G2、G3等)及M开头的(M0、M1等)是分开的,所以一定要注意区分。
我这里以一个简单例子做说明,执行M03的时候,接通一个继电器,执行M05的时候,关闭这个继电器。
首先因为是M命令,所以应该将代码添加在M代码部分。为了方便查找,按照原顺序进行添加会更好,比如M3应该放在M2和M4之间。
添加代码是一定要注意#if、#endif这样的宏命令

1. #ifdef ULTIPANEL
2. case 0: // M0 - Unconditional stop - Wait for user button press on LCD
   3. case 1: // M1 - Conditional stop - Wait for user button press on LCD
   4. {
   5. LCD_MESSAGEPGM(MSG_USERWAIT);
   6. codenum = 0;
   7. if(code_seen('P')) codenum = code_value(); // milliseconds to wait
   8. if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
   9.
   10. st_synchronize();
   11. previous_millis_cmd = millis();
   12. if (codenum > 0){
   13. codenum += millis();  // keep track of when we started waiting
   14. while(millis()  < codenum && !lcd_clicked()){
   15. manage_heater();
   16. manage_inactivity();
   17. lcd_update();
   18. }
   19. }else{
   20. while(!lcd_clicked()){
   21. manage_heater();
   22. manage_inactivity();
   23. lcd_update();
   24. }
   25. }
   26. LCD_MESSAGEPGM(MSG_RESUMING);
   27. }
   28. break;
   29. #endif
   30.
   31. //需要添加的代码应该放在这个位置
   32. case 3:
   33. digitalWrite(Pin,High);//Pin指你打算用于控制继电器的接口(arduino Pin编号)。如果跟其它管脚冲突,可能需要配置Pins.h文件中相关管脚为-1.
   34. break;
   35. case 5:
   36. digitalWrite(Pin,LOW);
   37. break;
   38.
   39. //定制添加代码结束
   40.
   41. case 17:
   42. LCD_MESSAGEPGM(MSG_NO_MOVE);
  1. 添加代码后,就可以通过发送M3和M5来分别拉高(5V)和拉低(0V)相应的IO口,从而实现对继电器的控制了。
    修改代码的话跟添加差不多,只是找到相应代码段进行修改就好了。

(转)基于marlin手指的SCARA机械臂

https://www.dazhuanlan.com/maymask/topics/1229030

我上了thingiverse,https: //www.thingiverse.com/thing:2339480[](https://www.thingiverse.com/thing:2339480)

参考

平行平行臂结构morgan (上图)
臂[](http://www.thingiverse.com/thing:1241491)http://www.thingiverse.com/thing:1241491(下图)
Delta3D的打印机代码解读
马林精读
DARM

定义关节坐标

[](http://wx4.sinaimg.cn/mw690/e8d4eb99gy1fq9ozfiph5j215v0uvadv.jpg)

[

](http://wx4.sinaimg.cn/mw690/e8d4eb99gy1fq9ozfiph5j215v0uvadv.jpg)

定义x轴(主臂)的关节坐标主臂与x负半轴轴夹角的角度(在上为正,在为负),y轴(副臂)的关节坐标为副臂和主臂额外线夹角的角度。(上下:跳跃1的关节坐标[X41,Y42],跳跃2的关节坐标为[X0,Y0],跳跃3的关节坐标为[X-55,Y152])。X轴最小坐标值时触发限位,Y轴最大坐标值时触发限位。

正解(关节坐标转化成绝对坐标)

[](http://wx2.sinaimg.cn/mw690/e8d4eb99gy1fq9ozh14rrj20x00segpz.jpg)

[

](http://wx2.sinaimg.cn/mw690/e8d4eb99gy1fq9ozh14rrj20x00segpz.jpg)

void (float f_scara[3])
{


//图中绿色坐标为真正的坐标

  float x_sin, x_cos, y_sin, y_cos;//如图
//f_scara[X_AXIS]为X轴关节坐标,
//SCARA_RAD2DEG为弧度转角度转化因子等于pi/180
//(关节坐标是角度制,三角函数是弧度制,需要转化)
//Linkage_1、Linkage_2分别为主、副臂长度
//delta[X_AXIS]为绝对坐标的X轴值
//SCARA_offset[X_AXIS] 、SCARA_offset[Y_AXIS] 是假定
//的坐标原点关节于真实坐标的坐标(真实坐标原点的偏移量)

//简单的三角函数关系就能得出
    x_sin = sin(f_scara[X_AXIS]/SCARA_RAD2DEG) * Linkage_1;  
    x_cos = cos(f_scara[X_AXIS]/SCARA_RAD2DEG) * Linkage_1;
    y_sin = sin(f_scara[X_AXIS]/SCARA_RAD2DEG + f_scara[Y_AXIS]/SCARA_RAD2DEG) * Linkage_2;
    y_cos = cos(f_scara[X_AXIS]/SCARA_RAD2DEG + f_scara[Y_AXIS]/SCARA_RAD2DEG) * Linkage_2;


    delta[X_AXIS] = -x_cos - y_cos + SCARA_offset[X_AXIS] ;
//因为关节坐标从x轴负半轴开始,实际为负值,所以取反。
//加上偏移量变换成真正的坐标。
    delta[Y_AXIS] = x_sin + y_sin + SCARA_offset[Y_AXIS] ;  

} 

| | |
| - | - |

反解(绝对坐标转化为关节坐标)

[](http://wx3.sinaimg.cn/mw690/e8d4eb99gy1fq9t5a23grj20wi0ldmzc.jpg)

[

](http://wx3.sinaimg.cn/mw690/e8d4eb99gy1fq9t5a23grj20wi0ldmzc.jpg)

void calculate_delta(float cartesian[3]){

  float SCARA_pos[2];
  static float SCARA_C2, SCARA_S2, SCARA_K1, SCARA_K2, SCARA_theta, SCARA_psi; 

  //把实际坐标(偏移后的坐标)转化成假定的坐标,X轴取反。
  SCARA_pos[X_AXIS] = -cartesian[X_AXIS] * axis_scaling[X_AXIS] + SCARA_offset[X_AXIS] ;  
  SCARA_pos[Y_AXIS] = cartesian[Y_AXIS] * axis_scaling[Y_AXIS] - SCARA_offset[Y_AXIS] ;  


  
    SCARA_C2 = ( ( sq(SCARA_pos[X_AXIS]) + sq(SCARA_pos[Y_AXIS]) ) / (2 * (float)L1_2) ) - 1;
  #else
    SCARA_C2 =   ( sq(SCARA_pos[X_AXIS]) + sq(SCARA_pos[Y_AXIS]) - (float)L1_2 - (float)L2_2 ) / 45000; 
  #endif//三角形ABC中,用余弦定理计算角A的值,角A和Y轴电机的角度(关节坐标)互补(余弦值取反)可以得到Y轴角度的余弦值


  SCARA_S2 = sqrt( 1 - sq(SCARA_C2) );//计算Y轴角度的正弦值
  SCARA_K1 = Linkage_1 + Linkage_2 * SCARA_C2;//直角三角形OBC中,计算OC的长
  SCARA_K2 = Linkage_2 * SCARA_S2;//计算OB的长

  SCARA_theta = ( atan2(SCARA_pos[X_AXIS],SCARA_pos[Y_AXIS])-atan2(SCARA_K1, SCARA_K2) )*-1
 //计算X轴的关节坐标(弧度制),图中角1-角2,即(90-角3)-(90-角OBC),即(角3-角OBC)*-1
  SCARA_psi   =   atan2(SCARA_S2,SCARA_C2);//计算Y轴的关节坐标

  delta[X_AXIS] = SCARA_theta * SCARA_RAD2DEG; //弧度转角度   
  delta[Y_AXIS] = SCARA_psi * SCARA_RAD2DEG;   
  delta[Z_AXIS] = cartesian[Z_AXIS];

| | |
| - | - |

注:本指针是基于http://www.thingiverse.com/thing:1241491 手指臂修改的。

第四轴

[](http://wx3.sinaimg.cn/mw690/e8d4eb99gy1fq9ozhkhpmj20zj0kvmxg.jpg)

[

](http://wx3.sinaimg.cn/mw690/e8d4eb99gy1fq9ozhkhpmj20zj0kvmxg.jpg)

第四轴为旋转轴,规定两指的连线(下定义为手爪的X轴)与坐标轴系X轴的夹角(0-180)为第四轴的绝对坐标,在A_AXIS之后,关节坐标(即舵机的角度)为手爪Y轴(垂直于手爪X轴)与主臂的夹角,与A_AXIS_R简单几何关系得:
A_AXIS_R=270-delta[X_AXIS]-delta[Y_AXIS] ]-A_AXIS
在反解函数中加入:servos
[0].write(0.9*(270-delta[X_AXIS]-delta[Y_AXIS]-A_AXIS));
注:变量A_AXIS的值由G5代码获取,0.9是比例因,因为用的舵机角度不准确,0-180实际就是0-200。

马林鱼基础参数修改

Configuration.h 文件中

//========================= SCARA配置 ==================================
#define SCARA  
#define scara_segments_per_second 400 

#define Linkage_1 125 // 主臂长度
#define Linkage_2 125 // 副臂长度

#define SCARA_offset_x  60 // 绝对坐标相对假定坐标的偏移量
#define SCARA_offset_y -100
#define SCARA_offset_z  0
#define SCARA_RAD2DEG 57.2957795 //弧度转角度因子 

#define L1_2 sq(Linkage_1) //主臂的平方值
#define L2_2 sq(Linkage_2) 

//========================= 基础设置 ==================================
#define SERIAL_PORT 0//端口,默认0

#define BAUDRATE 115200//波特率

#ifndef MOTHERBOARD
  #define MOTHERBOARD BOARD_RAMPS_13_EFB//主板类型,在board.h中可以找到对应主板的名称
#endif

#define EXTRUDERS 1//挤出机数量

#define POWER_SUPPLY 1//电源类型,一般为1

//============================= 温度设置 ============================
// -2 is thermocouple with MAX6675 (only for sensor 0)
// -1 is thermocouple with AD595
// 0 is not used
// 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup)
// 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup)
// 3 is Mendel-parts thermistor (4.7k pullup)
// 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !!
// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (4.7k pullup)
// 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup)
// 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup)
// 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup)
// 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup)
// 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup)
// 10 is 100k RS thermistor 198-961 (4.7k pullup)
// 11 is 100k beta 3950 1% thermistor (4.7k pullup)
// 12 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) (calibrated for Makibox hot bed)
// 13 is 100k Hisens 3950  1% up to 300°C for hotend "Simple ONE " & "Hotend "All In ONE" 
// 20 is the PT100 circuit found in the Ultimainboard V2.x
// 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950
//
//    1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k
//                          (but gives greater accuracy and more stable PID)
// 51 is 100k thermistor - EPCOS (1k pullup)
// 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup)
// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (1k pullup)
//
// 1047 is Pt1000 with 4k7 pullup
// 1010 is Pt1000 with 1k pullup (non standard)
// 147 is Pt100 with 4k7 pullup
// 110 is Pt100 with 1k pullup (non standard)
// 998 and 999 are Dummy Tables. They will ALWAYS read 25°C or the temperature defined below. 
//     Use it for Testing or Development purposes. NEVER for production machine.
//     #define DUMMY_THERMISTOR_998_VALUE 25
//     #define DUMMY_THERMISTOR_999_VALUE 100

#define TEMP_SENSOR_0 1 //各个挤出头的温度传感器类型(对应上面的注释,常见的为1),0是不使用
#define TEMP_SENSOR_1 0
#define TEMP_SENSOR_2 0
#define TEMP_SENSOR_3 0  
#define TEMP_SENSOR_BED 0 //热床

#define HEATER_0_MINTEMP 5 //最低温度
#define HEATER_1_MINTEMP 5
#define HEATER_2_MINTEMP 5
#define HEATER_3_MINTEMP 5
#define BED_MINTEMP 5

#define HEATER_0_MAXTEMP 275 //最高温度
#define HEATER_1_MAXTEMP 275
#define HEATER_2_MAXTEMP 275
#define HEATER_3_MAXTEMP 275
#define BED_MAXTEMP 150
//注:如果定义了挤出头的热敏电阻但是使用的时候没插,打印机就会报错,但不定义可能会编译不成功。如果不想使用挤出头可以把挤出头温度传感器类型设为1,最低温度设为0


//============================ 限位设置 ==========================

const bool X_MIN_ENDSTOP_INVERTING = true; 
const bool Y_MIN_ENDSTOP_INVERTING = true;  
const bool Z_MIN_ENDSTOP_INVERTING = true; 
const bool X_MAX_ENDSTOP_INVERTING = true; 
const bool Y_MAX_ENDSTOP_INVERTING = true; 
const bool Z_MAX_ENDSTOP_INVERTING = true; // 坐标最大值和坐标最小值的限位开关的常开常闭设置(true为常开)
//#define DISABLE_MAX_ENDSTOPS //取消最大坐标值限位  
//#define DISABLE_MIN_ENDSTOPS //取消最小坐标值限位

#define DISABLE_X false
#define DISABLE_Y false
#define DISABLE_Z false //在电机不工作时解锁电机
#define DISABLE_E false //对于所有挤出机有效
#define DISABLE_INACTIVE_EXTRUDER true //只解锁不工作的电机

#define INVERT_X_DIR false  
#define INVERT_Y_DIR false  
#define INVERT_Z_DIR true   
#define INVERT_E0_DIR false   
#define INVERT_E1_DIR false   
#define INVERT_E2_DIR false   
#define INVERT_E3_DIR false  //电机转动方向

#define X_HOME_DIR -1
#define Y_HOME_DIR 1
#define Z_HOME_DIR 1//限位配置,1为最大坐标限位

#define X_MAX_POS 250
#define X_MIN_POS 0
#define Y_MAX_POS 250
#define Y_MIN_POS 0
#define Z_MAX_POS MANUAL_Z_HOME_POS
#define Z_MIN_POS 0                    //喷头各轴的行程设置

#define MANUAL_X_HOME_POS  -32
#define MANUAL_Y_HOME_POS 151
#define MANUAL_Z_HOME_POS 190 //触发限位时各轴的坐标或角度,这里是初始值,后可用G代码修改


//============================ 电机设置 ==========================
#define HOMING_FEEDRATE {20*60, 20*60, 20*60, 0}  //home时的速率


#define DEFAULT_AXIS_STEPS_PER_UNIT   {53.333333,44.444444,100,300}  移动单位长度或角度需要的脉冲数(对应X,Y,Z,E)
#define DEFAULT_MAX_FEEDRATE          {200, 200, 200, 25}    // 最大速度
#define DEFAULT_MAX_ACCELERATION      {1000,1000,1000,1000}    // 最大加速度

#define DEFAULT_ACCELERATION          500    // 默认加速度
#define DEFAULT_RETRACT_ACCELERATION  2000     //反转加速度

//============================ 舵机设置 ==========================

#define NUM_SERVOS 3 // 舵机个数
//注:原固件中的舵机是给自动调平用的,如果要用g代码控制舵机需要自己添加

| | |
| - | - |

马林鱼的修改

正反解

Marlin_main.cpp 文件中
1.找到calculate_SCARA_forward_Transform(正解)和calculate_delta(反解)函数,修改成上面的正反解。
2.找到代码的这个部分,在#ifdef SCARA中ManualHomePos[3]加入数组变量,这个一排到底是哪一个轴触发了限位时的关节坐标(也就是初始坐标的值)

#ifdef DELTA
  float delta[3] = { 0, 0, 0 };
  #define SIN_60 0.8660254037844386
  #define COS_60 0.5
  // these are the default values, can be overriden with M665
  float delta_radius = DELTA_RADIUS;
  float delta_tower1_x = -SIN_60 * delta_radius; // front left tower
  float delta_tower1_y = -COS_60 * delta_radius;   
  float delta_tower2_x =  SIN_60 * delta_radius; // front right tower
  float delta_tower2_y = -COS_60 * delta_radius;   
  float delta_tower3_x = 0;                      // back middle tower
  float delta_tower3_y = delta_radius;
  float delta_diagonal_rod = DELTA_DIAGONAL_ROD;
  float delta_diagonal_rod_2 = sq(delta_diagonal_rod);
  float delta_segments_per_second = DELTA_SEGMENTS_PER_SECOND;
#endif

#ifdef SCARA
  float axis_scaling[3] = { 1, 1, 1 }; 
  float ManualHomePos[3]={MANUAL_X_HOME_POS,MANUAL_Y_HOME_POS,MANUAL_Y_HOME_POS};
  float SCARA_offset[3]={SCARA_offset_x,SCARA_offset_y,SCARA_offset_z};
#endif         

| | |
| - | - |

3.找到写G28的那一段代码,添加如下代码,即把触发限位时各轴的坐标定义成实际的限位触发触发点。

 if(code_seen('G'))
  {
    switch((int)code_value())
    {
          ...
     case 28:
               ...
          #ifdef SCARA 

             calculate_SCARA_forward_Transform(ManualHomePos);
             for(int8_t i=0; i < 3; i++)
             {
                 destination[i]=current_position[i]=delta[i];
                 delta[i]=ManualHomePos[i];
             }   
             plan_set_position(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS]);
          #endif 
               ...
     break;
     }
}

| | |
| - | - |

添加写入 EEPROM 的参数:

在ConfigurationStore.cpp文件中的Config_StoreSettings()、Config_RetrieveSettings()函数下添加以下代码:(两个函数分别是写入和恢复参数)

#ifdef SCARA
  EEPROM_WRITE_VAR(i,SCARA_offset);//原点偏移量
  EEPROM_WRITE_VAR(i,ManualHomePos);//触发限位角度
  #endif

| | |
| - | - |

在 Config_ResetDefault() 下添加:(此函数为恢复参数默认)

#ifdef SCARA
  SCARA_offset[X_AXIS] = SCARA_offset_x; 
  SCARA_offset[Y_AXIS] = SCARA_offset_y;
  SCARA_offset[Z_AXIS] = SCARA_offset_z;
  ManualHomePos[X_AXIS] = MANUAL_X_HOME_POS;
  ManualHomePos[Y_AXIS] = MANUAL_Y_HOME_POS;
  ManualHomePos[Z_AXIS] = MANUAL_Z_HOME_POS;
  #endif

| | |
| - | - |

在 Marlin.h 中定义

#ifdef SCARA
extern float axis_scaling[3]; 
extern float SCARA_offset[3];
extern float ManualHomePos[3]; 
#endif

| | |
| - | - |

添加自定义的G、M代码:

1.添加修改限位角度的M代码(M360)。找到写M代码的部分加入以下代码。
case 360:
        for(int8_t i=0; i < 3; i++)
        {
            if(code_seen(axis_codes[i])) 
            {
                ManualHomePos[i] = code_value();//把触发限位时的相对坐标设置成输入的值
            }
        }
        break;  

| | |
| - | - |

2.添加偏移量的M代码(M361)

case 361:
        for(int8_t i=0; i < 3; i++)
        {
            if(code_seen(axis_codes[i])) 
            {
                SCARA_offset[i] = code_value();
            }
        }
        break;

| | |
| - | - |

  1. 添加控制舵机的 G 代码。首先要在 Configuration.h 文件中定义舵机
case 5: // G5 servo contrl
      if (code_seen('A')) 
        servos[0].write(code_value());//舵机A转动所输入的角度
      if (code_seen('B')) 
        servos[1].write(code_value());
      if (code_seen('C')) 
        servos[2].write(code_value());
    break;

| | |
| - | - |

4.添加角度模式。Marlin_main.cpp文件中添加角度模式的开关变量。

#ifdef SCARA
  float axis_scaling[3] = { 1, 1, 1 }; 
  float ManualHomePos[3]={MANUAL_X_HOME_POS,MANUAL_Y_HOME_POS,MANUAL_Y_HOME_POS}; 
  float SCARA_offset[3]={SCARA_offset_x,SCARA_offset_y,SCARA_offset_z};
  bool angle_mode=false;
#endif   

| | |
| - | - |

在 G 代码的案例中添加案例 95 。 即 G95 代码切换角度使用模式和坐标模式。

case 95: 
      angle_mode=!angle_mode;
      break;

| | |
| - | - |

反解函数calculate_delta 修改为如下,即角度模式为假进行坐标换算,为真不换算。

if(angle_mode==false)
  {
    delta[X_AXIS] = SCARA_theta * SCARA_RAD2DEG; // Multiply by 180/Pi - Theta is support arm angle (shoulder)
    delta[Y_AXIS] = SCARA_psi * SCARA_RAD2DEG;   // - Psi sub arm angle (elbow)
    delta[Z_AXIS] = cartesian[Z_AXIS]-SCARA_offset[Z_AXIS];
  }
  else
  {
      delta[X_AXIS] = cartesian[X_AXIS];
      delta[Y_AXIS] = cartesian[Y_AXIS];
      delta[Z_AXIS] = cartesian[Z_AXIS];
  }

| | |
| - | - |

5.添加当前坐标设定的 G 代码。原有固件在 G92(case 92)代码中只能设置 E 轴的当前坐标。所以添加如下代码可以把机械手任意的位置设置成想要的坐标。
原理即修改坐标偏移量 SCARA_offset[i] 但不保存到固件

#ifdef SCARA
        if (i == X_AXIS || i == Y_AXIS||i == Z_AXIS) {

                    SCARA_offset[i]=SCARA_offset[i]-current_position[i]+code_value();//新的坐标偏移量=旧的坐标偏移量-当前坐标+想要设定的坐标
                    current_position[i] = code_value();  //设定当前坐标为输入的值
        }
#endif

| | |
| - | - |

RAMPS主板详解:

[](http://wx4.sinaimg.cn/mw690/e8d4eb99gy1fq9tptizfvj20m80fw11z.jpg)

[

](http://wx4.sinaimg.cn/mw690/e8d4eb99gy1fq9tptizfvj20m80fw11z.jpg)

如果 arduino2560 是 ams1117 用的稳压芯片,建议把 D1,两个板子单独供电。

常用G、M代码:

M360 触发限位角度设置
M361 原点偏移设置
G5 舵机角度控制

G0 快速点定位
G1 直线插补
G4 延迟
G28 回归所有轴
G92 当前坐标设定
G95 切换绝对/关节坐标

M0 停止
M3 鹦鹉正转
M4愚正转M4 鹦鹉
停止
M17 启动步进电机
M20 读取卡打印
M21
初始化SD 卡M22 弹出SD 卡
M23 选择SD 卡文件
M24 开始SD 卡的打印
M25 暂停SD 卡打印
M41 循环
M82 发射机定位坐标
M83 发射机定位坐标
M84 安装电机电机
M92 设置步进电机数据
M101 正转
投机机
M104 设置发射机温度
M105 获取温度
M106
关闭打开获取风扇
M112 紧急停止
M114 当前坐标和角度
M119 获取限位开关状态
M201 设置最大速度
M202 设置最大移动速度
M203 设置电机最大速度
M204 设置默认速度
M500 设置保存到EEPROM
M501 读取EEPROM 中的配置
M502 恢复设置
M503 读取起始设置

**

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結構來實現龐大的功能體系,同時也爲新功能的增添提供了巨大的便利

最后修改:2021 年 08 月 27 日
如果觉得我的文章对你有用,请随意赞赏