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

上面已经实现了字节和数组如何从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<

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

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:初始化参数的读入和读出显示)