Save changes into SD

Hi everyone.
I'm working on a personal project that controls users access trought a Keypad, each user have a code and I declared it like this:

char user1[]="67202";
char user2[]="62601";
char user3[]="60920";

Then if my arduino received an external order to delete any user or create a new one it works, no problem on that. So if i delete the 67202 (user1) and i try to introduce this code trough the keypad my program return "Incorrect code".

if(strcmp(baja, user1) == 0){user1[0]='b';} //baja is a string with the user code i want to delete
        else if(strcmp(baja, user2) == 0){user2[0]='b';}
        else if(strcmp(baja, user3) == 0){user3[0]='b';}
// alta is the code of the new user, so i check my list and when i find a deleted user, overwrites it with the new code.
        if(user1[0]=='b'){user1[0]=alta[0],user1[1]=alta[1],user1[2]=alta[2],user1[3]=alta[3],user1[4]=alta[4];}
        else if(user2[0]=='b'){user2[0]=alta[0],user2[1]=alta[1],user2[2]=alta[2],user2[3]=alta[3],user2[4]=alta[4];}
        else if(user3[0]=='b'){user3[0]=alta[0],user3[1]=alta[1],user3[2]=alta[2],user3[3]=alta[3],user3[4]=alta[4];}

Where I have the problem is when I turn off the arduino power cause I have to store changes into a non-volatil memory. I've been reading this past days about SD card options. Actually I bought an SD shield and i try some library SD.h example that works perfectly.
I want to save my users list in to the SD, so I can read it when my program starts and if there is any change (some user is deleted or just i add a new one) save it before the arduino turn off.But if i have my users list save in to a txt file, how can i use it as arrays like i'm doing right now that i have it write in the flash memory??
I hope i explain my problem well cause my english could be not good enough.
Thanks so much for you time!

aaarrgghh!! :smiley:

You should first try to implement code that manages an "array of c-strings".

use a bidimensional array, e.g.:

char users[MAX_USERS][MAX_USERID_LEN];

But I see you're storing numbers, although represented as c strings. Have you considered using unsigned longs ?

Hi tuxduino thanks a lot for your answer :slight_smile:

yep that was the same thing i was thinking while writing the code (aaarghhhh XD)

So you suggest to use a bidimensional array like "listuser[number of user][user code]"

I save the users list on a txt file in to the SD memory and delete from the arduino flash memory. The when the program starts again it's going to read the txt file with all the user, but is the arduino capable to recognize and rewrite or delete users like before when all the users were written in the flash memory?? That is my biggest question. Then before the arduino turn off i have to save the txt again in to the SD with all the changes made.

Thanks again!

Yes, a bidimensional array like you say is one good solution. As I said, if all your user codes are numeric, you can save memory and simplify code by using unsinged longs (or unsigned ints if a user code is not going to be greater than 65535). Conversion to/from string form at save/load time can be handled easily with standard functions.

But I think we're mixing different functional requirements here: save/load the user list to/from sd card and manage the user list (add, delete, list users).

Each of these actions should be performed by its own specific function. IMHO the user list can be a global variable that every function accesses.

My suggestion is to first learn how to manage the main data structure, i.e. implement list users (e.g. using Serial.println()s) add user, delete user. Save to sd and load from sd should not be too difficult at that point

Hi tuxduino.

I tried to read the SD file and write on it and works perfectly. I use this code to read:

  if(!SD.begin(CS)){
    Serial.println("Tarjeta SD en mal estado");
    return;
  }
  Serial.println("Tarjeta OK");
       dataFile=SD.open("user.txt",FILE_READ);
    // read from the file until there's nothing else in it:
    while ( dataFile.available()) {
    	Serial.write(dataFile.read());
    }

And this is what I see in the Serial:

Tarjeta OK
char user1[]=67202;
char user2[]=62601;
char user3[]=60920;
char user4[]=61014;
Introduce PIN:

But the program did not recognize these arrays so If I enter the "67202" code it returns me an error.Maybe I have to extract the data from the SD byte to byte or something...I'm still trying thing and looking for information on internet with out results by now.

Thanks again for your time mate!

I'm still trying thing and looking for information on internet with out results by now.

Two possible avenues to explore. One would be to take your snippets over to snippets-r-us.com. The other, and this is far more likely to prove useful, is to post ALL of your code here.

We can see from that snippet and output that you can read the card correctly, but no where do you actually save that data in arrays or anywhere where you can compare input to.

Why the failure to compare serial data to card data happens is a mystery because you didn't post that code.

So there were the contents of the file:

char user1[]=67202;
char user2[]=62601;
char user3[]=60920;
char user4[]=61014;

right ?

You were not expecting Arduino to include a C-parser, did you ? :slight_smile:

I'd put one number on each line and write a function that would look more or less like this:

declare char readBuffer
declare int cnt=0

read one byte from file
if no more bytes, return
if the byte is CR or LF
readBuffer[cnt] =0
parse readBuffer to an integer, and store that as a new user id into the user ids array
else
store the byte in readBuffer
cnt++
endif

Hi guys thanks for your help.

Right now i made a smaller program just to learn how to use SD properly. I have a txt file in the Sd (user.txt) with 4 users codes. For now i im trying to save it like: user[1]=67202....user[4]61014 but ir doesn't work. The serial shows user[1]=59, user[2]=59, user[3]=59,user[4]=59. Here is my code.

67202
62601
60920
61014

#include <String.h>
#include <SD.h>

int CS=53;
String dataString;
File dataFile;

int i=1;

unsigned long dato;
unsigned long user[100];

void setup(){
  Serial.begin(115200);
  Serial.println("Initiating SD");
  pinMode(CS, OUTPUT);
  if(!SD.begin(CS)){
    Serial.println("SD failed");
    return;
  }
  Serial.println("SD OK");
  leerSD();
}
  
void leerSD(){
  Serial.println("Reading SD...");
  dato=0;
  dataFile=SD.open("user.txt",FILE_READ);
    // read from the file until there's nothing else in it:
    while (dataFile.available()&& dataFile.peek() != '\n'){
      Serial.write(dataFile.read()); 
      delay(50);
    }
      asignauser();
 }

void asignauser(){
        if(i<=4){
        user[i]=dataFile.read();
        Serial.print("The user");
        Serial.print(i);
        Serial.print("is:");
        Serial.println(user[i]);
        i++;
        leerSD();
        }
        loop();
}

void loop(){
}

Many thanks!!

This one is better, but still not works...

#include <String.h>
#include <SD.h>

int CS=53;
String dataString;
File dataFile;

int i=1;

unsigned long dato;
unsigned long user[100];

void setup(){
  Serial.begin(115200);
  Serial.println("Initiating SD");
  pinMode(CS, OUTPUT);
  if(!SD.begin(CS)){
    Serial.println("SD failed");
    return;
  }
  Serial.println("SD OK");
  openSD();
}
  
void openSD(){
  Serial.println("Reading SD...");
  dato=0;
  dataFile=SD.open("user.txt",FILE_READ);
  readSD();
}

void readSD(){
    while (dataFile.available() && dataFile.peek() != '\n'){
      Serial.write(dataFile.read());
      delay(50);
    }
    asignauser();
}
    
void asignauser(){
    if(i<=4){
      user[i]=dataFile.read();
      Serial.print("The user ");
      Serial.print(i);
      Serial.print(" is:");
      Serial.println(user[i]);
      i++;
      readSD();
    }
}

The serial returns me this:

Initiating SD
SD OK
Reading SD...
67202 The user 1 is:10
62601 The user 2 is:10
60920 The user 3 is:10
61014 The user 4 is:4294967295[/b]

Obviously it hast to be --> user 1 is:67202...etc

This one is better, but still not works...

Better how? Still not works how?

Recursive calls are not a good idea.

dataFile.read() returns ONE character, not the rest of the record.

So, how must be done to return every single character before "\n"?? Thats what i'm looking for. When the program reads:Serial.write(dataFile.read());
Print all the characters not just one...

Thanks PaulS!

Some pseudocode to get you started:

char buffer[BUFLEN];
int cnt = 0;

ch = read one byte from file
if it's \n, then
    buffer[cnt]=0
    do something with buffer
    cnt=0
else
    if (cnt < BUFLEN-1) then
        buffer[cnt] = ch
        cnt++
    endif
endif

When the program reads:
Code:

Serial.write(dataFile.read());

Print all the characters not just one...

Change that to Serial.println() and see what happens.

Hi guys,

First of all thanks for your replies. I'm a total amateur with this so i can find a solution. Cause i'm running out of time i'. gonna try to find other way instead of the SD card. I think the EEPROM can be a good option too. Right now i have a code to learn how to use EEPROM but im going to open a new topic cause i don't want to mix things in the forum.

Thanks a lot.