I would like to retrieve data previously recorded on an SD card using a microSD Shield (I use the SDfat library ).
These data are in fact numbers between 0 and 1024 obtained from a sensor. I want them back and then controlling a servomotor, yet I can't do it.
I think I'm stuck because the data that I get on the SD card are automatically of type char, and the servomotor request type int.
Do you have an idea to help me ? thank you !
Do you have an idea to help me ?
Post the code that you have that is reading the data from the SD card.
Look at the documentation for atoi().
here is my program
the values I had in my SD card scrolls well in the serial monitor, but I don't know hw to use them to move my servomotor.
#include <SdFat.h>
#include <SdFatUtil.h>
#include <ctype.h>
#include <Servo.h>
Servo myservo;
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;
char name[] = "Test.txt";
char contents[256];
char in_char=0;
int index=0;
void setup(void)
{
Serial.begin(115200);
myservo.attach(9);
pinMode(10, OUTPUT);
card.init();
volume.init(card);
root.openRoot(volume);
}
void loop(void){
file.open(root, name, O_READ);
in_char=file.read();
while(in_char >=0)
{
Serial.print(in_char);
in_char=file.read();
}
file.close();
delay(1000);
}
but I don't know hw to use them to move my servomotor.
Well, just sending them to the serial monitor is useless, as you've observed.
You need to make use of the data. Exactly how to do that depends on what the data on the card looks like.
If there is a continuous stream of characters that represent digits, you have a problem. If there are non-digit characters in between, like carriage return, line feed, space, etc. then those form delimiters.
You can store the characters in an array, and use atoi to convert the array to an int, then reset the array. Or, you can construct the int as you read each digit from the file.
thank you for your help,
but i don't manage with the delimiters.
In fact I used the fnction strtok_r, but it didn't work.
Are there any other fnction to make segmentation (delimiters are line feed in my case) ?
In fact I used the fnction strtok_r, but it didn't work.
You want to be using strtok(), not the thread-safe version.
"It didn't work" means that you wrote your code wrong. Since you didn't share that code, we can only guess at the problem. I'm going to guess 57.
#include <stdio.h>
#include <stdlib.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <ctype.h>
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;
char name[] = "Test.txt";
char contents[256];
char in_char=0;
char* val = "0";
int index=0;
int a;
void setup(void)
{
Serial.begin(115200);
pinMode(10, OUTPUT);
card.init();
volume.init(card);
root.openRoot(volume);
}
void loop(void){
file.open(root, name, O_READ);
val[0] = file.read();
while(val >=0){
val[0]=file.read();
char *str;
while ((str = strtok_r(val, ";", &val)) != NULL) // delimiter is the semicolon
int a = atoi(str);
Serial.print(a);
delay(10);
}
file.close();
}
There are so many things wrong with that code that it is hard to know where to begin.
char* val = "0";
This points to the character 0 stored somewhere in memory.
val[0] = file.read();
while(val >=0){
val[0]=file.read();
This attempts to overwrite the one character that val points to. The while loop will always be true, because val is an address, and that address is not 0. So, you read another byte into the same memory location, overwriting the previous one.
char *str;
while ((str = strtok_r(val, ";", &val)) != NULL) // delimiter is the semicolon
int a = atoi(str);
Then, you try to pass a non-NULL-terminated array to a function that expects a NULL terminated array of chars. Fail!
You need to define an array of fixed size, NOT using a pointer. You need to read data from the card until some end-of-record marker is read, or until the end-of-file marker is encountered. Collect the characters in the array as they are read, adding a NULL after each character added to the array.
When the end of record marker is read, then you want to parse the data, using strtok, not strtok_r.
I see what you mean.
In fact I am a novice in arduino and C language, that's why it's a bit difficult for me to code this program.
I thank you for ur advices, but can u explain me quickly how to use them ?
char* val = "0";
By example, what should i put instead of that.
while(val >=0){
val[0]=file.read();
this must be deleted?
how to create a non-NULL-terminated array?
and a end of record marker ?
If you have a little time to dedicate to my program, could you correct my wrong things, this will help me a lot!
ty
By example, what should i put instead of that.
char val[10];
(If the record length does not exceed 10 characters. If it does, make the value larger.)
this must be deleted?
No. You need an index into the array. That index should be incremented as the character is added. Don't keep overwriting position 0.
how to create a non-NULL-terminated array?
That's not what you want. You want a NULL terminated array of characters.
and a end of record marker ?
That needed to be done when the file on the SD card was created. What does the file look like?
Here is some code that reads from the serial port. It expects the data to be bounded by start and end of packet markers. Reading from a file is simpler, since you know when "the start marker arrives". That happens when you open the file, and after processing each record in the file.
The end of packet marker is probably a carriage return or linefeed (\r or \n).
#define SOP '<'
#define EOP '>'
bool started = false;
bool ended = false;
char inData[80];
byte index;
void setup()
{
Serial.begin(57600);
// Other stuff...
}
void loop()
{
// Read all serial data available, as fast as possible
while(Serial.available() > 0)
{
char inChar = Serial.read();
if(inChar == SOP)
{
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}
else if(inChar == EOP)
{
ended = true;
break;
}
else
{
if(index < 79)
{
inData[index] = inChar;
index++;
inData[index] = '\0';
}
}
}
// We are here either because all pending serial
// data has been read OR because an end of
// packet marker arrived. Which is it?
if(started && ended)
{
// The end of packet marker arrived. Process the packet
// Reset for the next packet
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
You should be able to adapt this to reading from a file, instead of the serial port.
TY for your help, but I've still problems of conversion..
In fact my file "Test.txt" contains 3digit-numbers from 0 to 255, like this :
"076;234;145;024;245;ect..."
Here is your code that I adapted.
#define SOP '<'
#define EOP '>'
bool started = false;
bool ended = false;
char name[] = "Test.txt"; // name of the file n my SD card
char inData[1000];
byte index;
void setup()
{
Serial.begin(9600);
// Etc...
}
void loop()
{
file.open(root, name, O_READ); //Open the file in read mode.
char inChar=file.read(); //Get the first byte in the file.
while(inChar >0){
char inChar = file.read();
if(inChar == SOP)
{
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}
else if(inChar == EOP)
{
ended = true;
break;
}
else
{
if(index < 999)
{
inData[index] = inChar;
index++;
inData[index] = '\0';
}
}
}
}
We are here because all pending serial data has been read , does it change something in the code ?
if(started && ended)
{
// Process the packet = Segment + store in an array + convert to int ?
// segmentation
char *token;
token = strtok (inChar, ";");
// creation of an array (3 digit-numbers)
int a;
char array[3]= {0};
how to store "token" in this array ? does "a=sprintf(array,token)" is correct ?
int a = atoi (array);
and how to convert them one by one ?
// Reset for the next packet
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
Have you considered storing your code in binary instead of text it would simplify this a lot.
char inChar=file.read(); //Get the first byte in the file.
while(inChar >0){
char inChar = file.read();
Get the first byte. If it's not NULL, throw it away. Well, OK. I guess that will work.
Define another variable named inChar, that is local to the while loop. Guess what you have now. An infinite loop. The while loop variable never changes value, so the loop never ends.
In fact my file "Test.txt" contains 3digit-numbers from 0 to 255, like this :
"076;234;145;024;245;ect..."
No <? No >? So, why are SOP and EOP defined as < and >?
char inData[1000];
Between this array and the SD library, 3/4 of your SRAM is gone.
byte index;
You can not use a byte sized index into a 1000 element array.
We are here because all pending serial data has been read , does it change something in the code ?
You'll never get there. So, don't worry about it.
Fix the issues above, then we can talk.