How to store the serial received string to EEPROM

Hi All,

I looking guidance and sample code that store the serial received string to EEPROM using EEPROM Put and read it back later. The current code store the string to EEPROM but the return from EEPROM Get does not display the string stored.

Code below is store string to EEPROM
#include <EEPROM.h>
 
#define StatusPin 13

String User_String;
String ComData;

void setup() 
{
  Serial.begin(115200);
  pinMode(StatusPin,OUTPUT);
  digitalWrite(StatusPin,LOW);
  Serial.println("Initialize complete...");
  Serial.println("Please input command: ");
  Status_Done();
}

void loop() 
{
  while(Serial.available() == 0)
  {
       delay(100);
  }
  
  if(Serial.available()> 0)
  {
    ComData = "";
    while(Serial.available() > 0)
    {
      ComData = Serial.readStringUntil('\r');
      delay(2);  
    }
    Serial.println(ComData);
    if (ComData == "EEPROM Clear")
    {
      EEPROM_Clear();
      Serial.println("\nPlease input command:");
    }
    else if (ComData == "EEPROM Put")
    {
      while(Serial.available() == 0)
      {
        Serial.println("\nPlease input the string:");
        delay(1000);
      }
      if(Serial.available()> 0)
      {
        User_String = "";
        while(Serial.available() > 0)
        {
           User_String = Serial.readStringUntil('\r');
           delay(2);  
        }
        Serial.print("User String: ");
        Serial.println(User_String);
        EEPROM_Put();
      }
      Serial.println("\nPlease input command:");
    }
    else
    {
      Serial.println("Invalid input!!!");
      Serial.println("\nPlease input command:");
    }
  }
}

void EEPROM_Clear()
{
  // Clear all bytes in EEPROM to 0
  Serial.println("Clear the EEPORM...");
  for (int i = 0 ; i < EEPROM.length() ; i++) 
  {
    EEPROM.write(i, 0);
  }

  Serial.println("EEPORM Clear Done...");
  Status_Done();
  delay(100);
}  

void EEPROM_Put()
{
   int eeAddress = 0;   

  EEPROM.put(eeAddress, User_String);
  Serial.println("Written string to EEPROM...");
  Status_Done();
}

void Status_Done()
{
  for (int Done = 0; Done < 5; Done++)
  {
    digitalWrite(StatusPin,HIGH);
    delay(200);
    digitalWrite(StatusPin,LOW);
    delay(200);
  }
}

Code below read the string from EEPROM
#include <EEPROM.h>
 
#define StatusPin 13

String ComData;

void setup() 
{
  Serial.begin(115200);
  pinMode(StatusPin,OUTPUT);
  digitalWrite(StatusPin,LOW);
  Serial.println("Initialize complete...");
  Serial.println("Please input command:");
  Status_Done();
}

void loop() 
{
  while(Serial.available() == 0)
  {
     delay(100);
  }
  if(Serial.available()> 0)
  {
    ComData = "";
    while(Serial.available() > 0)
    {
        ComData = Serial.readStringUntil('\r');
        delay(2);  
    }
    Serial.println(ComData);
    if (ComData == "EEPROM Clear")
    {
      EEPROM_Clear();
      Status_Done();
      Serial.println("\nPlease input command:");
    }
    else if (ComData == "EEPROM Get")
    {
      EEPROM_Get();
      Status_Done();
      Serial.println("\nPlease input command:");
    }
    else
    {
      Serial.println("Invalid input!!!");
      Serial.println("\nPlease input command:");
    }
  }
}

void EEPROM_Clear()
{
  // Clear all bytes in EEPROM to 0
  Serial.println("Clear the EEPORM...");
  for (int i = 0 ; i < EEPROM.length() ; i++) 
  {
    EEPROM.write(i, 0);
  }
  Serial.println("EEPORM Clear Done...");
  Status_Done();
  delay(100);
}

void EEPROM_Get()
{
   String User_String; 
   int eeAddress = 0;  
  
   // Get the Arduino Serial Number from the EEPROM at position 'eeAddress'
  Serial.print("Read User String from EEPROM: ");
  EEPROM.get(eeAddress, User_String);
  Serial.println(User_String);   
}

void Status_Done()
{
  for (int Done = 0; Done < 5; Done++)
  {
    digitalWrite(StatusPin,HIGH);
    delay(150);
    digitalWrite(StatusPin,LOW);
    delay(150);
  }
}

Thank you.

Put what? You didn't specify any data to store. You never looked at any example sketches?

this is user function:

1 Like

Oops, yeah. But can you store a String object?

"data: the data to write, can be a primitive type (eg. float) or a custom struct"
https://docs.arduino.cc/learn/built-in-libraries/eeprom

1 Like

No, I believe this stores a pointer.

You could try to store User_String.c_str().

[edit] This does not work either, you can only store a fixed size array using put it seems.

1 Like

@eekhaytan
You cant directly store the String variable with put(), because EEPROM library does not support String class. Convert it to the char array first.

1 Like

Better, use char arrays for everything and don't use Strings at all.

2 Likes

Repeat to yourself. I will never, ever, name my function the same as a library function. Ever. It is simply not necessary to add this layer of obfuscation.
Others may have a different opinion. Confusion will reign supreme. It just isn't necessary at the beginner, intermediate, or senior level. Let the geeks play with that, it's what they get paid for.
C
And yes, before anyone screams, I do get the difference between the dot and the underscore. But this makes code much more difficult to read.

I think you are over-reacting in this case about the name

what's really wrong is the use of a global variable rather than a parameter to the function :slight_smile:

it fooled me but I'm relatively easy to fool

Thank you for everyone who has responded.

Sorry for the confusion, I will change it as soon as my problem has a fix.
By the way, How do we convert the string received from the serial to char array?
For example the string received from serial probably like FD98D84F2BC6C0C6A145 (no fix length).

Thank you.

That's another issue, but you and I are just triggered differently. That would be my second trigger.

me too, it's why I'm sensitive to it... I hate traps that are built into the code like this - I build enough of my own that aren't that obvious!
C

Making the change to the code.

Have your tried your code with a power cycle to see what you think is saved to the eeprom is indeed there.

As previously said, you can not save a String object to eeprom.

Without the power cycle, the saved pointer to the String objects address will still point at the underlying String and it will look like it is being read from EEPROM when it is not.

Hi Cattledog,

Yup, I do power cycle.

This code has two section, one is write to EEPROM and another one is read from EEPROM.
I load the Write code to the Arduino, the code will save the string received from Serial to EEPROM.
After that I load the read code to the Arduino again, and use to read the string store before from EEPROM.

Thank you.

Might be simpler to write one code, and use an #ifdef or a flag variable to incorporate writing or reading. That allows you to see the two portions of the code within one context. Admittedly, either approach will work.
C

I think you should be very careful. As @cattledog has said... EEPROM.put/get are not intended to be used with Strings... you may get some very odd results.

Try the following simple example... the result might surprise you.

#include <EEPROM.h>

String str1  = "abcde";
String str2  = "fghij";

void setup()
{
  Serial.begin(115200);

  EEPROM.put(0, str1);
  
  str1 = "12345"; // This should not impact the value stored in the EEPROM ... should it ???
  
  EEPROM.get(0, str2);

  Serial.println(str2);
}


void loop()
{}

I certainly don't confirm your results with a power cycle between the two pieces of code.

Initialize complete...
Please input command:
save_strings
Please input the string:
User String: Does this String object get stored in EEPROM
Written string to EEPROM...

Initialize complete...
Please input command:
read_strings
Read User String from EEPROM: ⸮⸮_T⸮se⸮+⸮}/⸮ϟ⸮⸮⸮⸮}⸮⸮⸮⸮⸮Mu⸮⸮⸮⸮⸮f羥⸮[⸮⸮⸮⸮

If we really want to store C strings (char const* and char*) and String objects, perhaps something like the following is an option.

class MyEEPROM : public EEPROMClass {
public:
  using EEPROMClass::put;
  using EEPROMClass::get;

  char const* put(int idx, char const* data) {
    size_t i;
    for (i = 0; data[i]; i++) {
      put(idx + i, data[i]);
    }
    put(idx + i, '\x00');
    return data;
  }

  char* put(int idx, char* data) {
    return put(idx, const_cast<char const*>(data));
  }

  String& put(int idx, String& data) {
    put(idx, data.c_str());
    return data;
  }

  String& get(int idx, String& data) {
    data = "";
    char c;
    for (size_t i = idx; (c = get(i, c)); i++) {
      data += c;
    }
    return data;
  }
};

Usage:

MyEEPROM myEEPROM;

// ...

char const* ccStr = "abc";
myEEPROM.put(0, ccStr);
char* cStr = const_cast<char*>("def");
myEEPROM.put(5, cStr);
String sStr = "ghi";
myEEPROM.put(10, sStr);

// ...

char cStr[10];
Serial.println(myEEPROM.get(0, cStr));   // Prints "abc".
Serial.println(myEEPROM.get(5, cStr));   // Prints "def".
Serial.println(myEEPROM.get(10, cStr));  // Prints "ghi".
String sStr;
Serial.println(myEEPROM.get(0, sStr));   // Prints "abc".
Serial.println(myEEPROM.get(5, sStr));   // Prints "def".
Serial.println(myEEPROM.get(10, sStr));  // Prints "ghi".

// ...

// Verification, prints "abcÿdefÿghiÿ" (and three invisible characters).
for (size_t i = 0; i < 15; i++) {
  Serial.print(static_cast<char>(myEEPROM.read(i)));
}