运动控制器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<<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中。
在调试程序时候,善用串口调试助手进行程序的过程输出。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容