Problème avec While et fonction OU (||) - [Résolu]

Bonjour à tous,

Je débute sur Arduino et sur le forum (j'ai déjà réalisé quand même quelques projets qui fonctionnent).

J'ai commencé la réalisation d'un automatisme de portail sous Arduino avec 2 moteurs de récupération.

Je rencontre un petit problème sur lequel j'ai passé quelques heures sans succès.

J'ai besoin de réaliser une boucle qui sort lorsque l'une ou l'autre des 2 conditions et vrai:

While (condition1 || condition2){
mise à jour condition 1
mise à jour condition 2
}
suite du programme

Il se trouve que la fonction "ou" (||) ne fonctionne pas. Si je place une seule une des 2 condition sans le "ou" || cela fonctionne très bien mais si je mets les 2 avec || le programme ne sort pas de la boucle alors que j'ai vérifié avec le moniteur série les variables sont OK et à un moment elles devraient sortir de la boucle...

Idem avec la fonction If

If(condition1 || condition2)...

Bien sûr, à chaque fois mon programme est bien compilé et ne retourne pas d'erreurs.

J'ai bricolé avec 2 boucles If imbriquée tout fonctionne, mais je trouverais plus élégant de passer par while si je souhaite rajouter d'autres conditions.

Je pense que je ne maîtrise pas correctement la fonction While ou la la fonction "ou" ||, j'ai cherché bien sûr sur le net, j'ai trouvé des exemples similaires avec "et" && mais pas avec "ou" ||...

Voici ci-dessous mon code dans son état actuel, pas terminé en cours de développement, il fonctionne pour l'instant sur une maquette et seulement sur un des moteurs.

Je vous remercie par avance pour votre aide

Frédéric

//Définition des variables

int OG=4;                  //OG= broche ouverture gauche
int FG=5;                  //FG= broche fermeture gauche
int DOG=8;                 //DOG= broche détecteur ouverture gauche
int DFG=9;                 //DFG= broche détecteur fermeture gauche
int CG=A0;                //mesure_CG= broche de mesure du courant gauche
int CD=A1;                //mesure_CFG= broche de mesure du courant droit

byte etat_DOG;            //etat_DOG= valeur du capteur de position ouverture gauche (HIGH ou LOW)
byte etat_DFG;            //etat_DOG= valeur du capteur de position fermeture gauche (HIGH ou LOW)
byte etat_DOD;            //etat_DOG= valeur du capteur de position ouverture droit (HIGH ou LOW)
byte etat_DFD;            //etat_DOG= valeur du capteur de position fermeture droit HIGH ou LOW)
int valeur_CG=0;          //CG= valeur du courant gauche (de 0 à 1024)
int valeur_CD=0;          //CD= valeur du courant droit (de 0 à 1024)

void setup()               //ces lignes sont éxécutées une seule fois lors du démarrage de l'Arduino
 
{
pinMode( OG , OUTPUT);      //La broche OG est utilisée en sortie
pinMode( FG , OUTPUT);      //La broche FG est utilisée en sortie
pinMode( DOG , INPUT);      //La broche DOG est utilisée en entrée
pinMode( DFG , INPUT);      //La broche DFG est utilisée en entrée

}

void loop()                 //répéter indéfiniment
{
Fermeture ();               //exécuter le sous programme "Fermeture"
delay( 500); 
Ouverture ();               //exécuter le sous programme "Ouverture"
delay( 2000 );              //attendre 2 secondes
Fermeture ();               //exécuter le sous programme "Fermeture"               
delay( 2000 );              //attendre 2 secondes
}

//Partie des sous programmes ------------------------------------------------------------------------------------------------------------------------------------------------------


// Sous programme "Ouverture"

void Ouverture()                  
{
digitalWrite( OG , HIGH );                    //mettre la sortie "OG" à l'état haut (5 Volts) pour lancer l'ouverture du vantail gauche


etat_DOG = digitalRead(DOG);                //lire l'état du Detecteur Ouverture Gauche et le mettre dans la variable etat-DOG
valeur_CG = analogRead(CG);                 //mesurer le Courant Ouverture Gauche et le mettre dans la variable mesure_DOG

while (etat_DOG == LOW || valeur_CG <500){   //tant que le Detecteur Ouverture Gauche est à l'état LOW et le Courant Ouverture Gauche est inférieur à 500, faire en boucle
etat_DOG = digitalRead(DOG);                  //lire l'état du Detecteur Ouverture Gauche et le mettre dans la variable etat-DOG
valeur_CG = analogRead(CG);                 //mesurer le Courant Ouverture Gauche et le mettre dans la variable mesure_DOG
}
digitalWrite( OG , LOW );                     //dès qu'une des conditions ci-dessus est active mettre la sortie "OG" à l'état bas (0 Volts) pour arrêter l'ouverture du vantail gauche
}


//Sous programme "Fermeture"
void Fermeture()                  
{
digitalWrite( FG , HIGH );                    //mettre la sortie "FG" à l'état haut (5 Volts) pour lancer la fermerture du vantail gauche

etat_DFG = digitalRead(DFG);
while (etat_DFG == LOW){
etat_DFG = digitalRead(DFG);
}
                 
digitalWrite( FG , LOW );                     //mettre la sortie "FG" à l'état bas (0 Volts) pour arrêter la fermerture du vantail gauche
}

while (etat_DOG == LOW || valeur_CG <500){
//tant que le Detecteur Ouverture Gauche est à l'état LOW
et le Courant Ouverture Gauche est inférieur à 500, faire en boucle

Le code est en contradiction avec le commentaire.
ET : &&
OU : ||

J'ai bricolé avec 2 boucles If imbriquée tout fonctionne,

2 if imbriqué fonctionnent comme un AND et pas comme un OR
Change ton || par &&

J'ai besoin de réaliser une boucle qui sort lorsque l'une ou l'autre des 2 conditions et vrai:

je vois deux silutions
a) (folklorique)

while (1 == 1) { // boucle infinie)
if Cond1 break; // sort si cond1
if Cond2 break; // ou cond2
....
}

b) la negation de "l'une ou l'autre des condistions est vraie" est "cond1 est fausse ou cond2 est fausse"

while ((! cond1) || (!cond2)) { // j'espère, ne sachant pas C par choeur, que ! designe la negation logique
....
}

Bonjour, la solution donnée par le collègue au dessus de mon message semble être nickel.

Mais si je peux me permettre quelques conseils pour la suite. En faisant une boucle comme ça le reste de ton programme est bloqué.
Si tu veux faire évoluer ton système tu vas être.. Bloqué :slight_smile:

Si j'ai bien suivi ta boucle while va tourner le temps de la manœuvre du portail gauche ?
Alors imaginons que tu veuille arrêter cette manœuvres ou l'inverser, grâce à ton bouton ou un signal rf d'une télécommande que tu pourrais fabriquer ?

Tu devrais éviter de bloquer ta loop par ces delay.
Essaye soit d'activer la fermeture ouverture par un bouton poussoir, dont l'appuie sera détecté
Parce qu'il faudra bien un jour déclencher les actions par l'extérieur.
Puis tu peux à chaque tour de loop appeler une fonction par exemple

miseAJourDODetCG
Qui va exécuter les conditions if décrite et au quel cas passer OG à low.
Ce qui permet d'avoir ta loop qui tourne sanq discontinuité et rajouter des fonctions en parallèle

Dont vérifier si les boutons on était appuyé. Faire clignoter un fare etc ou vérifier la réception d'une trame rf :slight_smile:

C'est pas pour faire mon je sais tout hein
Je suis par là et c'est chiant de devoir remanié le programme entièrement pour rajouter des fonctionnalités

while (1 == 1)

Drôle d’écriture, écrire while(1) donne exactement le même résultat.

Voir ici un exemple de programme de contrôle d'un portail écrit avec une machine à états. Si ça peut vous aider...

Drôle d'écriture, écrire while(1) donne exactement le même résultat.

Et aussi :

 for (;;)

Drôle d'écriture, écrire while(1) donne exactement le même résultat.

Pourquoi est elle drole.
A noter que certains langages (bash) ont une logique inversee (0 veut dire vrai -il n'y a pas d'erreurs-) et fonctionnent parfaitement.
la condition (1 == 1) est independante d'une convention (qui est une source de drôles d'ambiguités )

et fait la drôle d'hypothèse que l'optimiseur de C++ est efficace, assez pour ne pas s'ennuyer avec de pures conventions.....

Bonjour,

Tout d'abord merci à tous pour vos réponses multiples et rapides.

En effet hbachetti mon code et en opposition avec le commentaire... Je souhaite que tant que le Détecteur Ouverture Gauche est à l'état LOW ou le Courant Ouverture Gauche est inférieur à 500, faire en boucle le rafraîchissement de ces 2 conditions jusqu'à qu'une des 2 s'active pour déclencher l’arrêt du moteur.

Pour résumer, si le courant dépasse le seuil ou si le détecteur s'actionne, le moteur s'arrête.

Je pense d’après vos réponses que je n'ai pas compris le fonctionnement de la bouche while que j'utilise pour la première fois... je vais refaire des essais

Désolé Charly26, je n'en suis pas encore aux boutons ou télécommande, pour l'instant je veux que ma maquette s'ouvre et se ferme en continu. Je verrai par la suite pour intégrer les boutons de télécommande à l'aide d'une interruption qui "réveille" l'Arduino, mais je n'en suis pas encore là!

La maquette, pour l'instant, n'a qu'un moteur sur lequel je teste les capteurs de fin de course et le capteur de courant (voir photo) jointe.

Il y aura bien sûr ensuite les délais de sécurité, le démarrage progressif, la barrière IR, le gyro... mais ce sera plus tard!

Pour info ci-dessous le code avec les if qui lui fonctionne très bien mais très maladroit :

debut:
etat_DOG = digitalRead(DOG);                //lire l'état du Detecteur Ouverture Gauche et le mettre dans la variable etat-DOG
valeur_CG = analogRead(CG);                 //mesurer le Courant Ouverture Gauche et le mettre dans la variable mesure_DOG

if (etat_DOG == LOW)                        //si le Detecteur Ouverture Gauche est à l'état LOW
{
  if (valeur_CG < 220)                    //si le Courant Ouverture Gauche est inférieur à 220
    {
    goto debut;                           //retourner au début de la boucle
    }
  else{ 
  digitalWrite( OG , LOW );               //arreter le moteur
  }
}

else{ 
digitalWrite( OG , LOW );                 //arreter le moteur
}

}

Je vais faire d'autres tests, approfondir la fonction while et vous tiendrai informé du projet. Dès que j'ai trouvé la bonne solution à mon problème, je publie le code ici pour que ça puisse servir à d'autres.

Mon but, à travers ce projet, est d'apprendre donc vous me pardonnerez mes petites erreurs et imperfections de code.

Je vous mettrai également le schéma de principe ce sera plus clair.

J'aurai gagné du temps à acheter un automatisme tout prêt, mais ça n'aurait pas le même charme :wink:

Encore merci à tous

Frédéric

Effectivement le goto fait un peu cochon.

Au risque d'insister :

savoriano:
2 if imbriqué fonctionnent comme un AND et pas comme un OR
Change ton || par &&

Si tes deux IF imbriqués te donnent satisfaction, il s'agit bien d'un ET, et non pas d'un OU.

  Tant que capteur non atteint ET courant < 220 {
    relire capteur
    relire courant
  }
  stop

En simplifiant :

// si les variables etat_DOG et valeur_CG sont inutiles par ailleurs
  while (digitalRead(DOG) == LOW && analogRead(CG) < 220) {}
  digitalWrite( OG , LOW );
// ou
  while (digitalRead(DOG) == LOW && analogRead(CG) < 220);
  digitalWrite( OG , LOW );
// si les variables etat_DOG et valeur_CG sont utiles par ailleurs
  while ((etat_DOG = digitalRead(DOG)) == LOW && (valeur_CG = analogRead(CG)) < 220);
  digitalWrite( OG , LOW );

L'interruption c'est une très bonne idée. Mais peut-être que tu risque d'être limité par, qu'est-ce qui peu déclencher une interruption ?

Bonjour,

Merci encore à tous pour votre aide et vos conseils, j'ai fini par comprendre mon erreur, quel boulet !!! J'ai honte, c'était trop simple... :confused:

Voici mon nouveau code qui fonctionne maintenant très bien:

//Programme réalisé par ...
//Le 14/08/2019
//Ver 6


//Définition des variables

int OG=4;                  //OG= broche ouverture gauche
int FG=5;                  //FG= broche fermeture gauche
//int OD=6;                  //OD= broche ouverture droite
//int FD=7;                  //FD= broche fermeture droite
int DOG=8;                 //DOG= broche détecteur ouverture gauche
int DFG=9;                 //DFG= broche détecteur fermeture gauche
//int DOD=8;                 //DOD= broche détecteur ouverture droit
//int DFD=9;                 //DFD= broche détecteur fermeture droit
int CG=A0;                //mesure_CG= broche de mesure du courant gauche
int CD=A1;                //mesure_CFG= broche de mesure du courant droit

byte etat_DOG;            //etat_DOG= valeur du capteur de position ouverture gauche (HIGH ou LOW)
byte etat_DFG;            //etat_DOG= valeur du capteur de position fermeture gauche (HIGH ou LOW)
byte etat_DOD;            //etat_DOG= valeur du capteur de position ouverture droit (HIGH ou LOW)
byte etat_DFD;            //etat_DOG= valeur du capteur de position fermeture droit HIGH ou LOW)
int valeur_CG=0;          //CG= valeur du courant gauche (de 0 à 1024)
int valeur_CD=0;          //CD= valeur du courant droit (de 0 à 1024)

void setup()               //ces lignes sont éxécutées une seule fois lors du démarrage de l'Arduino
 
{
//Serial.begin(9600); // initialise la communication série
//pinMode( 13 , OUTPUT);    //La broche 13 est utilisée en sortie
pinMode( OG , OUTPUT);      //La broche OG est utilisée en sortie
pinMode( FG , OUTPUT);      //La broche FG est utilisée en sortie
//pinMode( OD , OUTPUT);      //La broche OD est utilisée en sortie
//pinMode( FD , OUTPUT);      //La broche FD est utilisée en sortie
pinMode( DOG , INPUT);      //La broche DOG est utilisée en entrée
pinMode( DFG , INPUT);      //La broche DFG est utilisée en entrée

}

void loop()                 //répéter indéfiniment
{
Fermeture ();               //exécuter le sous programme "Fermeture"
delay( 500);                //attendre 2 secondes
Ouverture ();               //exécuter le sous programme "Ouverture"
delay( 2000 );              //attendre 2 secondes
Fermeture ();               //exécuter le sous programme "Fermeture"               
delay( 2000 );              //attendre 2 secondes
}

//Partie des sous programmes ------------------------------------------------------------------------------------------------------------------------------------------------------


// Sous programme "Ouverture"

void Ouverture()                  
{
digitalWrite( OG , HIGH );                      //mettre la sortie "OG" à l'état haut (5 Volts) pour lancer l'ouverture du vantail gauche
delay( 1500);                                   // ne pas prendre en compte les 300 premières mesures sup à 300 avec un 470nF en integration, sera corrigé plus tard avec le démarage en douceur par PWM

etat_DOG = digitalRead(DOG);                    //lire l'état du Detecteur Ouverture Gauche et le mettre dans la variable etat-DOG
valeur_CG = analogRead(CG);                     //mesurer le Courant Gauche et le mettre dans la variable mesure_DOG

while (etat_DOG == LOW && valeur_CG < 200){     //tant que le Detecteur Ouverture Gauche et le Courant Gauche sont en dessous du seuil faire...
  
etat_DOG = digitalRead(DOG);                    //lire l'état du Detecteur Ouverture Gauche et le mettre dans la variable etat-DOG
valeur_CG = analogRead(CG);                     //mesurer le Courant Gauche et le mettre dans la variable mesure_DOG
//Serial.println(valeur_CG, DEC);
}

digitalWrite( OG , LOW );                       //arreter le moteur

}


//Sous programme "Fermeture"
void Fermeture()                  
{
digitalWrite( FG , HIGH );                    //mettre la sortie "FG" à l'état haut (5 Volts) pour lancer la fermerture du vantail gauche

etat_DFG = digitalRead(DFG);
while (etat_DFG == LOW){
etat_DFG = digitalRead(DFG);
}
                 
digitalWrite( FG , LOW );                     //mettre la sortie "FG" à l'état bas (0 Volts) pour arrêter la fermerture du vantail gauche
}

Comme vous pouvez le constater, je me suis amusé à enregistrer la courbe de consommation du moteur au démarrage avec le moniteur série et en faire une courbe avec les données recopiées sur tableur, pour le fun le résultat en pièce jointe. Dans le code ci-dessus, les puristes verront que je n'enregistre pas depuis la mise en route mais après le délai, c'était pour déterminer la valeur optimale de courant à ne pas dépasser, pour la version finale, j'ai mis la communication série en commentaire.

Pour info, j'utilise pour commander les moteurs des ponts en H avec deux BTS7960B que l'on trouve pas chers (Lien)et qui intègrent un capteur de courant. Le problème est qu'il y a donc, sur la carte, un capteur par circuit qu'il faut coupleur les deux avec 2 diodes et un circuit intégrateur RC pour économiser 2 entrés analogiques sur l'Arduino.

Pour ce qui est de la future utilisation des interruptions, ce sera uniquement pour réveiller d'Arduino par la télécommande car dans le cas de l'ouverture/fermeture d'un portail 2 fois par jour, il va passer le plus clair de son temps en veille. J'ai déjà utilisé ce principe sur ma commande de store et ça fonctionne très bien depuis déjà quelques années.

Peut-être aussi une version avec ESP32 pour commande par smartphone et wifi intégrée, mais ce sera pour bien plus tard...

Encore merci à tous, dans le prochain post, je vous mettrai un schéma propre du montage prévisionnel.

Frédéric

Comme convenu, le schéma simplifié, j'ai re-mappé les broches comme ci-dessous:

//N°    Broche        E/S   Fonction
//0     RXD   
//1     TXD   
//2     INT0          E     Télécommande
//3     INT1 / PWM    E     détecteur ouverture droit
//4                   E     détecteur fermeture droit
//5     PWM           S     Ouverture Droit
//6     PWM           S     Fermeture droit
//7                   E     détecteur ouverture gauche
//8                   E     détecteur fermeture gauche
//9     PWM           S     Ouverture Gauche
//10    PWM           S     Fermeture Gauche
//11    PWM   
//12                  E     Barrière IR
//13                  S     Clignotant
//A0                  E     Courant Gauche
//A1                  E     Courant Droit
//A2      
//A3      
//A4    SDA   
//A5    SCL

Je vais peut-être, pour la suite, ouvrir un sujet dans la section "projet" afin que tout le monde puisse en profiter.

Frédéric