Pages: [1] 2   Go Down
Author Topic: Arduino and SD card help  (Read 1232 times)
0 Members and 1 Guest are viewing this topic.
Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey,

I have a few issues with my program...

I have on it a file called jessica.txt and can read from it fine digit by digit onto the serial monitor but I can't seem to store into a variable correctly.

The file contains

12 01 00 1 0

The code so far is as follows

Code:
#include <SD.h>

const int chipSelect = 4;
int i = 0;

class details
{
  public:
  int hours;
  int mins;
  int secs;
  int pillOne;
  int pillTwo;
};

void setup()
{

  Serial.begin(9600);

  Serial.print("Initializing SD card...");

  pinMode(10, OUTPUT);
 
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");
}


void loop()
{
 
  int num1;
  int num2;
  int num3;
  int num4;
 
  details jessica;
 
  File jessicaFile;
 
  jessicaFile = SD.open("jessica.txt");
  if(jessicaFile)
  {
    while( jessicaFile.available())
    {
     
     
      switch(i)
      {
        case 0:
          jessica.hours = jessicaFile.read();
          break;
        case 1:
          jessica.mins = jessicaFile.read();
          break;
        case 2:
          jessica.secs = jessicaFile.read();
          break;
        case 3:
          jessica.pillOne = jessicaFile.read();
          break;
        case 4:
          jessica.pillTwo = jessicaFile.read();
          break;
        default:
          break;
      }
      i++;
      Serial.write(jessicaFile.read());
     
      delay(1000);
    }
    jessicaFile.close();
  }
  else
  {
    Serial.println("error opening jessica.txt"); 
   
  }
  Serial.println("Hours:");
  Serial.write(jessica.hours);
  Serial.println("\n Minutes:");
  Serial.write(jessica.mins);
  Serial.println("\n Seconds:");
  Serial.write(jessica.secs);
  Serial.println("\n Pill One:");
  Serial.write(jessica.pillOne);
  Serial.println("\n Pill Two");
  Serial.write(jessica.pillTwo);
  Serial.println("\n");
  delay(10000);
}


and i know it shouldn't be all in the loop, just got lazy, and it will eventually be combined with other parts for a project

Thanks for your help!
Logged

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 150
Posts: 6130
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

strtok should be able to parse that for you.
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 642
Posts: 50384
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I have on it a file called jessica.txt and can read from it fine digit by digit onto the serial monitor but I can't seem to store into a variable correctly.
You have some underlying assumptions reflected in your code that are wrong.

Quote
The file contains

12 01 00 1 0
Code:
          jessica.hours = jessicaFile.read();
The hours member of the jessica instance will now contain '1', not 12.

Code:
          jessica.mins = jessicaFile.read();
This will read the '2', not the 01.

You need to learn how to read a complete record (which means you need to understand what a complete record is, specifically when one ends), storing the data in an array (NULL terminated at all times), and then, as SurferTim mentions, use strtok() to parse that array.
Logged

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I have on it a file called jessica.txt and can read from it fine digit by digit onto the serial monitor but I can't seem to store into a variable correctly.
You have some underlying assumptions reflected in your code that are wrong.

You need to learn how to read a complete record (which means you need to understand what a complete record is, specifically when one ends), storing the data in an array (NULL terminated at all times), and then, as SurferTim mentions, use strtok() to parse that array.


Thanks for your condescending help Paul, obviously I am unsure of how to do it, otherwise I wouldn't have asked...

And thanks for the link Tim.

I still can't get it to work, could you see where I have gone wrong?

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

const int chipSelect = 4;
int i = 0;
int a = 0;

class details
{
public:
  int hours;
  int mins;
  int secs;
  int pillOne;
  int pillTwo;
};

char str[12];
char * pch;

void setup()
{

  Serial.begin(9600);

  Serial.print("Initializing SD card...");

  pinMode(10, OUTPUT);

  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");
}


void loop()
{

  details jessica;

  File jessicaFile;

  jessicaFile = SD.open("jessica.txt");
  if(jessicaFile)
  {
    while( jessicaFile.available())
    {
      i++;
      str[i] = jessicaFile.read();
      Serial.write(str[i]);

      delay(1000);
    }
    jessicaFile.close();
  }
  else
  {
    Serial.println("error opening jessica.txt"); 

  }

  pch = strtok(str," ,.-");
  while(pch != NULL)
  {
    Serial.write(pch);
 //   a = atoi(pch);
    pch = strtok(NULL," ,.-");
   
   // Serial.write(a);
    Serial.println("is this working?\n");

  }

  Serial.println("didn't Work!!!");
  delay(10000);

}


Thanks
Logged

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 150
Posts: 6130
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I would try this:
Code:
 jessicaFile = SD.open("jessica.txt");
  if(jessicaFile)
  {
    i = 0;
    while( jessicaFile.available())
    {
      char ch = jessicaFile.read();
      if(i < 11) {
        str[i] = ch;
        Serial.write(str[i]);
        i++;
        str[i] = 0;
      }
    }
    jessicaFile.close();
  }
  else
  {
    Serial.println("error opening jessica.txt");  
  }
Or are you getting a "error opening jessica.txt"?

edit: modified the read so it would read the entire file, even tho after 11 characters it will not store it.
« Last Edit: July 03, 2012, 07:43:04 am by SurferTim » Logged

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is what i have now. And it opens and reads the numbers and prints at the pch serial.write's but not quite sure if what ive done to convert to integers is correct, well i know its not cause it doesn't come out correctly. I've tried subtracting 48, '0', casting... Or maybe im going about it all wrong?

Code:

Thanks for your condescending help Paul, obviously I am unaware of how to do it, otherwise I wouldn't have asked...

I still can't get it to work, could you see where I have gone wrong?

[code]
#include <SD.h>
#include <String.h>

const int chipSelect = 4;
int i = 0;
int a = 0;

class details
{
public:
  int hours;
  int mins;
  int secs;
  int pillOne;
  int pillTwo;
};

char str[12];
char * pch;

void setup()
{

  Serial.begin(9600);

  Serial.print("Initializing SD card...");

  pinMode(10, OUTPUT);

  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");
}


void loop()
{

  details jessica;

  File jessicaFile;

  jessicaFile = SD.open("jessica.txt");
  if(jessicaFile)
  {
    while( jessicaFile.available())
    {
      i++;
      str[i] = jessicaFile.read();
      Serial.write(str[i]);

      delay(1000);
    }
    jessicaFile.close();
  }
  else
  {
    Serial.println("error opening jessica.txt");  

  }

  pch = strtok(str," ,.-");
  while(pch != NULL)
  {
    Serial.write(pch);
 //   a = atoi(pch);
    pch = strtok(NULL," ,.-");
    
   // Serial.write(a);
    Serial.println("is this working?\n");

  }

  Serial.println("didn't Work!!!");
  delay(10000);

}


Thanks[/code]
« Last Edit: July 03, 2012, 08:25:30 am by ballboii » Logged

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 150
Posts: 6130
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Did you see my post above? There are major things wrong.
Code:
  if(jessicaFile)
  {
    // initialize i here

    while( jessicaFile.available())
    {
      // here are two. Increment i after the read, and limit i to (the size of your buffer) - 1
      i++;
      str[i] = jessicaFile.read();
      Serial.write(str[i]);
      // here is another. You should insure the text data is zero terminated.

      // and here is another. Why the delay?
      delay(1000);
    }
    jessicaFile.close();
  }
Logged

0
Offline Offline
Edison Member
*
Karma: 67
Posts: 1658
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Reading files into variables is often easier using the C++ Standard I/O Streams Library.  SdFat implements much of this library.

Here is a sketch that read a line from the jessica.txt file into the details structure, prints the structure, rewinds the file and lists the file as ascii text.

Code:
#include <SdFat.h>
SdFat sd;
const int chipSelect = 4;

class details {
public:
  int hours;
  int mins;
  int secs;
  int pillOne;
  int pillTwo;
};

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

  // SdFat will initialize pin 10, SS, as an output and set it high
  if (!sd.init(SPI_FULL_SPEED, chipSelect)) sd.initErrorHalt();
 
  // open file
  ifstream jessicaFile("jessica.txt");
  if (!jessicaFile.is_open()) {
    Serial.println("open failed");
    return;
  }
  // structure for data
  details jessica;

  // read line
  jessicaFile >> jessica.hours >> jessica.mins >> jessica.secs >> jessica.pillOne >>jessica.pillTwo;

  // check for read error
  if (!jessicaFile) {
    Serial.println("read error");
    return;
  }
  // print result
  Serial.print("Hours: ");
  Serial.println(jessica.hours);
  Serial.print("Minutes: ");
  Serial.println(jessica.mins);
  Serial.print("Seconds: ");
  Serial.println(jessica.secs);
  Serial.print("Pill One: ");
  Serial.println(jessica.pillOne);
  Serial.print("Pill Two: ");
  Serial.println(jessica.pillTwo);
 
  // list the file content
  Serial.println("___________________");
  // rewind the file
  jessicaFile.seekg(0);
  int c;
  // print file
  while ((c = jessicaFile.get()) >= 0) Serial.write(c);
}
void loop() {}

Here is the output from the sketch:
Quote
Hours: 12
Minutes: 1
Seconds: 0
Pill One: 1
Pill Two: 0
______________________
12 01 00 1 0

The SdFat library is here http://code.google.com/p/sdfatlib/downloads/list
Logged

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry Tim,

I posted the wrong code...

Code:

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

const int chipSelect = 4;
int i = 0;
int a = 0;

class details
{
public:
  int hours;
  int mins;
  int secs;
  int pillOne;
  int pillTwo;
};

char str[12];
char * pch;

void setup()
{

  Serial.begin(9600);

  Serial.print("Initializing SD card...");

  pinMode(10, OUTPUT);

  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");
}


void loop()
{

  details jessica;

  File jessicaFile;

  jessicaFile = SD.open("jessica.txt");
  if(jessicaFile)
  {
    i = 0;
    while( jessicaFile.available())
    {
    //  char ch = jessicaFile.read();
      while(i<11)
      {
      str[i] = jessicaFile.read();
      Serial.write(str[i]);
      i++;
      str[i] = 0;
      delay(1000);
      }
    }
    jessicaFile.close();
  }
  else
  {
    Serial.println("error opening jessica.txt"); 

  }
 
  i=0;
  Serial.println("\n");
  pch = strtok(str," ,.-");
  while(pch != NULL)
  {
    switch(i)
    {
      case 0:
        jessica.hours = (int)(pch - 48);
        break;
      case 1:
        jessica.mins = (int) pch;
        break;
      case 2:
        jessica.secs = (int) pch;
        break;
      case 3:
        jessica.pillOne = (int) pch;
        break;
      case 4:
        jessica.pillTwo = (int) pch;
        break;
      default:
        break;
       
    }
    i++;
   
    Serial.write(pch);
 //   a = atoi(pch);
    pch = strtok(NULL," ,.-");
   
   // Serial.write(a);
    Serial.println("is this working?\n");

  }
 
  Serial.write(jessica.hours);
  Serial.write(jessica.mins);

  delay(10000);

}


and using the SDFat library is a cool idea, but i don't really have any idea what is going on there but il look into it.
Logged

0
Offline Offline
Edison Member
*
Karma: 67
Posts: 1658
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Using the C++ I/O streams library can be very powerful but most old-timers and hobbyists don't have the knowledge to effectively use this library so maybe sticking with the simpler Arduino SD API will be best for you.

The Arduino API is a simple wrapper for an old version of SdFat that does not expose I/O streams.

The I/O streams library is nice since one line can read text for an entire structure, convert the text to binary, store the result in program variables, and check for errors.

Here is the statement for your data:
Code:
  jessicaFile >> jessica.hours >> jessica.mins >> jessica.secs >> jessica.pillOne >> jessica.pillTwo;
You can test for success of the above read statement like this:
Code:
  if (!jessicaFile) {
    // error occurred
  }


Logged

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 150
Posts: 6130
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You may have problems here if the file has more than 11 characters. It will not exit the while loop because it will not read the entire file. That is why I put the read outside the save routine. That way it will read the entire file and not stay in the loop.
Code:
   while( jessicaFile.available())
    {
    // If the file is larger than 11 bytes, it will lock here
    //  char ch = jessicaFile.read();

    // and this should be if(i < 11), not while
      while(i<11)
      {
      str[i] = jessicaFile.read();
      Serial.write(str[i]);
      i++;
      str[i] = 0;

      // remove this delay!
      delay(1000);
      }
    }

Remove that delay! It is in the wrong place. An eleven character file will take ten seconds to read. ??
If you want a second between file reads, put it after the jessicaFile.close().

This is just an SD shield? No ethernet onboard?

edit: I missed the while(i < 11). It should be if(i < 11).

This is the way I see it:
Code:
   while( jessicaFile.available())
    {
      char ch = jessicaFile.read();

      if(i<11)
      {
        str[i] = ch;
        Serial.write(str[i]);
        i++;
        str[i] = 0;
      }
    }

« Last Edit: July 03, 2012, 10:07:41 pm by SurferTim » Logged

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That part works, and the delay is just so i can see it, not for any other reason. and it needs to be

if(i<=11) or just if(i<12) because there are 12 characters in there... if its less than 11 than its only doing it 11 times

I just can't figure out how to divide them into my class? It works to divide them using the strtok and when i print out the pch. it doesn't work when I have casted them back to int so it can be stored using the switch...
Logged

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 150
Posts: 6130
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
char str[12];
If you are getting 12 ascii type characters that you plan on printing, then you better increase the size of str[] by one character. 12 characters along with the terminating zero makes 13 characters total. You will overflow your array.
Logged

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Why do you need a terminating zero?

And I am only printing the numbers so I can see it working, I really just want them put into the class "details" so that I can use them later
« Last Edit: July 03, 2012, 11:09:31 pm by ballboii » Logged

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 150
Posts: 6130
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Then you don't need the terminating zero. But I don't think strtok will work with a string that is not zero terminated, so you may need to find another way of parsing the array.
Logged

Pages: [1] 2   Go Up
Jump to: