Go Down

Topic: [SOLVED] Struct arrays not possible on arduino... sort of. (Read 12622 times) previous topic - next topic

Whandall

You testcode just happens to print what you like.
In all your for loops you do not initialize the index variable.
This generates warnings and unpredictable behaviour.

Code: [Select]
txtttt.ino: In function 'void setup()':
txtttt.ino:23:11: warning: 'i' is used uninitialized in this function [-Wuninitialized]
txtttt.ino:32:11: warning: 'i' is used uninitialized in this function [-Wuninitialized]
txtttt.ino:46:11: warning: 'i' is used uninitialized in this function [-Wuninitialized]
txtttt.ino:55:11: warning: 'i' is used uninitialized in this function [-Wuninitialized]
txtttt.ino:60:11: warning: 'i' is used uninitialized in this function [-Wuninitialized]
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

SurferTim

#31
Jun 09, 2016, 03:28 am Last Edit: Jun 09, 2016, 03:34 am by SurferTim
@Whandall: My bad. I corrected the code, and it still runs the same. Exactly what I expected it to do.
edit: What did you mean by this?
Quote
You testcode just happens to print what you like.
Of course it does.

Whandall

But now you know it will work regardless of the running environment.  ;)

I added a dump to your (unchanged) testsketch, maybe you find the functionality useful.

Code: [Select]
#include <EEPROM.h>

struct mytest {
  int test1;
  byte test2;
  long test3;
  char test4[32];
};

mytest newTest[2] = {
  4, 5, 6, "this is a test0",
  7, 8, 9, "this is a test1"
};

int address = 0;

char tBuf[32];

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  dump_E((byte*)address, sizeof(newTest));
  Serial.println("");
  dump((byte*)newTest, sizeof(newTest));
  Serial.println("");

  for (int i; i < 2; i++) {
    Serial.println(newTest[i].test1);
    Serial.println(newTest[i].test2);
    Serial.println(newTest[i].test3);
    Serial.println(newTest[i].test4);
  }

  Serial.println("Writing to EEPROM");

  for (int i; i < 2; i++) {
    address = i * sizeof(mytest);
    EEPROM.put(address, newTest[i]);
  }

  for (int i = 0; i < 2; i++) {
    newTest[i].test1 = i + 3;
    newTest[i].test2 = i + 4;
    newTest[i].test3 = i + 5;
    strcpy(newTest[i].test4, "test");
    itoa(i, tBuf, 10);
    strcat(newTest[i].test4, tBuf);
  }

  for (int i; i < 2; i++) {
    Serial.println(newTest[i].test1);
    Serial.println(newTest[i].test2);
    Serial.println(newTest[i].test3);
    Serial.println(newTest[i].test4);
  }

  Serial.println("Reading from EEPROM");

  for (int i; i < 2; i++) {
    address = i * sizeof(mytest);
    EEPROM.get(address, newTest[i]);
  }

  for (int i; i < 2; i++) {
    Serial.println(newTest[i].test1);
    Serial.println(newTest[i].test2);
    Serial.println(newTest[i].test3);
    Serial.println(newTest[i].test4);
  }
}

void loop() {
  // put your main code here, to run repeatedly:
}


char hexNibble(byte val) {
  val &= 0xF;
  if (val > 9) {
    return val + 'A' - 10;
  } else {
    return val + '0';
  }
}

void hexByte(char* store, byte val) {
  store[1] = hexNibble(val);
  store[0] = hexNibble(val >> 4);
}

char* toHex(unsigned int val, byte adrTyp = 0) {
  static char textBuf[9];
  const char* cTyp = " rpe";
  if (adrTyp) {
    textBuf[0] = cTyp[adrTyp - 1];
    textBuf[1] = ' ';
    hexByte(textBuf + 2, (byte)(val >> 8));
    hexByte(textBuf + 4, (byte)val);
    textBuf[6] = ':';
    textBuf[7] = ' ';
    textBuf[8] = 0;
  } else {
    hexByte(textBuf, (byte)val);
    textBuf[2] = ' ';
    textBuf[3] = 0;
  }
  return textBuf;
}

void dumpGen(byte (*func)(byte*), byte typ, byte* adr, unsigned int len) {
  int lines = (len + 15) >> 4;
  bool moreThanOneLine = (lines != 1);
  byte bytes;
  for (; lines--; adr += 16, len -= 16) {
    Serial.write(toHex((unsigned int)adr, typ));
    for (bytes = 0; bytes < 16; bytes++) {
      if (bytes < len) {
        Serial.write(toHex((*func)(&adr[bytes])));
      } else if (moreThanOneLine) {
        Serial.print(F("   "));
      }
    }
    Serial.print(F("'"));
    for (bytes = 0; bytes < 16; bytes++) {
      if (bytes < len) {
        byte cVal = (*func)(&adr[bytes]);
        Serial.write((cVal & 0x7F) < 0x20 ? '.' : cVal);
      }
    }
    Serial.print(F("'\r\n"));
  }
}

byte ramReadByte(byte* adr) {
  return *adr;
}

byte flashReadByte(byte* adr) {
  return pgm_read_byte_near(adr);
}
byte eepromReadByte(byte* adr) {
  return eeprom_read_byte(adr);
}

void dump(byte* adr, unsigned int len) {
  dumpGen(ramReadByte, 2, adr, len);
}

void dump_P(byte* adr, unsigned int len) {
  dumpGen(flashReadByte, 3, adr, len);
}

void dump_E(byte* adr, unsigned int len) {
  dumpGen(eepromReadByte, 4, adr, len);
}

produces:
Code: [Select]
e 0000: 04 00 05 06 00 00 00 74 68 69 73 20 69 73 20 61 '.......this is a'
e 0010: 20 74 65 73 74 30 00 00 00 00 00 00 00 00 00 00 ' test0..........'
e 0020: 00 00 00 00 00 00 00 07 00 08 09 00 00 00 74 68 '..............th'
e 0030: 69 73 20 69 73 20 61 20 74 65 73 74 31 00 00 00 'is is a test1...'
e 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00       '..............'

r 0100: 04 00 05 06 00 00 00 74 68 69 73 20 69 73 20 61 '.......this is a'
r 0110: 20 74 65 73 74 30 00 00 00 00 00 00 00 00 00 00 ' test0..........'
r 0120: 00 00 00 00 00 00 00 07 00 08 09 00 00 00 74 68 '..............th'
r 0130: 69 73 20 69 73 20 61 20 74 65 73 74 31 00 00 00 'is is a test1...'
r 0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00       '..............'

4
5
6
this is a test0
7
8
9
this is a test1
Writing to EEPROM
3
4
5
test0
4
5
6
test1
Reading from EEPROM
4
5
6
this is a test0
7
8
9
this is a test1
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

SurferTim

I added a dump to your (unchanged) testsketch, maybe you find the functionality useful.
Thanks, but not really. That was also exactly what I expected.

rinkrides

@Whandall- about the b < 8... i know right?! I was proving a point about < vs <=...

I figured that as a char array, the reference says to leave one byte of padding so that serial.print knows when to stop, ie null terminator.

And finally.. EEPROM.get(address, LED); //this will fill the whole array of structs?! ARE JU KIDDING ME?!?!  :smiley-eek: Tested just now... that one liner to me right now with the little sleep I have looks as elegant as E = MC2

Well good sir, show a man how to fish ect.. may I spam your Karma link?

I am an Autobody Collision Tech by trade. I have a passion for electronics engineering (mostly analog), but i have a new passion for MCU's that started with the Basic stamp II, Parallax Propeller, and now in AVR land having a blast the past 5 years!

EEPROM.get(address, LED); just blows my mind! amazing! had zero idea that was possible!!!
Electronics Engineering, "EE=MC^(OMG x WTF?!)"
Professional Auto Collision/Custom tech

nickgammon

Quote
I have a passion for electronics engineering (mostly analog), but i have a new passion for MCU's that started with the Basic stamp II, Parallax Propeller, and now in AVR land having a blast the past 5 years!
Enjoy yourself. It can be a lot of fun. :)
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Whandall

I figured that as a char array, the reference says to leave one byte of padding so that serial.print knows when to stop, ie null terminator.
If you have plenty of EEPROM free, the unused byte does not matter, but in the small environment often each byte counts. Printing is not as convenient as with the embedded terminator, but it would be easy to add a function to the structure that deals with the missing terminator.
Remember that a structure is just a class with all public members.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

rinkrides

#37
Jun 10, 2016, 12:21 am Last Edit: Jun 10, 2016, 12:40 am by rinkrides
@Whandall - this is true. If need be, one could use  a quick 4 lines assignment to initialize the 8th char in the .name array to "0", or for loop for bigger struct arrays. ButI got the jist.I guess C++ is quite powerful if you know what your doing. I was worried I was overloading the EEPROM.get() function by assigning a character to a multidimensional array. Does anyone know of a good online tut site for C++? Or should I just invest in a college course?

Unrelated my copy of "the Art of Electronics 3rd ed" just arrived! It's everything I've learned since age 9 x10.
Electronics Engineering, "EE=MC^(OMG x WTF?!)"
Professional Auto Collision/Custom tech

rinkrides

Whandal - may I say that EEPROM.put(address, LED); would also update/store the whole array of the LED structure?
Electronics Engineering, "EE=MC^(OMG x WTF?!)"
Professional Auto Collision/Custom tech

Whandall

Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

rinkrides

Marked solved. Thank you all for your help with this subject. Arrays of structs are possible in a sketch, makes for tidy readable code ;) A quick example:
Code: [Select]

#include <EEPROM.h>

struct  myParameters{
  float        voltage;
  uint32_t  bigNumber;
  char        longName[16];
};

myParameters  myPar[16];

void setup(){
  EEPROM.get(address, myPar);  //gets ALL the values of the struct array and stores in RAM for your sketch
  sampleVoltages();
  getName();
  calcBigNum();
  if( valuesChanged ){
    EEPROM.put(address, myPar);  //will only write values if they are different than EEPROM values
  }
}
Electronics Engineering, "EE=MC^(OMG x WTF?!)"
Professional Auto Collision/Custom tech

Go Up