Problème Programmation Anémomètre

Bonjour à tous,

Je vous écris aujourd’hui après quelques jours de galère.

J’ai comme projet de crée grâce à Arduino un anémomètre qui affiche la vitesse du vent et qui au dessus de 30 km/h d’afficher qu’il y a un danger à l’écran et même avertir les personnes autour grâce à un haut-parleur.

L’anémomètre envoie simplement un signal à chaque demi-tour effectuer donc j’ai pris en compte ce nombre de tour pour ensuite mon servir dans mon programme.

Alors la mesure marche parfaitement mais dès que je met l’écran et le haut-parleur cela bug completement (0 km/h afficher et haut-parleur qui marche tous le temps).

J’aimerai donc votre aide pour m’orienter vers la résolution de mon problème.

Voici mon code :

#include<LiquidCrystal.h>
LiquidCrystal lcd(8,9,4,5,6,7); //Déclaration des broches de l'afficheur A FINIR
int nbrtour = 0;                // Indique que la variable commence a 0
float nbtour;                   // Definie la variable du nombre de tour
float vitessems;                // Definie la variable vitesse en m/s
float vitessekm;                // Definie la variable en km/h
int piezoPin=30;
int anemometrePin=2;
void setup()
{
  pinMode (anemometrePin, INPUT);                                //Entree pour signal anemometre
  pinMode (piezoPin, OUTPUT);                              //Sortit pour le Haut-Parleur
  attachInterrupt (0, anemometre, RISING);           // capteur de front montant
  lcd.begin(16, 2);
  Serial.begin(9600);//Regle la taille de l'ecran LCD
}

void loop()
{
  delay(1000);
  nbtour=nbrtour/2;                     //Convertie le nombre d'impulsions en nombre de tour
  vitessems=2 * 3.1415 * 0.09 * nbtour; //Convertie le nombre de tour en une vitesse en m/s

  vitessekm=vitessems * 3.6;            //Vitesse en m/s passe en km/h
  lcd.setCursor(2,0);
  Serial.print(vitessekm);
  lcd.setCursor(2,1);
  lcd.print("km/h");
  nbrtour = 0;
  delay(1000);
  lcd.clear();
  
  if (vitessekm < 30)
{
  lcd.setCursor(2,0);
  lcd.print("AUCUN DANGER");
  delay(2000);
  lcd.clear();
}
  if (vitessekm >= 30)
{
  lcd.setCursor(2,0);
  lcd.print("DANGER ELEVER");
  tone(30,1000,1000); //Broche, Fréquence, Durée
  delay(1000);
  lcd.clear();
}
}

void anemometre()
{
    nbrtour++; /*La pin recoie un signal, la valeur s'incremente de 1*/
}

Hésité pas à me donner aussi des conseils pour faire une programme plus court ou simple. Je suis débutant.
Bien sur, les commentaires sont la pour m’aider en espérant qu’ils vous aident aussi

Bien Cordialement

c'est illisible avec la balise de "quote" --> corrigez votre post ci dessus et rajoutez les code tags autour du code:

[code]

[color=blue]// votre code ici[/color]

[/code]

.

ça doit ressembler à cela:

// votre code ici

(faites aussi ctrl-T (PC) or cmd-T (Mac) dans l'IDE avant de copier le code pour qu'il soit indenté correctement)


de manière générale quand on utilise les interruptions on a besoin de variables "[url=https://www.arduino.cc/reference/en/language/variables/variable-scope--qualifiers/volatile/]volatile[/url]" et de penser à gérer des sections critiques. par exemple que pensez vous que la calcul va donner si une interruption arrive quand vous calculez nbtour = nbrtour / 2; ou encore   vitessems = 2 * 3.1415 * 0.09 * nbtour; dans la loop ?

attention aussi aux débordements de variables un int ça ne compte pas très loin.

Voila dans un premier temps le message vient d'être modifié comme voulu. Désolé de la mauvaise mise en place du début.

Pour répondre à votre question, je pense que si une interruption arrive cela va créer un bug dans la programme et que cela va afficher ou alors ne pas être prit en compte dans le processus de calcul.

Une idée ducoup de comment résoudre ce problème ?

oui ça va faire un bug...

donc d'une part il faut déclarer nbrtour comme volatile (et mieux en unsigned int) et dans la loop créer une section critique avec noInterrupts() et interrupts() et entre les 2 dupliquer nbrtour dans une variable locale à la boucle et le remettre à 0

void loop()
{
  unsigned int nbrtourCopie;
  noInterrupts(); // désactive les interruptions
  nbrtourCopie =   nbrtour;
  nbrtour = 0;
  interrupts(); // réactive les interruptions

  // ici maintenant vous êtes tranquille vous avez dans nbrtourCopie la valeur lue que vous utilisez pour les calculs

}

Attention cependant, votre loop() tourne super vite par rapport à votre éolienne, donc que se passe-t-il selon vous la plupart du temps ?

J-M-L:
Attention cependant, votre loop() tourne super vite par rapport à votre éolienne

Pas tant que cela, la loop() dure 3 secondes (et le programme fait en sorte qu'elle dure le même temps quelle que soit la vitesse - avec ou sans tone() ).
Je calcule que pour V=30 km/h, ça donne nbtours = 14.75, soit environ 30 interruptions.
On aurait bien sûr intérêt à augmenter le temps de mesure, pour gagner en stabilité.
Evidemment la formule vitessems = 2 * 3.1415 * 0.09 * nbtour; devra être adaptée.

biggil:
Pas tant que cela, la loop() dure 3 secondes (et le programme fait en sorte qu'elle dure le même temps quelle que soit la vitesse - avec ou sans tone() ).
Je calcule que pour V=30 km/h, ça donne nbtours = 14.75, soit environ 30 interruptions.
On aurait bien sûr intérêt à augmenter le temps de mesure, pour gagner en stabilité.
Evidemment la formule vitessems = 2 * 3.1415 * 0.09 * nbtour; devra être adaptée.

ah oui j'avais zappé les delay()... si j'étais vous je les dégagerais et j'utiliserai millis()... :slight_smile:

essayez avec les suggestions ci dessus et dites moi déjà comment ça se comporte avec volatile et la section critique

Bon bah voila, je crois avoir fait tous ce qui est demandé sauf la fonction millis que je ne comprend pas. Voila comment je l’avais faite :

 if(temps - millis() > 500)

Sinon le code fait comme vous avez demandé est ici : Votre avis ?

#include<LiquidCrystal.h>
LiquidCrystal lcd(8,9,4,5,6,7); //Déclaration des broches de l'afficheur A FINIR
unsigned int nbrtour = 0;        // Indique que la variable commence a 0
unsigned int nbrtourCopie;       // Definir la valeur du nombre de tour en copie pour calcul
float nbtour;                   // Definie la variable du nombre de tour
float vitessems;                // Definie la variable vitesse en m/s
float vitessekm;                // Definie la variable en km/h
char compteur = 0;
unsigned long temps = millis();
#define piezoPin 4


void setup()
{
  pinMode (2, INPUT);                                //Entree pour signal anemometre
  pinMode(piezoPin, OUTPUT);                             //Sortit pour le Haut-Parleur
  attachInterrupt (0, anemometre, RISING);           // capteur de front montant
  lcd.begin(16, 2);                                  //Regle la taille de l'ecran LCD
  Serial.begin(9600);
}

void loop()
{
  delay(1000); // 1 Seconde de Mesure
  noInterrupts(); // désactive les interruptions
  nbrtourCopie = nbrtour;
  nbtour=nbrtourCopie/2;                //Convertie le nombre d'impulsions en nombre de tour
  nbrtour = 0;
  vitessems=2 * 3.1415 * 0.09 * nbtour; //Convertie le nombre de tour en une vitesse en m/s

  vitessekm=vitessems * 3.6;            //Vitesse en m/s passe en km/h
  lcd.setCursor(2,0);
  lcd.print(vitessekm);
  lcd.setCursor(2,1);
  lcd.print("km/h");
  delay(1000);
  lcd.clear();
  
  if (vitessekm < 30)
{
  lcd.setCursor(2,0);
  lcd.print("AUCUN DANGER");
  delay(2000);
  lcd.clear();
  interrupts(); // réactive les interruptions
}

  if (vitessekm >= 30)
{
  lcd.setCursor(2,0);
  lcd.print("DANGER ELEVER");
  tone (piezoPin,330); //Broche, Fréquence, Durée
  delay(2000);
  digitalWrite(piezoPin, LOW);
  lcd.clear();
  interrupts(); // réactive les interruptions
}


}

void anemometre()
{
    nbrtour++; /*La pin recoie un signal, la valeur s'incremente de 1*/
}

En tous cas Merci énormément de votre aide

non ce n'est pas ce que j'ai conseillé...

--> où est la variable volatile?
--> la section critique doit être réduite à sa plus simple expression comme indiqué plus haut dans mon code...

  unsigned int nbrtourCopie;
  noInterrupts(); // désactive les interruptions
  nbrtourCopie =   nbrtour;
  nbrtour = 0;
  interrupts(); // réactive les interruptions

  // ici maintenant vous êtes tranquille vous avez dans nbrtourCopie la valeur lue que vous utilisez pour les calculs


  // C'EST ICI QUE VOUS FAITES LE BOULOT D'AFFICHAGE

Pour la gestion par millis(), c'est juste dans l'autre sens.. if(millis() - temps > 500) {...} (en supposant que temps c'est la valeur de millis() la dernière fois que vous avez effectué les calculs --> avec 500 ça vous ferait lire le compteur 2 fois par secondes, c'est un peut trop... plutôt toutes les 5 ou 10 secondes ce serait mieux --> 5000 ou 10000

#include<LiquidCrystal.h>
LiquidCrystal lcd(4,5,6,7,8,9); //Déclaration des broches de l'afficheur A FINIR
unsigned int nbrtour = 0;        // Indique que la variable commence a 0
unsigned int nbrtourCopie;       // Definir la valeur du nombre de tour en copie pour calcul
float nbtour;                   // Definie la variable du nombre de tour
float vitessems;                // Definie la variable vitesse en m/s
float vitessekm;                // Definie la variable en km/h
char compteur = 0;
unsigned long temps = 0;
unsigned long temps2 = 0;
#define piezoPin 4


void setup()
{
  pinMode (2, INPUT);                                //Entree pour signal anemometre
  pinMode(piezoPin, OUTPUT);                             //Sortit pour le Haut-Parleur
  attachInterrupt (0, anemometre, RISING);           // capteur de front montant
  lcd.begin(16, 2);                                  //Regle la taille de l'ecran LCD
  Serial.begin(9600);
  temps = millis();
}

void loop()
{
  delay(1000); // 1 Seconde de Mesure
  noInterrupts(); // désactive les interruptions
  nbrtourCopie = nbrtour;
  nbtour=nbrtourCopie/2;                //Convertie le nombre d'impulsions en nombre de tour
  nbrtour = 0;
  vitessems=2 * 3.1415 * 0.09 * nbtour; //Convertie le nombre de tour en une vitesse en m/s

  vitessekm=vitessems * 3.6;            //Vitesse en m/s passe en km/h
  lcd.setCursor(2,0);
  lcd.print(vitessekm);
  lcd.setCursor(2,1);
  lcd.print("km/h");
  if (millis ()> (temps+2000))
  {
  lcd.clear();
  temps = temps+2000;
  }
  
  if (vitessekm < 30)
{
  lcd.setCursor(2,0);
  lcd.print("AUCUN DANGER");
  if (millis() > (temps2 + 4000))
  {
  lcd.clear();
  interrupts(); // réactive les interruptions
  temps2 = temps2+2000;
  }
}

  if (vitessekm >= 30)
{
  lcd.setCursor(2,0);
  lcd.print("DANGER ELEVER");
  tone (piezoPin,330); //Broche, Fréquence, Durée
  if (millis() > (temps2 + 4000))
  {
  lcd.clear();
  interrupts(); // réactive les interruptions
  temps2 = temps2+2000;
  }
}


}

void anemometre()
{
    nbrtour++; /*La pin recoie un signal, la valeur s'incremente de 1*/
}

Voila maintenant mon programme mais je tombe sur un problème. Mon écran arduino affiche n’importe quoi même si mon capteur envoie un signal cela ne change rien.
Possible de m’aider la dessus maintenant ?
Merci d’avance

Pourquoi ne suis-tu pas le conseil de J-M-L ? Tu réactives tes interruptions bien trop tard !

Par ailleurs ta gestion du temps est complètement fausse.
Ce qui est important, c'est que ta fonction loop() dure un temps précis.
Au départ, tu avais mis 3000 ms.
Cette valeur a une influence sur ta formule de calcul des vitesse :

 vitessems=2 * 3.1415 * 0.09 * nbtour;

le coefficient 0.09 est valable pour une certaine durée de la loop().

Tu comptes les interruptions (=le nombre de 1/2 tours) pendant une durée T.
Pour une vitesse de vent donnée, plus T est grand, plus le comptage est grand.
Il convient donc de t'assurer que ce coefficient 0.09 correspond bien à un comptage sur 3 secondes, sinon tu vas obtenir une vitesse, certes, mais erronée.

J-M-L te suggère d'utiliser millis() à la place de delay(). Pourquoi ?
C'est justement pour avoir une cadence de mesure précise.
Donc toute ta boucle loop doit être encadrée par:

unsigned long tprecedent = 0;
void loop() 
{
  unsigned long tnow= millis();
  unsigned long dt = tnow - tprecedent;
  if ( dt >= 3000L )
  {
    tprecedent= tnow;
    //
    // refaire le calcul du cofficient (0.09) en utilisant dt (qui peut être supérieur à 3000)
    ...
    vitessekm = 2 * 3.1415 * Coefficient_recalculé * nbtour; 
    // faire diverses choses, selon la vitesse; y compris des attentes par delay() ou tone(...)
    // en prenant soin de ne pas dépasser 3 secondes
    ...
  }
}

Nota: il conviendrait également de sauter le 1er comptage, car on ne sait pas combien de temps ce 1er comptage a duré.

et quand on désactive les interruptions, il faut s'attendre à ce que de nombreuses fonction qui dépendent des interruptions ne marchent plus... pas surpris que le LCD par exemple ne fonctionne pas bien.. il faut garder la partie critique aussi courte que possible - pour la 3ème fois...

  unsigned int nbrtourCopie;
  noInterrupts(); // désactive les interruptions
  nbrtourCopie =   nbrtour;
  nbrtour = 0;
  interrupts(); // réactive les interruptions

avec éventuellement une capture de millis() juste après le noInterrupts() si vous utilisez l'approche par millis()