EEPROM.put() and EEPROM.get()

Hi guys,

Just been trying to implement the new(ish) EEPROM library commands and getting some unexpected results.

These 2 Subroutines don't behave as I expected.

void Block()  {
  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == '"') {
      Marker ++;
      readString = "";
    }
    if (Marker == 2)  {
      Banned = readString;
      Marker = 0;
      readString = "";
      if (Banned != Primary_Phone) {
        EEPROM.put(0, Banned);
        delay(100);
        Serial.println("AT+CMGS" + Phone);             //Send SMS to this number
        delay(100);
        Serial.print (Banned);
        delay(100);
        showString (PSTR(" Blocked from system\r\n"));
        delay(100);
        showString(PSTR("\x1A\r\n"));                           //Delay to accomodate message send.
        Sec = 8;
        Delay();
        return;

      }
    }

    else {

      readString += c; //makes the string readString
    }
  }

}
void Restore()  {
  EEPROM.get(0, Banned);
  EEPROM.put (0, Dummy);
  Serial.println("AT+CMGS" + Phone);             //Send SMS to this number
  delay(100);
  Serial.print (Banned);
  delay(100);
  showString (PSTR(" Restored to system\r\n"));
  delay(100);
  showString(PSTR("\x1A\r\n"));                           //Delay to accomodate message send.
  Sec = 8;
  Delay();
  Banned = Dummy;

}

"Block" never sends the message after the EEPROM.put(), and doesn't actually seem to be writing to EEPROM, and "Restore" returns the value of "Dummy" instead of "Banned".

I know it'll be something I'm missing but from the examples I can't figure it out. Any help greatly appreciated.

Cheers
Greg.

If banned and Dummy are String objects, this will not work correctly, I just posted an explanation why this will not work here: Problem with eepromex loading a struct (code goes crazy) - #3 by pYro_65 - Programming Questions - Arduino Forum

Basically the String data is not stored in the object, but in dynamic memory separate to the object.

Instead of this:-

if (c == '"') {

Try:-

if (c == '\"') {

Also, you say "Restore" returns the value of "Dummy" instead of "Banned", yet 'void Restore()' doesn't actually return a value at all.

And how can you tell the difference since the last line in 'Restore()' is:-

Banned = Dummy;

Plus what pYro_65 just said. :slight_smile:

OldSteve:
Instead of this:-

if (c == '"') {

Try:-

if (c == '\"') {

@OldSteve: why should one introduce a superfluous backslash?
I doubt that the latter is more readable (for me, it is not).

Whandall:
@OldSteve: why should one introduce a superfluous backslash?
I doubt that the latter is more readable (for me, it is not).

In C++, it's necessary, isn't it? (An escape character for the ".)
C++ Escape sequences
(See the second entry in the chart.)

Or isn't it needed with Arduino?

Edit: In C++, it's the 'law'. Code won't perform as expected without it. Like the '' in '\n'.

OldSteve:
Or isn't it needed with Arduino?

OK, after a test, I can answer my own question - it's not needed in Arduino. Only in C++. My bad.
It 'works' in Arduino, but isn't 'required'.

OldSteve:
it's not needed in Arduino. Only in C++.

Sorry, Arduino uses C++.

You only have to escape the surrounding delimiter

char string[] = "abc\"de";
char tChr = '\'';

Whandall:
Sorry, Arduino uses C++.

Yes, I know it's based on C++, that's why I thought it was needed.

You only have to escape the surrounding delimiter

char string[] = "abc\"de";

char tChr = ''';

That's where I was mistaken. I've always thought I had to do this ", regardless of whether it was enclosed in single or double quotes. (Looks like for years I've been typing an extra character for no reason. And because it's happily accepted by the compiler, I haven't had a warning to tell me. :frowning: )

Thanks for bringing it to my attention. I didn't suggest it for 'readability' as you suggested, but because I thought it was required. Another lesson learned. That's what I like about these forums. :slight_smile:

Thanks Gents,

So, if I read what Pyro65 has written correctly, I need to use something other than a string object? In my case, the data is stored as a string in both cases ("Dummy" = +xxxxxxxxxxx, and "Banned" is a string, read from incoming serial data always enclosed within " ", always beginning with "+" and always 12 characters long including the "+" at the beginning.

As for how I tell the difference, The message should send prior to the "Banned = Dummy" instruction so the value of "Banned" in the message should be that of "Banned"?

Cheers
Greg.

gregcan:
As for how I tell the difference, The message should send prior to the "Banned = Dummy" instruction so the value of "Banned" in the message should be that of "Banned"?
Cheers
Greg.

I understand. I was just referring to the usual meaning of 'return value', and chose my words badly. I meant that even if 'Restore()' did have a 'String' return value, there'd be no way to tell the difference.
(A String sent serially isn't usually referred to as the 'return' value'. In this case it's the equivalent though.)

Hi OldSteve,

If there's an issue with incorrect terminology I'm sure it's mine... I'm still confused though, If my code instructs that the current value of a variable be sent in a message, then after the message send the value is changed to that of another variable, why would the sent message have the value of the second variable.

That said, how do I make the code work using Strings (or other preferred variable)...

Cheers
Greg.

gregcan:
I'm still confused though, If my code instructs that the current value of a variable be sent in a message, then after the message send the value is changed to that of another variable, why would the sent message have the value of the second variable.

That's a good question.

That said, how do I make the code work using Strings (or other preferred variable)...

C strings, (char arrays), are preferred over Strings, for a number of reasons. And I believe that C strings would work with the EEPROM library too. Which library, EEPROMex?
(I've haven't got as far as using the onboard EEPROM for anything yet. I've only been using Arduinos for about 4 weeks.)

Posting all of your code , rather than just the two functions, would help with both questions.

@gregcan

Please take a look at the excellent tutorial by Robin2 on Serial Input Basics for ways to read in your data as a null terminated character array (aka c string ; spelled with a lower case s) which can be stored in EEPROM.

Thanks Cattledog, I'll have a read and see what pearls of wisdom I can gain. OldSteve, I would include all my code but I fear that the shear size of this "experiment in how far you can push an ATmega 328" would have you, and many others tearing their hair out... The codeplug is currently 28K running on a Nano 3.0 (over 2500 lines of code) and although I'm certain you and many others would be able to work through it in time, it seems unnecessary to burden you with that much work. I have been adding function after function for the past 3 years and each is a standalone subroutine. this is my first attempt at using EEPROM to store anything so it's a whole new ballgame for me. The EEPROM.put(), and EEPROM.get() commands in the EEPROM library appear (from the descriptions) to be very flexible and intuitive but I'm unsure if I need to better define what I want "put, or got"... for example, If I say EEPROM.put (variable_name,0) and the variable_name is 12 characters long, do Ineed to specify a length of 12 characters or does the command allocate as many characters as required by the prescribed variable... Likewise, if I use EEPROM.get(0,variable_name), do I need to specify how many characters to get or does the command keep a record of what went where?

Get and put work with types larger than one byte (otherwise its identical to read/write). If you have an array of integers, then looping through the elements, you can use get and put to read/write the whole element in one go. Before the library had get and put, you would have to break up large types and write them one by one.

The first parameter for both methods is the address in the EEPROM (where you want to read to or write from), the second parameter is the object to read/write.

gregcan:
Thanks Cattledog, I'll have a read and see what pearls of wisdom I can gain. OldSteve, I would include all my code but I fear that the shear size of this "experiment in how far you can push an ATmega 328" would have you, and many others tearing their hair out... The codeplug is currently 28K running on a Nano 3.0 (over 2500 lines of code) and although I'm certain you and many others would be able to work through it in time, it seems unnecessary to burden you with that much work. I have been adding function after function for the past 3 years and each is a standalone subroutine. this is my first attempt at using EEPROM to store anything so it's a whole new ballgame for me. The EEPROM.put(), and EEPROM.get() commands in the EEPROM library appear (from the descriptions) to be very flexible and intuitive but I'm unsure if I need to better define what I want "put, or got"... for example, If I say EEPROM.put (variable_name,0) and the variable_name is 12 characters long, do Ineed to specify a length of 12 characters or does the command allocate as many characters as required by the prescribed variable... Likewise, if I use EEPROM.get(0,variable_name), do I need to specify how many characters to get or does the command keep a record of what went where?

Do I surmise from this that you have a version that works without EEPROM? Did you use that version to add EEPROM functionality or have you made other changes concurrently?

gregcan, these links answer most of your questions:-
EEPROM.put()
EEPROM.get()

And if you really want to continue to use the String class in the rest of your code, it's easy to convert a String object to a C string using c_str().

String myString="Arduino UNO";
char myBoard[15];

    strcpy(myBoard,myString.c_str());
    EEPROM.put(0,myBoard);
    
    char theBoard[15];
    EEPROM.get(0,theBoard);

Still, it's better to use char arrays / C strings right from the get-go instead of the String class.

Edit: But actually, despite what pYro_65 said in reply #1 about storing String objects using EEPROM.put() not working, I just tried and it worked fine.? Am I missing something again?

OldSteve:
gregcan, these links answer most of your questions:-
EEPROM.put()
EEPROM.get()

And if you really want to continue to use the String class in the rest of your code, it's easy to convert a String object to a C string using c_str().

String myString="Arduino UNO";

char myBoard[15];

strcpy(myBoard,myString.c_str());
   EEPROM.put(0,myBoard);
   
   char theBoard[15];
   EEPROM.get(0,theBoard);




Still, it's better to use char arrays / C strings right from the get-go instead of the String class.

Unfortunately the current version does not work with arrays, you still need to iterate through each element (but can be used to 'put' larger types used in the array).

You can download the next version I have prepared here (which will become available in a future version of the IDE)
https://forum.arduino.cc/index.php?topic=312645.msg2327941#msg2327941

This version will accept arrays.

pYro_65:
Unfortunately the current version does not work with arrays, you still need to iterate through each element (but can be used to 'put' larger types used in the array).

You can download the next version I have prepared here (which will become available in a future version of the IDE)
Official EEPROM library: support and reference. - #11 by pYro_65 - Programming Questions - Arduino Forum

This version will accept arrays.

The version that came with my Arduino IDE V1.6.5 works fine with both char arrays and String objects. I just tested both with no problems.
I can provide code examples if you like.

Here's a String object, to and from EEPROM:-

#include <EEPROM.h>

// Constants:-
String myString="Arduino UNO";

void setup()
{
    Serial.begin(115200);
    EEPROM.put(0,myString);
    String myBoard;
    EEPROM.get(0,myBoard);
    Serial.println(myBoard);
}

void loop(){}

OldSteve:
The version that came with my Arduino IDE V1.6.5 works fine with both char arrays and String objects. I just tested both with no problems.
I can provide code examples if you like.

The code will compile, but it does not work as expected.