How to save data to EEPROM

Hello, I'm making a automatic gate using RFID reader. Here I have used EEPROM to save the RFID tag numbers. I want to add new RFID tag number to EEPROM If the number is not in the EEPROM. I tried many ways but nothing worked. Can anyone give me a solution for this. My code is as follows.

#include <SPI.h>
#include <MFRC522.h>
#include <Servo.h>
#include <EEPROM.h>
#include <SafeString.h>

#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance.

int readsuccess;
byte readcard[4];
char str[32] = "";
String StrUID;
String temp = "";

boolean granted = false;


char myTags[][9] = {};
char reloadedTags[sizeof(myTags) / sizeof(myTags[0])][9];


Servo gate;
int pos = 0;

//---------------------------------------------------------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600); // Initialize serial communications with the PC
  SPI.begin();      // Init SPI bus
  mfrc522.PCD_Init(); // Init MFRC522 card
  gate.attach(8);
  gate.write(0);
  
  //write_Tag();
//    eeprom_clear();
}
// ------------------------------------------------------------------------------------------------------------------------------
void loop() {
  readsuccess = getid();
  if (readsuccess) {
    Serial.println(StrUID);
    checkAccess (StrUID);
    add(StrUID);
  }

}


// -------------------------------------------------------------------------------------------------------------------------------
int getid() {
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return 0;
  }
  if (!mfrc522.PICC_ReadCardSerial()) {
    return 0;
  }
  for (int i = 0; i < 4; i++) {
    readcard[i] = mfrc522.uid.uidByte[i]; //storing the UID of the tag in readcard
    array_to_string(readcard, 4, str);
    StrUID = str;
  }
  mfrc522.PICC_HaltA();
  return 1;
}
// ------------------------------------------------------------------------------------------------------------------------------
void array_to_string(byte array[], unsigned int len, char buffer[]) {
  for (unsigned int i = 0; i < len; i++) {
    byte nib1 = (array[i] >> 4) & 0x0F;
    byte nib2 = (array[i] >> 0) & 0x0F;
    buffer[i * 2 + 0] = nib1  < 0xA ? '0' + nib1  : 'A' + nib1  - 0xA;
    buffer[i * 2 + 1] = nib2  < 0xA ? '0' + nib2  : 'A' + nib2  - 0xA;
  }
  buffer[len * 2] = '\0';
}

// -------------------------------------------------------------------------------------------------------------------------------
void checkAccess (String StrUID) {            //Function to check if an identified tag is registered to allow access

  while (!Serial);
  EEPROM.get(0, reloadedTags);

  for (int tag = 0; tag < (sizeof(myTags) / sizeof(myTags[0])); tag++) {
    for (int c = 0; c < 8; c++) {
      temp += reloadedTags[tag][c];
    }
    
    //Serial.println(temp);
    if (temp == StrUID) {
      //Serial.println("found");
      open();
      granted = true;
    }
    else{
      granted = false;
      delay(500);
      }
    temp = "";
  }
 return granted;
 Serial.println("false");
}
//-------------------------------------------------------------------------------------------------------------------------------------
void open() {
  int pos = 0;
  for (pos = 0; pos <= 90; pos += 1) {
    gate.write(pos);
  }
  delay(2000);

  for (pos = 90; pos >= 0; pos -= 1) {
    gate.write(pos);
  }
}

//---------------------------------------------------------------------------------------------------------------------------------
void write_Tag() {
  while (!Serial);
  EEPROM.put(0, myTags);
}
//------------------------------------------------------------------------------------------------------------------------------------

void eeprom_clear() {
  while (!Serial);
  EEPROM.put(0, 0);
}
//----------------------------------------------------------------------------------------------------------------------------------

void add(String StrUID) {

  if(granted==false){

  createSafeStringFromCharPtrWithSize(myTags4, myTags[sizeof(myTags) / sizeof(myTags[0])], 9);
  myTags4 = StrUID.c_str();
  //Serial.println(myTags4);
//  while (!Serial); 
//   EEPROM.put(0, myTags);
//   delay(100);
//    EEPROM.put(0, myTags);
 for (int i = 0; i <sizeof(myTags) / sizeof(myTags[0])+1; i++) { 
   for (int j = 0; j < 8; j++) { 
    Serial.print(myTags[i][j]);
      //EEPROM.put(0, myTags);
   } 
   Serial.println("");
}
  
}
}

The add function is used to save the data to EEPROM if it is unavailable. Reading from the EEPROM and comparing with the current RFID number works fine. the problem is with the updating the EEPROM. Please help me on this.

why do you care using SafeString at all if you use the String class and also cstrings in your array_to_string() function ?? :o

Why do you want to store the ASCII representation in EEPROM when you have 4 perfect bytes that represent your card?

if you plan to have a finite number of tags you can deal with, the easiest way to do it is to create an array of 4 bytes structures (either a uint32_t or duplicate the format of mfrc522.uid.uidByte (10 bytes)) and put/get that array from EEPROM. adding a tag would just be finding an empty slot and storing the 4 bytes there.

char myTags[][9] = {};

This declares an array with no columns and 9 rows

Is that what you meant to do ?

Have you tried printing the result of

 Serial.println(sizeof(myTags) / sizeof(myTags[0]));

JML can you please give me an example for that.

J-M-L:
why do you care using SafeString at all if you use the String class and also cstrings in your array_to_string() function ?? :o

Why do you want to store the ASCII representation in EEPROM when you have 4 perfect bytes that represent your card?

if you plan to have a finite number of tags you can deal with, the easiest way to do it is to create an array of 4 bytes structures (either a uint32_t or duplicate the format of mfrc522.uid.uidByte (10 bytes)) and put/get that array from EEPROM. adding a tag would just be finding an empty slot and storing the 4 bytes there.

UKHeliBob, I wrote it like that because the number of tags that will be saved is unknown. Is that a wrong way.
I tried printing the size of the array and it gave me the size correctly. won't that will work in here.

I wrote it like that because the number of tags that will be saved is unknown. Is that a wrong way.

Yes.

You cannot expand the size of an array when the code is running. You must declare the array with the maximum number of rows and columns that you will use and in the program check that you never exceed those numbers. Otherwise you will be writing outside of the bounds of the array which will change the value of memory locations that are not part of it

The reason why you can leave the entry blank for the first element of an array when you define it is that the compiler can work out what the value should be from the defined data. You are defining no data when you declare the array, hence no memory is allocated to the array

chamodmelaka:
JML can you please give me an example for that.

Typed here, totally untested, just to give you some ideas. I removed your servo stuff

#include <MFRC522.h>
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance.

const byte cardIdSize = 4;

struct tCard {
  byte id[cardIdSize];
};


#include <EEPROM.h>
const uint32_t magicKey = 0xBADCAFE; // likelyhood of this being in EEPROM is very low


const byte maxCards = 10;
struct tSavedInEEPROM
{
  uint32_t sentinel; // will be our magicKey if memory already set otherwise don't assume it's correct
  tCard knownCards[maxCards];
} parameters;

unsigned int eepromStartAddress = 0; //EEPROM address to start reading from

void storeParametersInEEPROM()
{
  parameters.sentinel = magicKey;             // ensure we have the magic key set up
  EEPROM.put(eepromStartAddress, parameters); // save the current parameters
}

void initParameters()
{
  // Read EEPROM memory to initialize our parameters
  EEPROM.get(eepromStartAddress, parameters);

  // verify if we read garbage or good data
  if (parameters.sentinel != magicKey) {
    // data in memory is likely not good, initialize our data structure with defaut values
    for (byte c = 0; c < maxCards; c++)
      for (byte i = 0; i < cardIdSize; i++)
        parameters.knownCards[c].id[i] = 0;
    // and store it in memory for next time
    storeParametersInEEPROM();
  }
}

void printlnCard(tCard & aCard)
{
  for (int i = 0; i < cardIdSize; i++) {
    if (aCard.id[i] < 0xF) Serial.write('0');
    Serial.print(aCard.id[i], HEX);
    if (i != cardIdSize - 1) Serial.write(':');
  }
  Serial.println();
}

bool cardIsKnown(tCard & aCard)
{
  bool foundCard = false;
  // go through the parameters.knownCards array and check for a match

  return foundCard;
}

bool addCard(tCard & aCard)
{
  bool roomAvailable = false;

  // go through the parameters.knownCards array and check for an empty slot, if so set roomAvailable to true
  // copy card data in there
  // call storeParametersInEEPROM();

  return roomAvailable;
}

bool gotCard(tCard & aCard)
{
  if (!mfrc522.PICC_IsNewCardPresent()) return false;
  if (!mfrc522.PICC_ReadCardSerial()) return false;

  for (int i = 0; i < cardIdSize; i++) {
    aCard.id[i] = mfrc522.uid.uidByte[i]; //storing the UID of the tag in readcard
  }
  mfrc522.PICC_HaltA();
  return true;
}

void setup() {
  Serial.begin(115200); // Initialize serial communications with the PC
  SPI.begin();      // Init SPI bus
  mfrc522.PCD_Init(); // Init MFRC522 card
  initParameters();
}

void loop() {
  tCard card;
  if (gotCard(card)) {
    printlnCard(card);
    if (cardIsKnown(card)) {
      Serial.println(F("Card already registered"));
    } else {
      Serial.println(F("Card unknown, registering"));
      if (addCard(card)) {
        Serial.println(F("Card Added"));
      } else {
        Serial.println(F("No space left"));
      }
    }
  }
}

the idea is that you have a structure tSavedInEEPROM holding all the possible cards (you need to define a maximum) in RAM and this is the structure you read or write to EEPROM using get() and put().
There is a slight trick, the first time you'll boot this code the EEPROM won't be initialized with good data and you don't want to read garbage into the structure. That's the purpose of the magicKey (sentinel). If you find it at the start of the EEPROM, then you can assume that what's next is indeed correct, if not you initialize your known cards to "empty" and store that in EEPROM for next time.

there are a couple functions I left for you to write which should not be rocket science

bool cardIsKnown(tCard & aCard)
{
  bool foundCard = false;
  // go through the parameters.knownCards array and check for a match

  return foundCard;
}

bool addCard(tCard & aCard)
{
  bool roomAvailable = false;

  // go through the parameters.knownCards array and check for an empty slot, if so set roomAvailable to true
  // copy card data in there
  // call storeParametersInEEPROM();

  return roomAvailable;
}

of course that assumes you know the max number of cards and are OK to have SRAM allocated for all of those. If you want to only deal with stuff in EEPROM, you need to save in EEPROM the number of know cards and scan EEPROM 4 bytes by 4 bytes to find if a card exists and if you don't find it, increase by one th number of cards, save that back to EEPROM, and save at the end of the list the next 4 bytes.

Thank you JML. I'll try this

J-M-L:
Typed here, totally untested, just to give you some ideas. I removed your servo stuff

#include <MFRC522.h>

#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance.

const byte cardIdSize = 4;

struct tCard {
 byte id[cardIdSize];
};

#include <EEPROM.h>
const uint32_t magicKey = 0xBADCAFE; // likelyhood of this being in EEPROM is very low

const byte maxCards = 10;
struct tSavedInEEPROM
{
 uint32_t sentinel; // will be our magicKey if memory already set otherwise don't assume it's correct
 tCard knownCards[maxCards];
} parameters;

unsigned int eepromStartAddress = 0; //EEPROM address to start reading from

void storeParametersInEEPROM()
{
 parameters.sentinel = magicKey;             // ensure we have the magic key set up
 EEPROM.put(eepromStartAddress, parameters); // save the current parameters
}

void initParameters()
{
 // Read EEPROM memory to initialize our parameters
 EEPROM.get(eepromStartAddress, parameters);

// verify if we read garbage or good data
 if (parameters.sentinel != magicKey) {
   // data in memory is likely not good, initialize our data structure with defaut values
   for (byte c = 0; c < maxCards; c++)
     for (byte i = 0; i < cardIdSize; i++)
       parameters.knownCards[c].id[i] = 0;
   // and store it in memory for next time
   storeParametersInEEPROM();
 }
}

void printlnCard(tCard & aCard)
{
 for (int i = 0; i < cardIdSize; i++) {
   if (aCard.id[i] < 0xF) Serial.write('0');
   Serial.print(aCard.id[i], HEX);
   if (i != cardIdSize - 1) Serial.write(':');
 }
 Serial.println();
}

bool cardIsKnown(tCard & aCard)
{
 bool foundCard = false;
 // go through the parameters.knownCards array and check for a match

return foundCard;
}

bool addCard(tCard & aCard)
{
 bool roomAvailable = false;

// go through the parameters.knownCards array and check for an empty slot, if so set roomAvailable to true
 // copy card data in there
 // call storeParametersInEEPROM();

return roomAvailable;
}

bool gotCard(tCard & aCard)
{
 if (!mfrc522.PICC_IsNewCardPresent()) return false;
 if (!mfrc522.PICC_ReadCardSerial()) return false;

for (int i = 0; i < cardIdSize; i++) {
   aCard.id[i] = mfrc522.uid.uidByte[i]; //storing the UID of the tag in readcard
 }
 mfrc522.PICC_HaltA();
 return true;
}

void setup() {
 Serial.begin(115200); // Initialize serial communications with the PC
 SPI.begin();      // Init SPI bus
 mfrc522.PCD_Init(); // Init MFRC522 card
 initParameters();
}

void loop() {
 tCard card;
 if (gotCard(card)) {
   printlnCard(card);
   if (cardIsKnown(card)) {
     Serial.println(F("Card already registered"));
   } else {
     Serial.println(F("Card unknown, registering"));
     if (addCard(card)) {
       Serial.println(F("Card Added"));
     } else {
       Serial.println(F("No space left"));
     }
   }
 }
}



the idea is that you have a structure tSavedInEEPROM holding all the possible cards (you need to define a maximum) in RAM and this is the structure you read or write to EEPROM using get() and put().
There is a slight trick, the first time you'll boot this code the EEPROM won't be initialized with good data and you don't want to read garbage into the structure. That's the purpose of the magicKey (sentinel). If you find it at the start of the EEPROM, then you can assume that what's next is indeed correct, if not you initialize your known cards to "empty" and store that in EEPROM for next time.

there are a couple functions I left for you to write which should not be rocket science 


bool cardIsKnown(tCard & aCard)
{
 bool foundCard = false;
 // go through the parameters.knownCards array and check for a match

return foundCard;
}

bool addCard(tCard & aCard)
{
 bool roomAvailable = false;

// go through the parameters.knownCards array and check for an empty slot, if so set roomAvailable to true
 // copy card data in there
 // call storeParametersInEEPROM();

return roomAvailable;
}





of course that assumes you know the max number of cards and are OK to have SRAM allocated for all of those. If you want to only deal with stuff in EEPROM, you need to save in EEPROM the number of know cards and scan EEPROM 4 bytes by 4 bytes to find if a card exists and if you don't find it, increase by one th number of cards, save that back to EEPROM, and save at the end of the list the next 4 bytes.

Thank you UK HeliBob. I'll do like that.

UKHeliBob:
Yes.

You cannot expand the size of an array when the code is running. You must declare the array with the maximum number of rows and columns that you will use and in the program check that you never exceed those numbers. Otherwise you will be writing outside of the bounds of the array which will change the value of memory locations that are not part of it

The reason why you can leave the entry blank for the first element of an array when you define it is that the compiler can work out what the value should be from the defined data. You are defining no data when you declare the array, hence no memory is allocated to the array

Hey JML, I tried your code. Actually I'm not very much clever in Arduino coding. The code works perfectly. this is what i wrote for cardIsKnown function. This works fine.

bool cardIsKnown(tCard & aCard){
  bool foundCard = false;
  for (int a = 0; a < maxCards; a++){
      for (int b = 0; b < cardIdSize; b++){
        if(parameters.knownCards[a].id[b] == aCard.id[b]) {
        foundCard= true;
        }
      }  
  }
  return foundCard;
}

I wrote the addCard function but I was unable to check for an empty slot. Without that the code works perfectly. can you explain me how to check for the empty slot.

bool addCard(tCard & aCard){
  bool roomAvailable = true;

 for (byte x = 0; x < maxCards; x++){
      for (byte y = 0; y < cardIdSize; y++){
        parameters.knownCards[x].id[y] = aCard.id[y];
}
 storeParametersInEEPROM();
 //roomAvailable = true;

  return roomAvailable;
}

Can you tell me how to check for an empty slot in the array.

Slot x is an empty slot is if the 4 bytes in parameters.knownCards[x].id[0..3] are at zero.

Your cardIsKnown function does not really work. You have a match If the 4 bytes are identical (and then no need to continue reading the array)

JML, How about this code for the addCard function. I tested it and it worked. Is this have errors.

bool addCard(tCard & aCard){
  bool roomAvailable = false;
  int temp=0;
  
  for (int x = 0; x < maxCards; x++){
    for (int y = 0; y < cardIdSize; y++){
      if(parameters.knownCards[x].id[y] == 0){
         temp+=1;
     }   
    }
      if(temp==4){
        roomAvailable = true;
        parameters.knownCards[x]=aCard;
        storeParametersInEEPROM();
        break;
      }
   }       
  return roomAvailable;
}

Your cardIsKnown function does not really work. You have a match If the 4 bytes are identical (and then no need to continue reading the array)

Isn't that code will work?

This is getting close, don’t forget to reset temp to 0 each time you go compare the next entry otherwise you’ll be impacted by previous count. And once you find one, leave the for loop and handle it there. Something like

For each card
  Set temp counter to 0
  For each byte in the ID of that card
   If it is 0 no need to continue for that card
   Else increase temp counter
  If temp counter for this card is cardIdSize then found the card, break the search
  Else set temp counter to 0 and go to next card

If card found, deal with it

Also don’t test against 4, use cardIdSize. It will be cleaner.

Thanks JML and all others for the help. Now it is working well.

#include <MFRC522.h>
#include <EEPROM.h>
#include <Servo.h>

#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance.

const byte cardIdSize = 4;

struct tCard {
  byte id[cardIdSize];
};



const uint32_t magicKey = 0xBADCAFE; // likelyhood of this being in EEPROM is very low


const byte maxCards = 10;
struct tSavedInEEPROM
{
  uint32_t sentinel; // will be our magicKey if memory already set otherwise don't assume it's correct
  tCard knownCards[maxCards];
} parameters;

unsigned int eepromStartAddress = 0; //EEPROM address to start reading from

Servo gate;

void setup() {
  Serial.begin(9600); // Initialize serial communications with the PC
  SPI.begin();      // Init SPI bus
  mfrc522.PCD_Init(); // Init MFRC522 card
  initParameters();

  gate.attach(8);
  gate.write(0);
}

void loop() {
  tCard card;
  if (gotCard(card)) {
    printlnCard(card);
    if (cardIsKnown(card)) {
      //Serial.println(F("Card already registered"));
      open();
    } 
    else {
      addCard(card);
    }
  }
}

void storeParametersInEEPROM(){
  parameters.sentinel = magicKey;             // ensure we have the magic key set up
  EEPROM.put(eepromStartAddress, parameters); // save the current parameters
}

void initParameters(){
  // Read EEPROM memory to initialize our parameters
  EEPROM.get(eepromStartAddress, parameters);

  // verify if we read garbage or good data
  if (parameters.sentinel != magicKey) {
    // data in memory is likely not good, initialize our data structure with defaut values
    for (byte c = 0; c < maxCards; c++)
      for (byte i = 0; i < cardIdSize; i++)
        parameters.knownCards[c].id[i] = 0;
    // and store it in memory for next time
    storeParametersInEEPROM();
  }
}

void printlnCard(tCard & aCard){
  for (int i = 0; i < cardIdSize; i++) {
    if (aCard.id[i] < 0xF) 
    Serial.write('0');
    Serial.print(aCard.id[i], HEX);
    //if (i != cardIdSize - 1) 
   // Serial.write(':');
  }
  Serial.println();
}

bool cardIsKnown(tCard & aCard){
  bool foundCard = false;
  for (int a = 0; a < maxCards; a++){
      for (int b = 0; b < cardIdSize; b++){
        if(parameters.knownCards[a].id[b] == aCard.id[b]) {
        foundCard= true;
        }
      }  
  }
  return foundCard;
}

bool addCard(tCard & aCard){
  bool roomAvailable = false;
  int temp=0;
  while(Serial.available() > 0 ){
    String str = Serial.readString();
    if(str.indexOf("save") > -1){
     for (int x = 0; x < maxCards; x++){
        for (int y = 0; y < cardIdSize; y++){
          if(parameters.knownCards[x].id[y] == 0){
           temp+=1;
          }    
        }
        if(temp==cardIdSize){
          roomAvailable = true;
          parameters.knownCards[x]=aCard;
          storeParametersInEEPROM();
          break;
        }
        else{
          temp=0;
        }
     }
    }       
  }   
return roomAvailable;
}

bool gotCard(tCard & aCard){
  if (!mfrc522.PICC_IsNewCardPresent()) return false;
  if (!mfrc522.PICC_ReadCardSerial()) return false;

  for (int i = 0; i < cardIdSize; i++) {
    aCard.id[i] = mfrc522.uid.uidByte[i]; //storing the UID of the tag in readcard
  }
  mfrc522.PICC_HaltA();
  return true;
}

void open() {
  int pos = 0;
  for (pos = 0; pos <= 90; pos += 1) {
    gate.write(pos);
  }
  delay(2000);

  for (pos = 90; pos >= 0; pos -= 1) {
    gate.write(pos);
  }
}

JML one more thing. Can you explain me this line. Why both (tCard & aCard) is there?

bool gotCard(tCard & aCard){

What it is you don’t understand, it’s just a parameter to a function.

Here You pass a card type as parameter (by reference, hence the &) to the function and the function uses this to compare to the known cards.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.