Go Down

Topic: Speeding up the reading of several analog sensors working simultaneously  (Read 562 times) previous topic - next topic

LouisSnz

Hello everyone,

I am curently working on a student project to study vibrations on 3 differents analog sensors (piezoelectric sensors).

I have to store the data they send me back on a SD card plugged on my arduino uno. The problem is that I must have a quite high sampling frequency (around 1000Hz would be a good beginning but faster would be even better) but I can't reach such a frequency.

I did my best to optimize my code but I am barely reaching a frequency of 55Hz (I got values every 17-18ms). Here is my code :

Code: [Select]
#include <SD.h>
#include <SPI.h>

File myFileA1;

Sd2Card card;
SdVolume volume;
SdFile root;


int capteur1=0;
int capteur2=0;
int capteur3=0;

int pin1=A1;
int pin2=A2;
int pin3=A3;

String chaine;

unsigned long temps;

const int chipSelect = 10;

void setup() {

Serial.begin(9600);

while (!Serial) {
    ;
  }

if(!SD.begin(10))
{
  Serial.println("L'initialisation de la carte SD a echoue");
  return;
}

  Serial.println("l'initialisation de la carte SD a réussi");

  SD.remove("1.csv"); //suppresion du dernier fichier

  myFileA1=SD.open("1.csv",FILE_WRITE);
  myFileA1.print("Temps");
  myFileA1.print(";");
  myFileA1.print("Capteur1");
  myFileA1.print(";");
  myFileA1.print("Capteur2");
  myFileA1.print(";");
  myFileA1.println("Capteur 3");
  myFileA1.close();
}


void loop() {
 
    myFileA1=SD.open("1.csv",FILE_WRITE);
   
    chaine=String(millis());
    chaine+=";";
    chaine+=String(analogRead(pin1));
    chaine+=";";
    chaine+=String(analogRead(pin2));
    chaine+=";";
    chaine+=String(analogRead(pin3));

    myFileA1.println(chaine);
    //Serial.println(chaine);
   
    myFileA1.close();
}


Would you see a method to speed up these value readings and save time between each readings? Or should I use an arduino for each sensor or maybe change the card or the way the data are stored?
I also join the file I get at the end of my test : https://drive.google.com/open?id=1YotNvLUoOdyNxkKag1bMFMuzlDZA0A7q

Thank you in advance for your help.

AWOL

I think that the opening and closing of the file is where you're losing time.
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

LouisSnz

Thank you for your fast answer.

How could I change that ? Can I just open the file in the void setup() and the file will be left opened for the rest of the program ?

Something like that ?

Code: [Select]
#include <SD.h>
#include <SPI.h>

File myFileA1;

Sd2Card card;
SdVolume volume;
SdFile root;


int capteur1=0;
int capteur2=0;
int capteur3=0;

int pin1=A1;
int pin2=A2;
int pin3=A3;

String chaine;

unsigned long temps;

const int chipSelect = 10;

void setup() {

Serial.begin(9600);

while (!Serial) {
    ;
  }

if(!SD.begin(10))
{
  Serial.println("L'initialisation de la carte SD a echoue");
  return;
}

  Serial.println("l'initialisation de la carte SD a réussi");

  SD.remove("1.csv"); //suppresion du dernier fichier

  myFileA1=SD.open("1.csv",FILE_WRITE);
  myFileA1.print("Temps");
  myFileA1.print(";");
  myFileA1.print("Capteur1");
  myFileA1.print(";");
  myFileA1.print("Capteur2");
  myFileA1.print(";");
  myFileA1.println("Capteur 3");
}


void loop() {
   
    chaine=String(millis());
    chaine+=";";
    chaine+=String(analogRead(pin1));
    chaine+=";";
    chaine+=String(analogRead(pin2));
    chaine+=";";
    chaine+=String(analogRead(pin3));

    myFileA1.println(chaine);
    //Serial.println(chaine);
}

LightuC

If you really need to push things, then don't do the string conversion.
Just store them as binary values, you can restore them later when you are going to use the readings.

gfvalvo

Your data storage format and use of the String class isn't helping either. I'd be tempted to store the data as binary records: Three binary uint16_t values for each record. That's only 6 bytes per record. Then, pretty it up later in a non-real time post-processing stage.

EDIT:
@LightuC was quicker.
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

AWOL

I'd try putting the open in setup, then try reading continuously for, say, 20 seconds and then do the close.
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

LouisSnz

Hi everyone,

I have listened to all your advice and modified my program accordingly :

Code: [Select]
#include <SD.h>
#include <SPI.h>

File myFileA1;

Sd2Card card;
SdVolume volume;
SdFile root;

int pin1=A1; //x5
int pin2=A2; //x2
int pin3=A3; //pas amplifié

String chaine;

unsigned long temps;

const int chipSelect = 10;

void setup() {

Serial.begin(9600);

while (!Serial) {
    ;
  }

if(!SD.begin(10))
{
  Serial.println("L'initialisation de la carte SD a echoue");
  return;
}

  Serial.println("l'initialisation de la carte SD a réussi");

  SD.remove("1.csv"); //suppresion du dernier fichier

  myFileA1=SD.open("1.csv",FILE_WRITE);
  myFileA1.print("Temps");
  myFileA1.print(";");
  myFileA1.print("Capteur1");
  myFileA1.print(";");
  myFileA1.print("Capteur2");
  myFileA1.print(";");
  myFileA1.println("Capteur 3");
  myFileA1.close();

  myFileA1=SD.open("1.csv",FILE_WRITE); // file is opened for the loop
}

void loop () {
 
  myFileA1.print(millis());
  myFileA1.print(";");
  myFileA1.print(analogRead(pin1));
  myFileA1.print(";");
  myFileA1.print(analogRead(pin2));
  myFileA1.print(";");
  myFileA1.println(analogRead(pin3));

}


The problem is that when I don't open and close my file in my loop, the program doesn't write any data to my file which is pretty annoying.

mMoreover, would you know how to avoid writing MyFileA1.print(...) several times and do it all at once ?

Thanks for your help :)

AWOL

I'd try putting the open in setup, then try reading continuously for, say, 20 seconds and then do the close.
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

LouisSnz

Ok great ! This worked for me !

Code: [Select]

void loop () {
 
  myFile=SD.open("1.csv",FILE_WRITE);
 
  while(millis()<10000){
    myFile.print(millis());
    myFile.print(";");
    myFile.print(analogRead(pin1));
    myFile.print(";");
    myFile.print(analogRead(pin2));
    myFile.print(";");
    myFile.println(analogRead(pin3));
  }
 
  myFile.close();

  Serial.println("End of the loop");
 
  exit(0);
}


One thing I've noticied is that the function Serial.println("..."); takes a lot of time (around 5 ms). With this code, I take my values every millisecond.
I saw that we could make up to 10,000 value readings per second. Do you have any ideas to further optimize my code? I would also need a more precise function than millis() to know the time. Is there one?

AWOL

See reply #3

Quote
I would also need a more precise function than millis() to know the time. Is there one?
Finer granularity would be micros()
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

gfvalvo

One thing I've noticied is that the function Serial.println("..."); takes a lot of time (around 5 ms). With this code, I take my values every millisecond.
I saw that we could make up to 10,000 value readings per second. Do you have any ideas to further optimize my code?
It was suggested in both Reply #3 and Reply #4 to write the values as binary to the file. You ignored those suggestions.
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

LouisSnz

I don't really understant, isn't it what I have done ? I only use the function print and do not convert the values I get. How could I do otherwise?

AWOL

You could write the binary values directly, without semicolons or newlines.
You know how many you write each time, and they'll be fixed length, two bytes per reading.
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

PaulS

Quote
I only use the function print and do not convert the values
print() converts the int to a string and write()s the string.

write() does no such conversion.
The art of getting good answers lies in asking good questions.

LouisSnz

Hello, I'm back, I didn't have enough time to work on my project.

I tried to use the write() function but in my excel file, I didn't have readable values. I suppose I should convert the binary values into strings but I don't know how to do that and if it should be in the program or on excel.

Moreover, I have to separate my values so I must use the "  myFile.print(";");   " function (or am I missing something ?). Won't it slow down the execution ?

I never worked with binary values so please lenient  :D

Go Up