Ecran LCD récalcitrant

Bonjour à tous,
Je me permet de poster ici car ça va bientôt faire 2 semaine que je m’acharne là dessus, et je ne trouve toujours pas.
Ce projet consiste en un petit bras robot, avec un moteur pas-à-pas et un servo, qui trempe tout seul un sachet de thé et qui le sort après 3 minutes. J’en suis actuellement à l’ajout d’un écran LCD mais cette étape s’avère plus compliquée que prévue.
Voici le code sans écran LCD :

#include <Servo.h> //inclure bibliothèque servo
#include <Stepper.h> //inclure bibliothèque moteur pas-à-pas

#define buzzer 12 //remplacer buzzer par 12

boolean premiereFois; //variable pour jouer le programme 1 seule fois

const int stepsPerRevolution = 1275;  // définir le nombre de pas 

int c = 0; //variable pour le buzzer

Servo myservo; 
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11); //pins du moteur p-à-p

void setup() 
{ 
  myservo.attach(13);  // servo sur broche 13
  myStepper.setSpeed(20); //vitesse moteur p-à-p
  premiereFois = true; // variable vraie
  pinMode(buzzer,OUTPUT); //buzzer est une sortie
}

 void loop()
{ 
 if (premiereFois) // si premiereFois est vraie
  {
   myStepper.step(-stepsPerRevolution); // moteur p-à-p amene le sachet à la tasse
   delay(500); //delai
   
   for (pos = 90; pos >= 0; pos -= 1) // pos du servo de 90° à 0° (descente)
    { 
      myservo.write(pos); // le servo va à 0°
      delay(15);  // delai
    }
    
   delay(180000); // temps d'infusion

   for (pos = 0; pos <= 90; pos += 1) // pos du servo de 0° à 90°
    {   
     myservo.write(pos); //le servo va à 90° (montée)
     delay(15); // delai
    }
    
  delay(500); // delai
  myStepper.step(stepsPerRevolution);  // moteur p-à-p enleve le sachet de la tasse
  delay(500); //delai
  
  for (pos = 90; pos >= 0; pos -= 1) // pos du servo de 90° à 0° (descente)
    { 
     myservo.write(pos); // le servo va à 0°
     delay(15); // delai
    }
    
  while(c!=500) // tant que c est différent de 500
   {
    digitalWrite(buzzer,HIGH);
    delay(1);//wait for 1ms
    digitalWrite(buzzer,LOW);
    delay(1);//wait for 1ms
    digitalWrite(buzzer,HIGH);
    delay(2);//wait for 2ms
    digitalWrite(buzzer,LOW);
    delay(2);//wait for 2ms     
    c++; //ajouter 1 à c
   }
    premiereFois = false; // definir premiereFois comme fausse
  }
}

Et voici le code de l’écran:

#include <LiquidCrystal.h>
signed short minutes, secondes;

char timeline[16];
LiquidCrystal lcd(2, 3,4, 5, 6, 7);
void setup() {
  // put your setup code here, to run once:
  lcd.begin(16, 2);
  lcd.print("TeaMachine Mk_VI ");
}

void loop() {
  // put your main code here, to run repeatedly:
    lcd.setCursor(0, 1);
sprintf(timeline,"%0.2d mins %0.2d secs", minutes, secondes);      
     lcd.print(timeline);
  
     delay(1000);
     secondes++;
  
     if (secondes == 60)
      {
       secondes = 0;
       minutes ++;
      }
     if (minutes == 60)
      {
       lcd.setCursor(0, 0);
       lcd.clear ();
       lcd.print("Le the est pret!");
      }
}

Les deux codes marchent très bien séparément mais ensembles ça ne colle pas >:( .
J’ai mis le setup du LCD dans le setup du “gros” programme et la déclaration des variables etc… avec les autres: je pense que le problème vient du fait que je ne place pas correctement le loop du LCD dans le “gros” loop :

#include <Servo.h> //inclure bibliothèque servo
#include <Stepper.h> //inclure bibliothèque moteur pas-à-pas
#include <LiquidCrystal.h> 

#define buzzer 12 //remplacer buzzer par 12

boolean premiereFois; //variable pour jouer le programme 1 seule fois

const int stepsPerRevolution = 1275;  // définir le nombre de pas 

int c = 0; //variable pour le buzzer

signed short minutes, secondes; 

char timeline[16]; 

LiquidCrystal lcd(2, 3,4, 5, 6, 7);
Servo myservo; 
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11); //pins du moteur p-à-p

void setup() 
{ 
  myservo.attach(13);  // servo sur broche 13
  myStepper.setSpeed(20); //vitesse moteur p-à-p
  premiereFois = true; // variable vraie
  pinMode(buzzer,OUTPUT); //buzzer est une sortie
  lcd.begin(16, 2);
  lcd.print("TeaMachine Mk_VI ");
}

 void loop()
{ 
 if (premiereFois) // si premiereFois est vraie
  {
   myStepper.step(-stepsPerRevolution); // moteur p-à-p amene le sachet à la tasse
   delay(500); //delai
   
   for (pos = 90; pos >= 0; pos -= 1) // pos du servo de 90° à 0° (descente)
    { 
      myservo.write(pos); // le servo va à 0°
      delay(15);  // delai
    }
  lcd.setCursor(0, 1);
  sprintf(timeline,"%0.2d mins %0.2d secs", minutes, secondes);      
  lcd.print(timeline);
  
  delay(1000);
  secondes++;
  
   if (secondes == 60)
    {
     secondes = 0;
     minutes ++;
    }
   if (minutes == 60)
    {
     lcd.setCursor(0, 0);
     lcd.clear ();
     lcd.print("Le the est pret!");
    }
   delay(180000); // temps d'infusion

   for (pos = 0; pos <= 90; pos += 1) // pos du servo de 0° à 90°
    {   
     myservo.write(pos); //le servo va à 90° (montée)
     delay(15); // delai
    }
    
  delay(500); // delai
  myStepper.step(stepsPerRevolution);  // moteur p-à-p enleve le sachet de la tasse
  delay(500); //delai
  
  for (pos = 90; pos >= 0; pos -= 1) // pos du servo de 90° à 0° (descente)
    { 
     myservo.write(pos); // le servo va à 0°
     delay(15); // delai
    }
    
  while(c!=500) // tant que c est différent de 500
   {
    digitalWrite(buzzer,HIGH);
    delay(1);//wait for 1ms
    digitalWrite(buzzer,LOW);
    delay(1);//wait for 1ms
    digitalWrite(buzzer,HIGH);
    delay(2);//wait for 2ms
    digitalWrite(buzzer,LOW);
    delay(2);//wait for 2ms     
    c++; //ajouter 1 à c
   }
    premiereFois = false; // definir premiereFois comme fausse
  }
}

Si n’importe qui à une idée je prends :slight_smile:
Merci d’avance

Peux-tu préciser ce qui ne colle pas ?
Je pense que ton format d'écriture dans le sprintf devrait être %02d et pas %0.2d,mais il y a peut être d'autres problèmes.

L'écran affiche la première ligne mais la deuxième ligne reste bloquée sur 00mins 00secs.
Et pour le %02d ou %0.2d le programme seul fonctionne de la même façon mais ça ne colle toujours pas.
Merci de ta réponse :slight_smile:

Le programme ne passe qu’une seule fois par snprintf...lcd.print
Donc normal qu’il affiche 0 min 0 sec, c’est la valeur des variables à ce moment.

La structure du programme est quand même assez bancale...
Que doit-il faire exactement ? Descendre le sachet, attendre, remonter le sachet ?
Donc pour une deuxième utilisation il faut éteindre et rallumer le montage, c’est bien ça ?

Oui c'est cela, il doit descendre le sachet, attendre 3 mins puis le remonter. Pour une deuxième utilisation, il y aura un BP mais il ne m'en reste plus, ils arrivent d'ici une semaine. Que devrais je mettre pour les variables alors? Je débute en arduino, j'ai encore un peu de mal, surtout avec les variables...

Bonjour;

delay(1000);
secondes++;

Lorsque tu fait une incrémentation tu compte le nombre de passage de boucle et non un temps définis.
Mais comme tu n'a pas besoins de contrôle durant tes phases d'actions tu peux exécuter "delay()" a des instant précis de tes actions comme un chrono.

A savoir "delay()" stop l'évolution du programme.
Pour une temporisation plus précise tu devrai utiliser "millis()" pour la gestion de temps d'exécution de tes actions.
Alors que "millis()" est le retour temps d'exécution programme. Soit le chrono-temps depuis que le programme est lancé.

En faisant sa lecture à un instant "T" tu la charge dans une variable de temps actuel.
Tu compare cette variable à une base de temps souhaité dans la condition d'exécution de "if()".
Tu recharge le temps actuel dans ta variable de temps actuel pour le précédent passage de boucle.

https://www.arduino.cc/en/pmwiki.php?n=Reference/millis

A plus.

Bonjour,

Le problème principal vient de ce que l’affichage du décompte de temps sur le LCD n’est pas dans une boucle. Dans ton programme tu n’affiche qu’une seule fois minutes et secondes, puis tu attends 180 secondes et tu remontes le sachet.

Ensuite, comme tu ne fais l’ensemble du traitement qu’une seule fois, inutile de le mettre dans loop avec une variable ‘premiereFois’; mets tout directement dans setup()

Par ailleures il serait plus propre de séparer les différentes actions dans des fonctions dédiées: baisserSachet(), infuser(), monterSachet(), signaler().

Dernier truc (mais pour ça je n’ai pas modifié le programme), baisserSachet() et monterSachet() ne font pas d’actions symétriques: baisserSachet() devrait peut-être commencer par monter le sachet, puisqu’à la fin de monterSachet() on le baisse. Sinon il faut tourner le servo à la main pour le remettre en position initiale avant une autre séquence d’infusion. Bon, du coup c’est vrai que j’ai peut-être mal choisi les noms pour les fonctions baisserSachet() et monterSachet()…

Ce qui pourrait donner quelque chose comme ça:

#include <Servo.h> //inclure bibliothèque servo
#include <Stepper.h> //inclure bibliothèque moteur pas-à-pas
#include <LiquidCrystal.h>

#define buzzer 12 //remplacer buzzer par 12

const int stepsPerRevolution = 1275;  // définir le nombre de pas



LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
Servo myservo;
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11); //pins du moteur p-à-p

void setup(void)
{
  myservo.attach(13);  // servo sur broche 13
  myStepper.setSpeed(20); //vitesse moteur p-à-p
  pinMode(buzzer, OUTPUT); //buzzer est une sortie
  lcd.begin(16, 2);
  lcd.print("TeaMachine Mk_VI ");

  baisserSachet ();
  infuser ();
  monterSachet ();
  signaler ();
}

void loop (void)
{
}

void baisserSachet (void)
{
  short   pos;


  myStepper.step(-stepsPerRevolution); // moteur p-à-p amene le sachet à la tasse
  delay(500); //delai

  for (pos = 90; pos >= 0; pos -= 1) // pos du servo de 90° à 0° (descente)
  {
    myservo.write(pos); // le servo va à 0°
    delay(15);  // delai
  }
}

void monterSachet (void)
{
  short   pos;


  for (pos = 0; pos <= 90; pos += 1) // pos du servo de 0° à 90°
  {
    myservo.write(pos); //le servo va à 90° (montée)
    delay(15); // delai
  }

  delay(500); // delai
  myStepper.step(stepsPerRevolution);  // moteur p-à-p enleve le sachet de la tasse
  delay(500); //delai

  for (pos = 90; pos >= 0; pos -= 1) // pos du servo de 90° à 0° (descente)
  {
    myservo.write(pos); // le servo va à 0°
    delay(15); // delai
  }
}

void infuser (void)
{
  short minutes, secondes;
  short i;
  char timeline[16];


  minutes = secondes = 0;

  for (i = 0; i < 180; i++)
  {
    lcd.setCursor(0, 1);
    sprintf(timeline, "%02d mins %02d secs", minutes, secondes);
    lcd.print(timeline);

    delay(1000);
    secondes++;

    if (secondes == 60)
    {
      secondes = 0;
      minutes ++;
    }
  }
}

void signaler (void)
{
  short c;


  lcd.setCursor(0, 0);
  lcd.clear ();
  lcd.print("Le the est pret!");

  c = 0;
  while (c != 500) // tant que c est différent de 500
  {
    digitalWrite(buzzer, HIGH);
    delay(1);//wait for 1ms
    digitalWrite(buzzer, LOW);
    delay(1);//wait for 1ms
    digitalWrite(buzzer, HIGH);
    delay(2);//wait for 2ms
    digitalWrite(buzzer, LOW);
    delay(2);//wait for 2ms
    c++; //ajouter 1 à c
  }
}

Merci manumanu pour ces explications, et merci cbrandt pour ton implication :).
Donc si j'ai bien compris :
-il faudrait utiliser millis à la place de delay
-ensuite j'ai appris que l'on pouvait faire plusieurs fonctions dédiées chacune à une action !
Et lorsque j'ajouterais un bouton il suffirait de mettre baisserSachet(), infuser(), monterSachet(), signaler() dans la fonction loop avec un if, c'est bien ça ?
Merci encore à vous :slight_smile:

Oui c’est ça.
Gérer les délais avec millis () te permettra par exemple de prendre en compte un bouton pendant une attente.

Bonjour;

Pour ce qui est des fonctions...
Une fonction n'est utiles que si elle est régulièrement appelé dans la programmation de la boucle.
Cela sert à exécuter une opération répétitive. Elle peut être paramétré en fonction des donnée qu'elles reçois en cours de programme. (Mais vois cela plus tard)

Dans ton cas tu n'a "pas besoins" de multiples fonctions.
La seule tâche répétitive que tu as est le pilotage de ton servomoteur. C'est donc cette tache que du doit mettre sous fonction.(Mais vois cela plus tard)

Mais une chose après l'autre. Fait déjà ton programme sans fonction.
Tu as déjà assez de mal comme cela non !!!

Les deux codes marchent très bien séparément mais ensembles ça ne colle pas >:( .
J'ai mis le setup du LCD dans le setup du "gros" programme et la déclaration des variables etc.. avec les autres: je pense que le problème vient du fait que je ne place pas correctement le loop du LCD dans le "gros" loop :

Pour ton problème d'affichage LCD. Tu devrai modifier tes broches de Broche de synchronisation.
et broche d'activation de transmission données. Utilise la broche 12(MISO) en "RS" et 11(MOSI) en "E".
Approprié pour la transmission d'infos vers ton LCD.

Essais dans un premier temps de monter ton programme étape par étape (descendre, remonter) sans penser à la temporisation qui est en faite ton étape d'infusion.
INFO: Pour le pilotage des servos tu n'est pas obligé d'utiliser une boucle "for(X)" la valeur "X" que tu y inscrit est l'angle au quel il se positionnera.
Tu peux donc retirer cela et ne garder que la methode de "Servo" myservo.write(pos);
Le mouvement devrais se ressentir plus vif. Corrige la vitesse si il faut.

Ensuite place ta temporisation => ton infusion.
Soit tu met delay() à la fin de chaque tâches ce qui ira très bien si ton système n'a pas besoins d’être interrompu avant la fin de ce temps définis.
Soit tu crée une temporisation basé sur le temps programme avec millis(). Ci joint un exemple...

Cette solution te permet de garder la lecture programme active et d'activer d'autre partie du programme pour réaliser une autres action ou arrêter celle en cours.

Une fois que ton système fonctionne intègre ton LCD pour en afficher les données utiles.
Mais là si tu souhaite afficher l'évolution du "timer" tu n'auras pas le chois que d'utiliser millis(). Là aussi une fonction d'affichage serra utile car répétitive (mais fait déjà la lecture LCD)

Désolé je ne fait pas de programme tout fait :wink: !!
La maitrise de son projet passe par la mise en pratique des outils manipulés.
Méthodes et patiences.

Ps: Fait "ctrl"+"t" ça fait du bien à la lecture programme.
Des commentaires fonctionnels ça aide a poser ces idées.

Salutations.