美文网首页
运动控制器16:初始化参数的读入和读出显示

运动控制器16:初始化参数的读入和读出显示

作者: 吴松乾 | 来源:发表于2018-01-11 17:36 被阅读0次

    上面已经实现了字节和数组如何从EEPROM中读回和写入,我们控制器需要将常用的参数存入到EEPROM中,包括了机械结构的参数,那如何将结构体整体和部分读回和写入呢?

    存入的结构体

    typedef struct {
      float steps_per_mm[3];
      uint8_t microsteps;
      uint8_t pulse_microseconds;
      float default_feed_rate;
      float default_seek_rate;
      uint8_t invert_mask;
      float mm_per_arc_segment;
      float acceleration;
      float junction_deviation;
    } settings_v4_t;
    

    其中各个参数的意义在下文中有描述:
    GRBL的配置参数文件
    具体来说,存入的参数如下:

      #define DEFAULT_X_STEPS_PER_MM 600.0
      #define DEFAULT_Y_STEPS_PER_MM 600.0
      #define DEFAULT_Z_STEPS_PER_MM 600.0
      #define DEFAULT_STEP_PULSE_MICROSECONDS 60
      #define DEFAULT_MM_PER_ARC_SEGMENT 0.1
      #define DEFAULT_RAPID_FEEDRATE 100.0 // mm/min
      #define DEFAULT_FEEDRATE 300.0
      #define DEFAULT_ACCELERATION (10.0*60*60) // 10 mm/min^2
      #define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
      #define DEFAULT_STEPPING_INVERT_MASK 0x00//((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT))
      #define DEFAULT_REPORT_INCHES 0 // false
      #define DEFAULT_AUTO_START 1 // true
      #define DEFAULT_INVERT_ST_ENABLE 0 // false
      #define DEFAULT_HARD_LIMIT_ENABLE 0  // false
      #define DEFAULT_HOMING_ENABLE 0  // false
      #define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
      #define DEFAULT_HOMING_RAPID_FEEDRATE 150.0 // mm/min
      #define DEFAULT_HOMING_FEEDRATE 25.0 // mm/min
      #define DEFAULT_HOMING_DEBOUNCE_DELAY 100 // msec (0-65k)
      #define DEFAULT_HOMING_PULLOFF 1.0 // mm
      #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-255)
      #define DEFAULT_DECIMAL_PLACES 3
      #define DEFAULT_N_ARC_CORRECTION 25
    

    如此,我们存入的参数将不以字节为单元,该如何存入?

    memcpy_to_eeprom_with_checksum

    我们的函数用到了checksum,看如何通过算法进行checksum

    //入口参数:destination为写入的首地址,因为0位置保存的是版本号,全局变量我们从位置1开始存入
    //入口参数:*source 指针,指向的是结构体,通过&settings获取结构体的地址
    //并且强制转换成(char*)指针
    //入口参数:结构体的大小,通过函数sizeof来计算,这样,此函数的调用示范如下   
    //调用示例:memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL,    
    //(char*)&settings, sizeof(settings_t));
    void memcpy_to_eeprom_with_checksum  
    (unsigned int destination, char *source, unsigned int size) 
    {
      unsigned char checksum = 0;
      for(; size > 0; size--)
      { 
        checksum = (checksum << 1) || (checksum >> 7);
        //第一次循环,checksum=0;将第一个字节赋给checksum
        checksum += *source;
        //写入后地址++,写入后结构体指针++,这里结构体强制转换为了8位的数组
        eeprom_put_char(destination++, *(source++)); 
      }
      //最后将checksum写入到最后的一个字节中。
      eeprom_put_char(destination, checksum);
    }
    

    此函数实现了将结构体中的数据写入到EEPROM中,我们调用循环读出函数,将设置好的参数进行回读。首先,我们需要将结构体进行赋值,如下:

        settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
        settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
        settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
        ……
    

    设置完成以后,调用:write_global_settings,而此函数只是将版本和全局设置分开写入而已。

    void write_global_settings() 
    {
      eeprom_put_char(0, SETTINGS_VERSION);
      memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, 
      (char*)&settings, sizeof(settings_t));
    }
    

    设置完成以后,我们用测试程序进行查看EEPROM的写入是否成功:

         settings_reset(1);
         for(i=0;i<80;i++)
         {
             if(i%10==0) { DebugPf("\n"); }
             DebugPf("0X%02X  ",I2C_EE_ByteRead(i)); 
         }
    

    用串口输出一行10字节的数据,显示如下:


    串口调试助手输出的调试信息.png

    memcpy_to_eeprom_with_checksum

    uint8_t read_global_settings() {
      //先读取版本号,如果版本号是我们写入过的5
      uint8_t version = eeprom_get_char(0);
      if (version == SETTINGS_VERSION) {
        //
        if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
          return(false);
        }
      } 
      else {
        if (version <= 4) 
            {
          // Migrate from settings version 4 to current version.
          if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v4_t)))) {
            return(false);
          }     
          settings_reset(false); // Old settings ok. Write new settings only.
        } else {      
          return(false);
        }
      }
      return(true);
    }
    

    用到了下面的函数:此函数实现从EEPROM中读取到结构体中,并进行checksum校验。

    int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size) {
      unsigned char data, checksum = 0;
      for(; size > 0; size--) { 
        data = eeprom_get_char(source++);
        checksum = (checksum << 1) || (checksum >> 7);
        checksum += data;    
        *(destination++) = data; 
      }
      return(checksum == eeprom_get_char(source));
    }
    

    此函数我们用写入和读取,判断校验位的方式,看读写是否正确:通过测试,回读正确。

    void write_global_settings() 
    {
        //u8 a;
      eeprom_put_char(0, SETTINGS_VERSION);
      memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t));
        //测试回读
    //  a=memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t));
    //  if(a==1)
    //  DebugPf("EEPROM READBACK RIGHT\n");
    //  else 
    //  DebugPf("!!!!!!!!!!!!!!EEPROM READBACK WRONG!!!!!!!!!!!!!\n");
    }
    

    读全局参数配置

    uint8_t read_global_settings() {
      //检测版本信息
      uint8_t version = eeprom_get_char(0);
      if (version == SETTINGS_VERSION) 
      {
        //如果校验错误,则返回0,否则将结构体读出
        if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
          return(false);
        }
      } 
      else
      {
        if (version <= 4) 
            {
          if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v4_t)))) {
            return(false);
          }     
          settings_reset(false); // Old settings ok. Write new settings only.
        } else {      
          return(false);
        }
      }
      return(true);
    }
    

    函数确认OK以后,继续看settings_init,函数还可以保存故障发生时候XYZ的坐标值,我们这里没有保存,所以可以略过。
    程序测试:

    • 程序上电时,一定需要设置的参数不设置,而默认的参数,我们设置为一个固定值。
    • 程序返回设置完成的参数表,之后我们进行一次设置到默认值
    • 重新上电以后,程序将使用EEPROM中的参数进行打印输出
    void settings_init() {
      float coord_data[N_AXIS];
      uint8_t i;
      if(!read_global_settings()) {
        report_status_message(STATUS_SETTING_READ_FAIL);
        settings_reset(true);
        report_grbl_settings();
      }
      // Read all parameter data into a dummy variable. If error, reset to zero, otherwise do nothing.
      for (i=0; i<=SETTING_INDEX_NCOORD; i++) {
        if (!settings_read_coord_data(i, coord_data)) {
          report_status_message(STATUS_SETTING_READ_FAIL);
        }
      }
      // NOTE: Startup lines are handled and called by main.c at the end of initialization.
    }
    
    

    串口打印输出的文本如下:

    $0=0.000 (x, step/mm)
    $1=0.000 (y, step/mm)
    $2=0.000 (z, step/mm)
    $3=0 (step pulse, usec)
    $4=0.000 (default feed, mm/min)
    $5=0.000 (default seek, mm/min)
    $6=0 (step port invert mask, int:)
    $7=25 (step idle delay, msec)
    $8=0.000 (acceleration, mm/sec^2)
    $9=0.000 (junction deviation, mm)
    $10=0.000 (arc, mm/segment)
    $11=25 (n-arc correction, int)
    $12=3 (n-decimals, int)
    $13=0 (report inches, bool)
    $14=1 (auto start, bool)
    $15=0 (invert step enable, bool)
    $16=0 (hard limits, bool)
    $17=0 (homing cycle, bool)
    $18=0 (homing dir invert mask, int:)
    $19=25.000 (homing feed, mm/min)
    $20=150.000 (homing seek, mm/min)
    $21=100 (homing debounce, msec)
    $22=1.000 (homing pull-off, mm)
    System initialization finished
    
    
    初始化结构体参数设置完成,开始读取坐标值...
    
    error: EEPROM read fail. Using defaults
    坐标轴读取失败,系统将从逻辑零点开始运行
    error: EEPROM read fail. Using defaults
    坐标轴读取失败,系统将从逻辑零点开始运行
    error: EEPROM read fail. Using defaults
    坐标轴读取失败,系统将从逻辑零点开始运行
    error: EEPROM read fail. Using defaults
    坐标轴读取失败,系统将从逻辑零点开始运行
    error: EEPROM read fail. Using defaults
    坐标轴读取失败,系统将从逻辑零点开始运行
    error: EEPROM read fail. Using defaults
    坐标轴读取失败,系统将从逻辑零点开始运行
    初始化设置完毕
    
    $0=600.000 (x, step/mm)
    $1=600.000 (y, step/mm)
    $2=600.000 (z, step/mm)
    $3=60 (step pulse, usec)
    $4=300.000 (default feed, mm/min)
    $5=100.000 (default seek, mm/min)
    $6=0 (step port invert mask, int:)
    $7=25 (step idle delay, msec)
    $8=10.000 (acceleration, mm/sec^2)
    $9=0.050 (junction deviation, mm)
    $10=0.100 (arc, mm/segment)
    $11=25 (n-arc correction, int)
    $12=3 (n-decimals, int)
    $13=0 (report inches, bool)
    $14=1 (auto start, bool)
    $15=0 (invert step enable, bool)
    $16=0 (hard limits, bool)
    $17=0 (homing cycle, bool)
    $18=0 (homing dir invert mask, int:)
    $19=25.000 (homing feed, mm/min)
    $20=150.000 (homing seek, mm/min)
    $21=100 (homing debounce, msec)
    $22=1.000 (homing pull-off, mm)
    
    

    总结

    如何将一个结构体和特殊文件保存到EEPROM中。
    在调试程序时候,善用串口调试助手进行程序的过程输出。

    相关文章

      网友评论

          本文标题:运动控制器16:初始化参数的读入和读出显示

          本文链接:https://www.haomeiwen.com/subject/uyjtoxtx.html