[Résolu] 2 taux d'échantillonnages différents dans la boucle principale

Bonjour,

Je suis sur un projet d'enregistreur accélération sur un appareil de mesure. j'avais déja fait un topic sur le choix des composants et comment gérer une alimentation autonome.

J'ai donc toutes mes pieces, j'ai meme rajouté un capteur de pression atmosphérique et c'est avec lui que j'ai un soucis quand je cherche a écrire le code.

Je me retrouve avec un accéléromètre, et un capteur de pression dont je veux récupérer les données.
Pour l'accéléromètre, je veux le meilleur échantillonnage possible, stocker les vlauers dans une variable, et toutes les X échantillons (correspondant a une 10aine de seconde par exemple) prendre le max, effacer la variable, et recommencer.
C'est dans le but de limiter le nombre de lignes qui seront écrites sur la carte SD, et avoir quelque chose de plus lisible.

Le capteur de pression quant a lui demande un certain temps (au moins 2 secondes) pour avoir stabiliser la mesure.

voici les codes pour chacun des capteurs :
Accéléromètre (pour le moment je me limite au Z)

#include <Wire.h>
#include <LSM303.h>
float maxi=0;
int counter=0;

LSM303 compass;
char report[80];

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  compass.init();
  compass.enableDefault();  
}

void loop()
{
  compass.read();
  if (compass.a.z*0.122/1000.0>maxi)
  { maxi=compass.a.z*0.122/1000.0;}
  counter++;
  if (counter==200)
  {Serial.println(maxi);
  counter=0;
  maxi=0;
  }
}

Capteur de pression atmosphérique
(code de l'exemple de la bibliothèque que j'ai allégé)

#include <SFE_BMP180.h>
#include <Wire.h>

// You will need to create an SFE_BMP180 object, here called "pressure":

SFE_BMP180 pressure;


void setup()
{
  Serial.begin(9600);
  Serial.println("REBOOT");

  // Initialize the sensor (it is important to get calibration values stored on the device).

  if (pressure.begin())
    Serial.println("BMP180 init success");
  else
  {
    // Oops, something went wrong, this is usually a connection problem,
    // see the comments at the top of this sketch for the proper connections.

    Serial.println("BMP180 init fail\n\n");
    while(1); // Pause forever.
  }
}

void loop()
{
  char status;
  double T,P,p0,a;

  // You must first get a temperature measurement to perform a pressure reading.
  
  // Start a temperature measurement:
  // If request is successful, the number of ms to wait is returned.
  // If request is unsuccessful, 0 is returned.

  status = pressure.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);

    // Retrieve the completed temperature measurement:
    // Note that the measurement is stored in the variable T.
    // Function returns 1 if successful, 0 if failure.

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      // Print out the measurement:
      Serial.println("temperature: ");
      Serial.print(T,2);
      Serial.print(" deg C, ");

      status = pressure.startPressure(3);
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);

        // Retrieve the completed pressure measurement:
        // Note that the measurement is stored in the variable P.
        // Note also that the function requires the previous temperature measurement (T).
        // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          // Print out the measurement:
          Serial.println("absolute pressure: ");
          Serial.print(P,2);
          Serial.print(" mb, ");


          // The pressure sensor returns abolute pressure, which varies with altitude.
          // To remove the effects of altitude, use the sealevel function and your current altitude.
          // This number is commonly used in weather reports.
          // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m.
          // Result: p0 = sea-level compensated pressure in mb


        }
        else Serial.println("error retrieving pressure measurement\n");
      }
      else Serial.println("error starting pressure measurement\n");
    }
    else Serial.println("error retrieving temperature measurement\n");
  }
  else Serial.println("error starting temperature measurement\n");

  delay(2000);  // Pause for 2 seconds.
}

Je ne comprends pas trop la variable status et les valeurs qu'elle peut prendre, mais si je fais sauter les lignes "delay(status)" ça fout le bazar dans les résultats... donc y a réellement besoin d'un certain temps tout au long du process pour que les mesures soient correctes.

Comment concilier les 2 ?

J'ai bien penser a un "while" basé sur "counter" pour remplacer delay de 2000 mais je ne sais pas trop où le mettre dans le code du capteur de pression...

Lisez les tutos sur comment utiliser millis() (par exemple celui ci en anglais)

Je n'avais pas pensé à la fonction millis pour timer la fonction du capteur de pression.

Je pense voir globalement comment faire, du coup pas besoin de connaitre la valeur des variables "status", c'est mon intervalle de temps, et il faut que test le temps actuel - temps de début de ma fonction est supérieur a status ou pas ...

Je testerais ça demain

merci

c'est plus compliqué que ce que je pensais... Dans les exemples qu'on voit sur le net, il y a 1 paramètre a gérer avec la fonction millis() et ça marche très bien ... mais là j'ai 2 paramètres et le 2e dépend du premier...

voici ce que j'ai écrit

#include <SFE_BMP180.h>
#include <Wire.h>
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
unsigned long startMillis2;
  double T,P,p0,a;
int temp=0;


SFE_BMP180 pressure;

void setup()
{
  Serial.begin(9600);
  Serial.println("REBOOT");
    if (pressure.begin())
      Serial.println("BMP180 init success");
    else
    {
      Serial.println("BMP180 init fail\n\n");
      while(1); // Pause forever.
    }
    startMillis =0;
}
  
  void loop()
  {
    char status;
  
  currentMillis=millis();
  pressure.startTemperature();
  if (currentMillis - startMillis >=2015) 
  {
    if(temp==0)           
       {
            pressure.getTemperature(T);
            Serial.println("temperature: ");
            Serial.print(T,2);
            Serial.print(" deg C, ");
            pressure.startPressure(3);
            temp=1; 
        }
  }
        
                  
  if ( currentMillis - startMillis >=2060)
  {
     pressure.getPressure(P,T);
     Serial.println("absolute pressure: ");
     Serial.print(P,2);
     Serial.print(" mb, ");
     startMillis =millis();
     temp=0;
     
  }
}

Normalement, dès le début il commence le processus de mesure de température et dès qu'il dépasse 2015 ms il récupère la valeur de température. et bloque le processus en changeant la variable "temp".

Une fois que j'ai la température, je peux procéder à la mesure de la pression.

45ms plus tard je récupère la valeur de la pression ... et ça marche pas ...

J'ai bien vérifier la valeur de T dans la fonction "pressure.getPressure(P,T);" c'est bien la température mesuré sur le premier IF

J'ai essayé de faire tourner seulement le 2e if tout seul dans un scketch en lui fournissant une température à la main, et ça marche ...
Le problème a l'air de venir de la façon dont tout ça est imbriqué ... mais j'ai pas trouvé :confused:

EDIT :
ça doit vraiment venir de la façon dont le code est monté parce que je viens de tester avec un simple compteur

void loop()
  {
  
  

  if (counter==100)
  { pressure.startTemperature();}
  if (counter==100000)
  {
    
            pressure.getTemperature(T);
            pressure.startPressure(3);
            Serial.println("temperature: ");
            Serial.print(T,2);
  }
        
                  
  if (counter==500000){
     pressure.getPressure(P,T);
            //     Serial.println("temperature: ");
           //Serial.print(T,2);
            Serial.print(" deg C, ");
     Serial.println("absolute pressure: ");
     Serial.print(P,2);
     Serial.print(" mb, ");
    counter=0;
  }
  counter++;
}

et ça fonctionne bien si j'ai suffisemment de temps entre le start et le get

est-ce que vos fonctions de lecture de T et P sont bloquantes ?

Je dirais qu'elles ne sont pas bloquante, dans le sens où dans l'exemple fourni avec la lib, le delay est gérer dans la boucle, la fonction retourne juste une valeur de delay.

Mais je ne sais pas si quelque chose d'autre que le delay peut rendre une fonction bloquante.

Je ne suis pas chez moi, je posterais un lien vers la lib dans l'après midi, ça sera sûrement plus clair avec le code sous les yeux.

Merci pour les réponses.

le BMP180 (qui remplaçait le BMP085 et le BMP183) est un composant un peu ancien, qui est maintenant remplacé par le BMP280 ou le MPL3115A2. Suivant ce que vous voulez faire il vaut mieux prendre des composants récents plus performants

il existe plusieurs librairies pour le BMP180 (Adafruit, sparkfun en ont une - vu votre nom SFE_*** vous devez utiliser celle de SparkFun)

Vous écrivez

Le capteur de pression quant a lui demande un certain temps (au moins 2 secondes) pour avoir stabiliser la mesure.

Quand je regarde la datasheet ils disent que la conversion prend entre 4.5 et 76.5 millisecondes... et si je regarde la méthode startPressure() de votre librairie on voit que le délai retourné suivant la précision voulue est entre 5 et 26ms (ce qui veut dire qu'ils n'ont pas pris le mode Advanced Résolution qui est celui à 76.5ms)

--> donc je ne sais pas où sont vos 2 secondes.

la librairie que j'utilise est bien celle de sparkfun.

Le coup des 2 secondes c'est que je venais de découvrir la librairie, dans l'exemple, il y avait un délai de 2 seconde a la fin de la boucle.
Quand j'ai voulu mettre ça dans le code qui gère mon accéléromètre, ça donnait pas de bonnes valeurs.
J'en avait donc déduit qu'il lui fallait au moins 2 seconde pour prendre la mesure.

Depuis j'ai fouillé un peu dans le code de la librairie et j'ai bien vu que la mesure complète ne durait pas plus de 31ms entre la mesure de la température et de la pression.

Mais toujours est il que le taux d'échantillonnage de mon accéléromètre est de 50hz, soit 20ms.
J'aimerais garder cet échantillonnage car à la base c'est surtout l'accélération qui m'intéresse, la pression, je peux prendre 1 mesure par minute c'est largement suffisant.

On en est donc là d'un coté 20ms, de l'autre 31...

je viens de refaire un teste avec la fonction millis(), et en partant sur 3 timing différent, ça fonctionne enfin.
et le soucis devais venir que le startTemperature() était dans la loop et n'était pas timé.

Voici ce a quoi j'arrive, pour une mesure toutes les 10 secondes

#include <SFE_BMP180.h>
#include <Wire.h>
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
unsigned long startMillis2;
unsigned long startMillis3;
  double T,P,p0,a;
long temp=0;
long counter =0;

SFE_BMP180 pressure;

void setup()
{
 counter=0;
  Serial.begin(9600);
  Serial.println("REBOOT");
    if (pressure.begin())
      Serial.println("BMP180 init success");
    else
    {
      Serial.println("BMP180 init fail\n\n");
      while(1); // Pause forever.
    }
    startMillis =0;
}
  
  void loop()
  {
  currentMillis=millis();
 
  if (currentMillis - startMillis >=10000)
  {
    pressure.startTemperature();
    startMillis=millis();
  }

  
  
  
  
  if (currentMillis - startMillis2 >=10005)
  {
            pressure.getTemperature(T);
            Serial.println("temperature: ");
            Serial.print(T,2);
            Serial.print(" deg C, ");
            pressure.startPressure(3);
            startMillis2 =millis();
        
  }
        
                  
  if ( currentMillis - startMillis3 >=10031)
  {
     pressure.getPressure(P,T);
     Serial.println("absolute pressure: ");
     Serial.print(P,2);
     Serial.print(" mb, ");

     startMillis3 =millis();
      
  }
 }

il me reste a vérifier que je peux inclure ça dans mon code avec l'accéléromètre.

le code dans le message précédent n'est pas bon.
Le delta de temps entre les deux derniers if, s'agrandit au fil des boucles, jusqu'a avoir le pressure.getPressure(P,T) qui s’exécute avant le pressure.getTemperature(T); entrainant une valeur erronée qui revient de manière cyclique.

Voici le code auquel j'ai fini par arriver pour avoir quelque chose de stable dans le temps :

unsigned long currentMillis;
unsigned long startMillisTemp;
unsigned long startMillisSP;
unsigned long startMillisRP;
unsigned long counterloop;
unsigned long interval1;
unsigned long interval2;
unsigned long interval3;


LSM303 compass;
SFE_BMP180 pressure;


void setup()
{
  Serial.begin(9600);
  Wire.begin();
  compass.init();
  pressure.begin();
  compass.enableDefault();  
  startMillis=0;
  startMillisTemp=0;
  startMillisSP=0;
  startMillisRP=0;
  interval1=2000;
 
}

void loop()
{
  currentMillis=millis();

  if (currentMillis >=interval1)
  {
    pressure.startTemperature();
    interval1=2000*(counterloop+1);
    interval2=2000*(counterloop)+10;
  }
  
  if (currentMillis >=interval2)
  {
    pressure.getTemperature(T);
    pressure.startPressure(3);
    startMillisSP =millis();
    interval2=2000*(counterloop+1)+10;
    interval3=2000*(counterloop)+51;
  }

   if ( currentMillis >=interval3)
  {
     pressure.getPressure(P,T);
     Serial.print("temperature: ");
     Serial.print(T,2);
     Serial.println(" deg C ");
     Serial.print("absolute pressure: ");
     Serial.print(P,2);
     Serial.println(" mb, ");
     interval3=2000*(counterloop+1)+10;
     counterloop++;
  }