Go Down

Topic: Faire une boucle à condition ? (Read 216 times) previous topic - next topic

iFrostizz

Bonsoir,
J'ai un projet Terminale SI à rendre pour la fin de l'année, et il se trouve que j'ai eu l'idée, à l'aide d'un joystick et d'un écran LCD de pouvoir naviguer entre les différents menus qui nous délivreraient plusieurs infos: ex Vitesse, Km parcourus, etc ...

J'ai donc commencé un code, mais je me retrouve bloqué à cause de mon petit manque d'expérience (il y a énormément à apprendre ^_^).

Pour tout vous expliquer, je voudrais utiliser les coordonnées du Joystick en Y pour dire:
Si Y_pin==0, alors on descend de menu (et accessoirement, si menu<=0, alors on passe au menu maxi, par exemple de 5).
Pareil pour Y_pin>=1000, on monte de menu et si menu>=6, alors on passe au menu 1.

Le problème étant que ma boucle se fait à l'infini (je pense) Et j'ai donc pensé à deux solutions:
- Passer dans la boucle une seule fois
- Sortir de la boucle si et seulement si elle est vraie

Voici le code:

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

const int rs = 12, en = 11, d4 = 6, d5 = 5, d6 = 4, d7 = 3;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

const int SW_pin = 2; // digital pin connected to switch output
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output

void setup() {
  lcd.begin(16, 2);

  pinMode(SW_pin, INPUT);
  digitalWrite(SW_pin, HIGH);
  Serial.begin(9600);

  int menu=0;
}

void loop() {
 
  //
 
  //lcd.clear();
  //lcd.setCursor(0,0);
  //lcd.print(analogRead(X_pin));
  //lcd.setCursor(0,1);
  //lcd.print(analogRead(Y_pin));
  //delay(100);

  //
lcd.clear();
lcd.setCursor(0,0);
lcd.print(analogRead(Y_pin));


  if (analogRead(Y_pin)>1000)
  {
    int menu=menu++;
    if ((menu)>=6)
      menu=0;
    lcd.setCursor(0,1);
      lcd.print("menu");
    lcd.setCursor(5,1);
      lcd.print(menu);
  }
       
  if(analogRead(Y_pin)==0)
  {
    int menu=menu--;
    if ((menu)<=0)
      menu=5;
    lcd.setCursor(0,1);
      lcd.print("menu");
    lcd.setCursor(5,1);
      lcd.print(menu);
  }
       
delay(100);

}


Merci beaucoup de votre attention, passez une bonne soirée

hbachetti

Salut

Le problème est que quand la lecture de Y est supérieure à 1000, cette condition sera vraie un certain nombre de fois.
Quand la lecture de Y est égale à 0, cette condition sera vraie aussi un certain nombre de fois.
Il faudrait utiliser une variable d'état (globale ou statique) et exécuter les actions seulement lorsque cet état change.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

fdufnews

#2
Oct 18, 2018, 08:43 am Last Edit: Oct 18, 2018, 08:46 am by fdufnews
Bonjour,

Si tu ne veux pas que menu s'incrémente ou se décrémente en boucle, tu as plusieurs solutions
  • L'une consiste à tester que le joystick est revenu à une position neutre avant de reprendre la lecture de celui-ci.
    A la fin du premier if par exemple, tu peux faire une boucle while qui attend que analogRead(Y_pin) retourne une valeur inférieur au seuil (1000 dans ce cas). Cette solution est simple à mettre en oeuvre par contre le programme est bloqué tant que le joystick n'est pas revenu au neutre.
  • Une autre solution consisterait à introduire une temporisation. Il faudrait donc introduire une variable qui indiquerait au programme qu'une action a bien été prise en compte et de ne pas prendre en compte le joystick avant l'expiration d'un hors temps. Il faudrait que tu regardes le fonctionnement de l'instruction millis() pour gérer ce hors temps sans pour autant bloquer l'exécution du programme.

Quelques remarques:
  • il vaut mieux utiliser des variables (ou des define) pour fixer la valeur des seuils. Comme ça les paramètres du programme sont regroupés à un seul endroit (au début du code ou dans un .h) et si tu utilises plusieurs fois la valeur dans ton code tu es certain qu'il n'y aura pas d'incohérence entre les valeurs.
  • tester 0 et 1000 comme limites à la lecture d'un joystick c'est s'exposer à rater des actions. Avec le bruit de conversion tu pourrais très bien ne pas tout le temps atteindre ces valeurs. Je verrais mieux des seuils à 50 et 950 par exemple.
  • une petite incohérence dans ton code.
    Lorsque tu incrémentes menu tu testes si la variable dépasse 5 et tu la remets à zéro. Donc tu considères que menu peut varier de 0 à 5.
    Lorsque tu décrémentes menu tu testes si la variable est inférieur ou égale à zéro et tu la mets à 5. Donc tu considères que menu peut varier de 1 à 5.

lesept

Il faudrait utiliser une variable d'état (globale ou statique) et exécuter les actions seulement lorsque cet état change.
Tu devrais étudier la portée des variables : une variable est soit globale (donc définie en dehors d'une fonction, comme le setup et la loop), soit locale et dans ce cas elle n'est connue que dans le bloc (entre {}) où elle a été déclarée. Ta variable menu est déclarée et initialisée dans le setup. A la fin du setup, elle est effacée. Puis tu la recrées dans un bloc : à la fin de ce bloc, elle est effacée. Tu la recrées dans un autre bloc ensuite. Entre chaque bloc, il n'y a pas de passage d'information via cette variable.

Tu dois la déclarer avant le setup, une fois pour toutes, et tu pourras l'utiliser dans toutes tes fonctions ou blocs.
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

iFrostizz

Bonsoir, alors tout d'abord merci beaucoup pour vos réponses et remarques ! :)
Je m'adresse surtout à toi @fdufnews car le fait de faire une boucle où le joystick aurait par exemple atteint 950 et serait revenu à sa position initiale (mettons entre 500 et 550) était justement mon idée.
Mais le problème étant que je ne sais pas utiliser cette boucle. J'ai entendu parler du "do/while" mais je nen suis pas sur que cela va remédier à mon problème. Quelle serait la forme de cette fonction alors ? Merci encore, bonne soirée

dfgh

hello
un exemple
Code: [Select]
if (analogRead(Y_pin)>1000)
  {
    while(analogRead(Y_pin)>550){};//attendre que le joystick soit au point milieu(inf à 550)
    int menu=menu++;
    if ((menu)>=6)
      menu=0;
    lcd.setCursor(0,1);
      lcd.print("menu");
    lcd.setCursor(5,1);
      lcd.print(menu);
  }

iFrostizz

Merci beaucoup !! Ca fonctionne !!! :D
Alors maintenant, j'ai un léger problème. Comment faire pour que avant que je ne donne pas d'actions par le joystick, on ne sorte pas de la boucle (le but étant de laisser le texte écrit sur l'écran LCD et sans utiliser une temporisation car pas pratique) ?
Merci beaucoup, après je ne vous embêterais plus, promis :D
Bonne soirée à tous :)

dfgh

hello
une base de départ
Code: [Select]
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 6, d5 = 5, d6 = 4, d7 = 3;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int SW_pin = 2; // digital pin connected to switch output
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output
int calX = 0;
int calY = 0;
int menu=0;
void setup()
{
  lcd.begin(16, 2);
  pinMode(SW_pin, INPUT);
  digitalWrite(SW_pin, HIGH);
  Serial.begin(9600);
  lcd.setCursor(0,1);
  lcd.print("menu");
  calX = analogRead(X_pin);
  calY = analogRead(Y_pin);
}

void loop()
{
lcd.setCursor(5,1);
lcd.print(menu);
if (analogRead(Y_pin)>calY+100)
  {
    while(analogRead(Y_pin)>calY+100){};
    menu++;
    if ((menu)>=6){menu=0;} 
  }
if(analogRead(Y_pin)<calY-100)
  {
    while(analogRead(Y_pin)<calY-100){};
    menu--;
    if ((menu)<0){menu=5;}
  }
}

iFrostizz

Salut,

J'ai oublié de dire que j'avais réussi du coup, car le forum était down ce soir là. Merci en tout cas à tous pour votre aide.
Passez une bosse journée. :)

Go Up