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
#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
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.
The file contains
12 01 00 1 0
jessica.hours = jessicaFile.read();
The hours member of the jessica instance will now contain '1', not 12.
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.
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?
#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);
}
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?
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);
}
Did you see my post above? There are major things wrong.
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();
}
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.
#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() {}
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.
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.
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).
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...
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.
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.
Good to hear it is working, but you are still overflowing the str array.
// this is set for 13 characters
char str[13];
// then later in the code
if(i<13)
{
str[i] = ch;
Serial.write(str[i]);
i++;
// If i == 12, this will store zero in str[13] (14th position)
str[i] = 0;
delay(1000);
}
add: Overflowing arrays can have embarrassing results. Try this code.
char test[4] = {'a','b','c','d'};
char between[3] ={'1','2','3'};
char test2[4] = {'d','u','c','k'};
char testend = 0;
void setup()
{
Serial.begin(9600);
Serial.println(test);
Serial.println(between);
Serial.println(test2);
// this is changing the test array, not test2
test[7] = 'f';
// now print test2
Serial.println(test2);
}
void loop() {
}
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.
It will, but the results will not be what you expect. Somewhere in memory, after the address that is the start of the array, there will be a NULL. strtok() will keep processing until it finds it. The NULL is its clue (as with all string functions) that it has reached the end of the array.
If you really are too lazy to increase the size of the array by 1, and to NULL terminate the array, that's fine. Simply do not use any string handling functions (strtok, strcat, strcpy, atoi(), etc.).
Really, learning to deal with NULL terminated arrays of chars will be quite useful in most everything you do with the Arduino, and is worth taking the time and effort to learn how to do it properly.