Go Down

Topic: Clignotement de led et faire une moyenne ( fréquence cardiaque et arduino ) (Read 1 time) previous topic - next topic

HRadar

Bonjour à tous !

Je suis en train de faire un petit projet arduino, je tiens à préciser que je suis débutant.

J'ai deux cartes qui communiquent sans fils via des shields XBee. Sur l'émettrice il y a un capteur qui renvoi un valeur décimale, la fréquence cardiaque en bpm. Il envoie cette valeur à une carte réceptrice.

Je viens demander de l'aide pour deux choses :

- Comment puis-je faire clignoter une led ( ou un chenillard, mais une led c'est déjà bien ) en fonction de la valeur du pouls ? Par exemple si le bpm est de 65, la led devrait clignoter 65 fois par minutes... Je ne vois pas vraiment comme le coder proprement.

- Je dois faire une moyenne du bpm pris sur 12h ou 24h, comme coder cela, afin de définir une certaine valeur "m" comme la moyenne ?  J'ai pensé à faire un sous-programme qui relèverai une valeur du bmp toutes les secondes sur disons 12h, puis fais le calcul de la moyenne. Cependant l'addition de toutes ces valeur peut-elle directement être stockées dans une variable ?
Si par exemple je prends une valeur de bpm de 100 pendant 24h ( pour me donner de la marge ) alors j'additionne toutes ces valeurs dans une variable de type "long" et puis je divise par le nombre de mesures ( cela fait 86 400 mesures ). Ceci est la bonne méthode ?


Merci d'avance pour vos réponses !


PS : Voici les codes que j'utilise :

Émetteur :
Code: [Select]
#include <Wire.h>
void setup() {
  Serial.begin(9600);
  Serial.println("heart rate sensor:");
  Wire.begin();
  setDestination();
}
void loop() {
  Wire.requestFrom(0xA0 >> 1, 1);    // request 1 bytes from slave device
  while(Wire.available()) {          // slave may send less than requested
    unsigned char c = Wire.read();   // receive heart rate value (a byte)
    Serial.println(c, DEC);         // print heart rate value
  }
  delay(500);
}



// Xbee configuration
void setDestination() {
  Serial.print("ATRE\r");
  Serial.print("ATDL0\r");
  Serial.print("ATMY1\r");
  Serial.print("ATID1111\r");
  Serial.print("ATCN\r");
}



Récepteur :
Code: [Select]
void setup() {
  Serial.begin(9600);       //initialize serial
  setDestination();
}
 
void loop() {
  while(Serial.available()){  //is there anything to read?
    char getData = Serial.read();  //if yes, read it
    Serial.write( getData );
    }
  }
  

// Xbee configuration
void setDestination() {
  Serial.print("ATRE\r");
  Serial.print("ATMY0\r");
  Serial.print("ATID1111\r");
  Serial.print("ATCN\r");
}

trimarco232

Bonjour,

à priori, additionner les valeurs ne convient pas : pour avoir une moyenne, il faut, pour chaque nouvelle entrée, retrancher la plus ancienne ...

... et pour pouvoir la retrancher, il faut l'avoir gardée en mémoire.

l'être humain est bien fait, le nombre de battements par minute tient dans un octet : tu peux donc enregistrer chaque minute, cela te fera un tableau de 60*24 = 1440 octets pour la journée

quand une nouvelle donnée arrive (chaque minute), tu retranches la plus ancienne et tu recalcules toutes les moyennes que tu veux

c'est simple et exact !

mais il y a plus génial que moi sur ce forum, avec peut-être une méthode moins lourde ?



HRadar

Bonjour, merci de votre réponse.

J'ai donc essayé de coder cela, cependant je n'ai pas bien compris la solution proposée.

J'ai pris le cas où je prends une mesure par minutes pendant 12h.

Code: [Select]

#include <Wire.h>
long sommevaleurs = 0;
int moyenne = 0;
int nbmesures = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("heart rate sensor:");
  Wire.begin();
  rodage();
  setDestination();

// void loop etc

void rodage() {
   
  Wire.requestFrom(0xA0 >> 1, 1);    // request 1 bytes from slave device
  while(Wire.available()) {          // slave may send less than requested
     while (nbmesures <= 760){
     unsigned char valeur = Wire.read();   // receive heart rate value (a byte)
     sommevaleurs = sommevaleurs + valeur;
     nbmesures ++;
     delay(60000);
  }
  moyenne = sommevaleurs / nbmesures;
}
}



Le code est-il correct ?

trimarco232

Bonjour,

il faut créer un tableau qui contient les valeurs :
const nombre_de_valeurs = 60*12;
byte tableau_valeurs[nombre_de_valeurs];

initialiser le tableau avec des valeurs bidon :
for (unsigned int i=0; i <= nombre_de_valeurs; i++) { tableau_valeurs = 69; }
   

définir un pointeur qui va pointer les valeurs dans le tableau :
unsigned int pointeur = 0;

à chaque nouvelle entrée, détruire la donnée pointée et mettre la nouvelle donnée à la place (*) :
tableau_valeurs[pointeur] = nouvelle_valeur

ne pas oublier de faire avancer le pointeur, et de le remettre à 0 s'il est arrivé au bout :
pointeur++;
if (pointeur == nombre_de_valeurs)  { pointeur =0 }

maintenant on peut faire les moyennes. Exemple, moyenne générale :
on additionne toutes les valeurs :
unsigned int somme_des_valeurs = 0;
for (unsigned int i=0; i <= nombre_de_valeurs; i++) { somme_des_valeurs += tableau_valeurs ; }

on divise et c'est fini:
byte moyenne;
moyenne = somme_des_valeurs / nombre_de_valeurs;



(*) : c'est la méthode utilisée pour gérer un buffer


HRadar

Merci beaucoup de l'aide, j'ai mis cela en forme, et corrigé quelques truc par rapport aux differents messages d'erreurs, cependant il y a un message d'erreur que je n'arrive pas à résoudre.

Voici donc le code :
Code: [Select]
void rodage() {
   
  Wire.requestFrom(0xA0 >> 1, 1);    // request 1 bytes from slave device
  while(Wire.available()) {          // slave may send less than requested
     int nombre_de_valeurs = 5;
     unsigned int tableau_valeurs[nombre_de_valeurs];
     for ( int i=0; i <= nombre_de_valeurs; i++) { tableau_valeurs[i] = 0; }
     unsigned int pointeur = 0;
     
     for(pointeur=0; pointeur < nombre_de_valeurs; pointeur++){
     if((millis() - temps) > 1000)
        {
     unsigned char nouvelle_valeur = Wire.read();   // receive heart rate value (a byte)
     tableau_valeurs[pointeur] = nouvelle_valeur;
     temps = millis(); //on stocke la nouvelle heure
     if (pointeur == nombre_de_valeurs)  { pointeur =0; }
        }
  digitalWrite(5, HIGH);     
  delay(10); 
     }
  unsigned int somme_des_valeurs = 0;
  for (unsigned int i=0;  i<= nombre_de_valeurs; i++) { somme_des_valeurs += tableau_valeurs; }
  byte moyenne;
  moyenne = somme_des_valeurs / nombre_de_valeurs;
  Serial.println("moyenne");
  Serial.println(moyenne);
  digitalWrite(5, LOW);
 
}
}



Et le message :

EmetV2:53: error: invalid conversion from 'unsigned int*' to 'unsigned int' [-fpermissive]

exit status 1
invalid conversion from 'unsigned int*' to 'unsigned int' [-fpermissive]

HRadar

Je n'ai plus le message d'erreur avec ce code :
Code: [Select]
void rodage() {
   
  Wire.requestFrom(0xA0 >> 1, 1);                        // request 1 bytes from slave device
  while(Wire.available()) {                              // slave may send less than requested
     const int nombre_de_valeurs = 10;
     int tableau_valeurs[nombre_de_valeurs];
     for (unsigned int i=0; i <= nombre_de_valeurs; i++) { tableau_valeurs[i] = 0; }
     unsigned int pointeur = 0;
     
     for(pointeur=0; pointeur < nombre_de_valeurs; pointeur++){
     if((millis() - temps) > 1000)
        {
     int nouvelle_valeur = Wire.read();                 // receive heart rate value (a byte)
     tableau_valeurs[pointeur] = nouvelle_valeur;
     temps = millis();                                   //on stocke la nouvelle heure
     if (pointeur == nombre_de_valeurs)  { pointeur =0; }
        }
  digitalWrite(5, HIGH);     
  delay(10); 
     }
  unsigned int somme_des_valeurs = 0;
  for ( unsigned i=0;  i<= nombre_de_valeurs; i++) { somme_des_valeurs += tableau_valeurs[i]; }
  byte moyenne;
  moyenne = somme_des_valeurs / nombre_de_valeurs;
  Serial.println("moyenne");
  Serial.println(moyenne);
  digitalWrite(5, LOW);
 
}
}




Cependant cela ne fonctionne pas... Vue du moniteur série :

Code: [Select]
heart rate sensor:
ATRE
ATDL0
ATMY1
ATID1111
ATCN
moyenne
0
moyenne
0
moyenne
0
moyenne
0
moyenne
0
moyenne
0
moyenne
0
moyenne
0
moyenne
0
moyenne
10
104
104
104


En plus d'une répétition de l'affichage, on me donne une valeur de 10. On voit aussi qu'il n'y pas pas eu 10 mesures, une par seconde... Je vous avoue que je ne comprends plus !

HRadar

J'ai modifié un peu le code ( j'ai enlevé la fonction millis même si j'aimerais bien l'utiliser ! ) , et j'ai réussi à identifier le problème : le tableau ne se remplit pas ! Donc il fait une moyenne d'une seule valeur ! Comment y remédier ? Voici le code :


Code: [Select]
void rodage() {
   
   Wire.requestFrom(0xA0 >> 1, 1);                        // request 1 bytes from slave device
 
     const int nombre_de_valeurs = 10;
     int tableau_valeurs[nombre_de_valeurs];
     for (unsigned int i=0; i <= nombre_de_valeurs; i++) { tableau_valeurs[i] = 0; }
     
     unsigned int pointeur = 0;
     for(pointeur=0; pointeur < nombre_de_valeurs; pointeur++){
     
     while(Wire.available()) {
     int nouvelle_valeur = Wire.read();     // receive heart rate value (a byte)
     tableau_valeurs[pointeur] = nouvelle_valeur;
     }
     if (pointeur == nombre_de_valeurs)  { pointeur =0; }
       
     digitalWrite(5, HIGH);     
     delay(1000);
     }
  unsigned int somme_des_valeurs = 0;
  for ( unsigned i=0;  i<= nombre_de_valeurs; i++) { somme_des_valeurs += tableau_valeurs[i]; }
  Serial.println("somme");
  Serial.println(somme_des_valeurs);
  Serial.println(tableau_valeurs[3]);
  byte moyenne;
  moyenne = somme_des_valeurs / nombre_de_valeurs;
  Serial.println("moyenne");
  Serial.println(moyenne);
  digitalWrite(5, LOW);
 

}


Les différents "Serial.println" sont là uniquement pour me permettre de suivre les variables au cours du traitement. 

fdufnews

Pas la peine de calculer la somme de tous les échantillons à chaque fois.

Pour calculer une moyenne en continu.
A l'initialisation (dans le setup() par exemple)
  • mettre le tableau à zéro
  • mettre la somme à zéro

Pour chaque nouvel élément
  • déduire la valeur sous le pointeur de la somme
  • ajouter la nouvelle valeur à la somme
  • ranger la nouvelle valeur dans le tableau à l'emplacement désigné par le pointeur
  • avancer le pointeur
  • moyenne = somme/nb_echantillons
La moyenne ne sera juste qu'après avoir reçu nb_echantillons. Ensuite elle sera toujours bonne à chaque nouvel échantillon.
Si tu as besoin d'avoir la moyenne juste dès le début, tu peux raffiner la chose en partant avec nb_echantillons=0 dans le setup(), en l'incrémentant à chaque itération et en saturant sa valeur à nb_echantillons_max (nb_echantillons_max définissant la taille de ton tableau).

fdufnews


En ce qui concerne la LED clignotante.
Tu devrais t'inspirer de l'exemple BlinkWithoutDelay qui se trouve dans les exemples de code dans l'IDE. Ce code permet de faire clignoter une LED sans utiliser delay() et donc sans bloquer l'exécution du reste de ton application.

trimarco232

Quote
en partant avec nb_echantillons=0 dans le setup(), en l'incrémentant à chaque itération et en saturant sa valeur à nb_echantillons_max (nb_echantillons_max définissant la taille de ton tableau)
Bien vu, merci!
Donc raffinons : ne n'ai pas eu le cœur de vérifier si ça marche, mais au moins ça compile

Code: [Select]
#include <Wire.h>

const int nombre_de_valeurs_max = 12*60;
unsigned int somme_des_valeurs = 0, pointeur = 0, nombre_de_valeurs = 1;;
byte tableau_des_valeurs[nombre_de_valeurs_max], moyenne;

void setup() {

}

void loop() {

Wire.requestFrom(0xA0 >> 1, 1);                        // request 1 byte from slave device
         
if (Wire.available()) {

digitalWrite(5, HIGH);
byte nouvelle_valeur = Wire.read();     // receive heart rate value (a byte)
somme_des_valeurs += nouvelle_valeur;
   
if (nombre_de_valeurs > nombre_de_valeurs_max)
  { somme_des_valeurs -= tableau_des_valeurs[pointeur]; }
else
  { nombre_de_valeurs++; }

moyenne = somme_des_valeurs / nombre_de_valeurs;
Serial.println("moyenne:");
Serial.println(moyenne);

tableau_des_valeurs[pointeur] = nouvelle_valeur;

pointeur++;
if (pointeur == nombre_de_valeurs_max) { pointeur = 0; }
   

delay(1000);
digitalWrite(5, LOW);
     
}

 



Go Up