Sunday, April 8, 2018

Arduino - writing and reading a string to/from EEPROM



In my rigs that use an Arduino for control, I like to take advantage of the on-board EEPROM to save the last-used frequency (and other info) so that it's retained over a power cycle.  I didn't do this on my first couple of rigs, and having them power-up to "default" settings bothered me; we're well into the second decade of the 21st century, so why build something that acts like it's from 1980? 

With rigs using the Si5351, this was fairly simple because the frequency data is in long integer format.  With the NiceRF 818 modules I'm using in the Shack in the Box, however, the data is stored as string variables that get passed from the Arduino to the modules as part of a longer AT command string thats sent over a serial connection.

So, what I did was write functions to break each string up, byte by byte, and store the integer value of each byte (they're in ASCII otherwise) to EEPROM. Likewise, reading is done one byte at a time, and each byte is concatenated (fancy way to say appended) to a string holding the "reassembled" data word.

Since others may find this helpful, below is a sketch that writes the string "0123" to the first four slots in EEPROM, then reads and reassembles it back into another string, displaying each step in the Arduino IDE's Serial Monitor as it progresses.

One thing worth mentioning is that the EEPROM has a finite number of write cycles before it gives-up the ghost.  In a rig where you only write to it at power down (or, in the case of the SITB, when storing a VFO to memory), this should never be an issue, but you have to be careful when writing your sketch not to put EEPROM.writes in a loop, else you could burn it up fairly rapidly.  That's the purpose of the "flag" variable in my example sketch:  After one write/read cycle, the flag is set and the loop won't call to the write function until the next reboot.

Anyway, here's the sketch:

/*
   Sketch writing and reading a 4 byte STRING of numerals to/from EEPROM, then printing them in the serial monitor.
*/

#include<EEPROM.h>                                                      // Include EEPROM library

String TestString = "0123";                                             // Declare string variable to be input to sketch.
int addr;                                                               // Declare variable to store EEPROM address.
int flag = 0;                                                           // Declare variable used as a flag to signal loop after write/read cycle completes
String OutputString = "";                                               // Declare string variable to store output from sketch.

void writeeeprom()                                                      // Function to write 4 bytes to EEPROM:
{
  Serial.print(F("TestString = "));                                     // Print input string (TestString) to serial monitor
  Serial.println(TestString);
  for (addr = 0; addr <= 3; addr++)                                     // While addr = 0 to 3, incrementing by 1 each iteration...
  {
    Serial.print(F("In Loop, writing "));                               // ...Print byte being written to serial monitor...
    Serial.print(TestString.charAt(addr));                              //
    Serial.print(F(" To EEPROM Address "));                             // ...Print the address being written to to the serial monitor...
    Serial.println(addr);
    EEPROM.write(addr, (TestString.charAt(addr) - 48));                 // ...The byte will be the ASCII value of the number, convert it to its integer
  }//                                                                   // ...value and write it to the EEPROM.
  Serial.println(F("String written to EEPROM"));                        // Write message to serial monitor when loop completes.
}

void readeeprom()                                                       // Function to read 4 bytes from EEPROM:
{
  for (addr = 0; addr <= 3; addr++)                                     // While addr = 0 to 3, incrementing by 1 each iteration...
  {
    OutputString += EEPROM.read(addr);                                  // Read byte at 'addr' and append it to OutputString...
    Serial.print(F("In Loop, reading "));                               // ...print the byte being read to the serial monitor...
    Serial.print(EEPROM.read(addr));                                    //
    Serial.print(F(" From EEPROM Address "));                           // ...print the address being read to the serial monitor.
    Serial.println(addr);
  }
  flag = 1;                                                             // Set the flag to indicate that we've written and read all four bytes.
  Serial.print(F("OutputString = "));                                   // Print the reassembled string to the serial monitor.
  Serial.println(OutputString);
}

void setup()
{
  Serial.begin(9600);                                                   // open UART serial port at 9600 bps
}

void loop()
{
  if (flag == 0)                                                        // While the flag = 0
  {
    writeeeprom();                                                      //... write to EEPROM...
    readeeprom();                                                       //... then read from EEPROM
  }
}


And here's what is output to the Serial Monitor:

TestString = 0123
In Loop, writing 0 To EEPROM Address 0
In Loop, writing 1 To EEPROM Address 1
In Loop, writing 2 To EEPROM Address 2
In Loop, writing 3 To EEPROM Address 3
String written to EEPROM
In Loop, reading 0 From EEPROM Address 0
In Loop, reading 1 From EEPROM Address 1
In Loop, reading 2 From EEPROM Address 2
In Loop, reading 3 From EEPROM Address 3
OutputString = 0123