Conflit entre lcd et encoder rotatif [résolu]

Bonjour,
je rencontre un soucis innatendu. j'ai simplifié mon code afin d'isoler le problème. J'ai un écran LCD 4 lignes avec un encoder KY 040. l'encodeur est utilisé sans la librairie encoder.h car avec, l'encodeur ne répond pas correctement.

voici mon code

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define CLK_PIN 10
#define DT_PIN 11
#define SW_PIN 9

int position = 51;  // pour le test
int last_position = 0;
int n = 0;

LiquidCrystal_I2C lcd(0x27, 20, 4);  // Adresse I2C, colonnes (20 pour un écran 4x20), lignes (4), SDA (A4), SCL (A5)



void setup() {

  lcd.init();
  lcd.backlight();
  lcd.clear();
}
void loop() {
  n = digitalRead(CLK_PIN);

  if ((last_position == 0) && (n == HIGH)) {
    if (digitalRead(DT_PIN) == LOW) {
      position++;
    } else {
      position--;
    }
  }
  last_position = n;

  // test affichage
  lcd.setCursor(0, 0);
  //lcd.print("    position ");
  lcd.print(position);
}

avec ce code, l'encodeur fonctionne parfaitement, aucun soucis, réactivité parfaite.

par contre dès que j'écris quelques chose sur la même ligne ou la ligne en dessous, ça ne fonctionne plus.
cette ligne
//lcd.print(" position ");
passée en
lcd.print(" position ");
fais que l'encodeur ne fonctionne plus. parfois l'encodeur fixe, parfois ça incrémente correctement, parfois ça fait l'inverse et souvent ça bloque, je n'ai plus aucune réactivité.

je ne comprends pas comment le fait d'écrire un mot peut faire planter mon encodeur. ça fait plusieurs jours que je planche dessus et que je ne trouve pas de la solution, je me permets de demander à la communauté en espérant que vos lanternes m'aiguillent .

Meric beaucoup

Bienvenue

Pourquoi afficher constamment sur le lcd même quand la valeur n'a pas changé ? Ca gaspille énormément de cycles, et c'est probablement la cause de ton problème. Mais le mieux est de gérer un encodeur rotatif par des interruptions.

Post mis dans la mauvaise section, on parle anglais dans les forums généraux. ➜ déplacé vers le forum francophone.

Merci de prendre en compte les recommandations listées dans "Les bonnes pratiques du Forum Francophone".

Bonsoir magicyvan

Tu n'as pas initialisé les pin de ton encodeur (INPUT_PULLUP), avant c'était la bibliothèque qui s'en chargeai.

Etonnant!
Comment l'avais tu tu câblé?

Cordialement
jpbbricole

il n'y a pas de raison pour que ça ne puisse pas fonctionner

voici un code de test qui utilise les (très bonnes) bibliothèques suivantes:

ça affiche la valeur de l'encodeur quand elle change ainsi que l'état du bouton de l'encodeur

#include <Wire.h>
#include <hd44780.h>                        // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h>  // i2c expander i/o class header
#include <Encoder.h>                        // https://www.pjrc.com/teensy/td_libs_Encoder.html
#include <Toggle.h>                         // https://github.com/Dlloydev/Toggle

const uint8_t nbCols = 20;
const uint8_t nbRows = 4;
hd44780_I2Cexp lcd;

const byte encoderCLKPin = 2;
const byte encoderDTPin  = 3;
Encoder encoder(encoderDTPin, encoderCLKPin);
long encoderPosition;

const byte encoderSWPin = 4;
Toggle encoderSwitch;

bool encoderChanged() {
  long newPosition = encoder.read() >> 2;
  if (newPosition != encoderPosition) {
    encoderPosition = newPosition;
    return true;
  }
  return false;
}

void testSwitch() {
  encoderSwitch.poll();
  if (encoderSwitch.onPress()) {
    lcd.setCursor(13, 3);
    lcd.print(" APPUI ");
  }
  if (encoderSwitch.onRelease()) {
    lcd.setCursor(13, 3);
    lcd.print("RELACHE");
  }
}

void testEncoder() {
  if (encoderChanged()) {
    lcd.setCursor(5, 1); lcd.print(F("           ")); // on efface l'ancienne valeur
    lcd.setCursor(5, 1); lcd.print(encoderPosition);  // on met la nouvelle valeur
  }
}


void setup() {
  encoderSwitch.begin(encoderSWPin);
  Serial.begin(115200);

  int result = lcd.begin(nbCols, nbRows);
  if (result) {
    Serial.print("LCD initialization failed: ");
    Serial.println(result);
    hd44780::fatalError(result);
  }
  lcd.setCursor(0, 0); lcd.print(F("- KY040 + LCD20x04 -"));
  lcd.setCursor(0, 1); lcd.print(F("POS: 0"));
  lcd.setCursor(9, 3); lcd.print(F("SW: RELACHE"));
}

void loop() {
  testEncoder();
  testSwitch();
}

Merci pour vos retours très instructifs.

j'avoue bidouiller souvent les arduinos, mais je suis clairement novice comparé à vous ^^
je découvre que je peux faire plusieurs "void xxx" pour les rappeler dans le loop ! je comprends mieux la notion de void setup aussi merci.

J'ai compris que j'affiche des infos en fixe et que je mets dans le loop celles qui ont besoin d'un refresh (via le loop) et aussi que ça sert à rien d'initialiser dans le loop !! (merde pu**iin de newBie ^^)

une question concernant ce code, si je veux que mon compteur commence à 50, je peux changer cette ligne
lcd.setCursor(0, 1); lcd.print(F("POS: 50"));
mais ça reste pour l'affichage du départ, l'incrément part à 1 ce qui est logique. je n'arrive pas à donner à la variable encoderPosition un défaut de 50 pour que mon premier incrément soit 51.

Merci encore pour ces retours au top !

Bonjour,

Il suffit de l'initialiser dans la définition
long encoderPosition=50;

on appelle cela des fonctions (void veut dire dans ce cas que la fonction ne retourne rien à l'appelant)

si vous découvrez cela, il est temps de faire un tuto c++

c'est ce que j'ai fait, mais ça ne marche pas :face_with_monocle:
désolé j'aurais du dire que j'avais testé ça. pour moi aussi en toute logique si j'initialise encoderPosition à 50 ça devrait incrémenter à 51 bhé non ça part toujours à 1

@J-M-L a pris la peine de mettre un lien vers la doc de la librairie Encoder. Il suffit de lire cette doc.
Il n'y a pas beaucoup à lire car il n'y que le constructeur et 2 méthodes, une pour lire la valeur de l'accumulateur et l'autre pour fixer sa valeur.

Basic Usage
Encoder myEnc(pin1, pin2);
Create an Encoder object, using 2 pins. You may create mulitple Encoder objects, where each uses its own 2 pins. The first pin should be capable of interrupts. If both pins have interrupt capability, both will be used for best performance. Encoder will also work in low performance polling mode if neither pin has interrupts.

myEnc.read();
Returns the accumulated position. This number can be positive or negative.

myEnc.write(newPosition);
Set the accumulated position to a new number.

Dans mon wokwi ci dessus rajoutez au début du setup

encoder.write(50<<2); 

On fait <<2 qui correspond à x4 parce que l’encodeur a 4 ticks pour un click et que la bibliothèque compte les ticks

Je suis persuadé que l’écran affichera 50

@fdufnews oui désolé je n'avais pas creusé la doc constructeur.

@J-M-L Merci ta syntaxe est la bonne, ça fonctionne :slightly_smiling_face:

Merci encore pour vos aides, je retourne sur mon projet initial. d'ailleurs y a un endroit où on peut présenter son projet pour montrer ses avancements et poser des éventuelles questions ?

tant que le projet n'est pas fini et que vous avez des questions, postez ici

quand il sera fini, si vous voulez le présenter les principes et expliquer le montage / le code, vous pouvez poster dans la catégorie Réalisations et Projets Finis - Arduino Forum

super merci pour le retour

Projet terminé !!!

Il est dispo ici

Merci encore pour les aides

bonjour à tous.
je rencontre un soucis de freeze sur mon projet. je m'en suis servi pour faire une étuve de ginger beer (grrrr :slight_smile: ) mais au petit matin il semble bloqué.
je l'éteints et le rallume et oui clairement il était bloqué. lui ou la sonde, mais la sonde donnait 28° et était bloqué.
Après reboot, la sonde se remet à s'actualiser toute les secondes et il fait 21°. donc j'ai bien eu un blocage.

je vous repose le code utilisé. en espérant que vous ayez une idée car je sèche

#include <Wire.h>
#include <hd44780.h>                        // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h>  // i2c expander i/o class header
#include <Encoder.h>                        // https://www.pjrc.com/teensy/td_libs_Encoder.html
#include <Toggle.h>
#include "max6675.h"  // https://github.com/Dlloydev/Toggle
//création LCD
const uint8_t nbCols = 20;
const uint8_t nbRows = 4;
hd44780_I2Cexp lcd;
//config des pins
int relais = 2;
int thermoDO = 4;
int thermoCS = 5;
int thermoCLK = 6;
const byte encoderSWPin = 9;

Toggle encoderSwitch;
const byte encoderCLKPin = 10;
const byte encoderDTPin = 11;
//////
Encoder encoder(encoderDTPin, encoderCLKPin);
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);

//config des variable
int tempRef;
int page = 1;
unsigned long previousMillis = 0;    // Variable pour stocker le temps précédent
const unsigned long interval = 500;  // pour pallier le delay qui fait planter l'encoder


bool encoderChanged() {
  long newPosition = encoder.read() >> 2;
  if (newPosition != tempRef) {
    tempRef = newPosition;
    return true;
  }
  return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  encoderSwitch.begin(encoderSWPin);
  //Serial.begin(9600);


  pinMode(relais, OUTPUT);
  int result = lcd.begin(nbCols, nbRows);
  encoder.write(28 << 2);
  intro();
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
void intro() {
  lcd.backlight();
  lcd.clear();
  delay(100);
  lcd.setCursor(0, 0);
  lcd.print(" / / Etuve  Box / / ");
  lcd.setCursor(4, 2);
  lcd.print("V1 23/09/203 ");
    lcd.setCursor(0, 1);
   lcd.print("   by Yvan Bonnin   ");
  delay(100);

  lcd.backlight();
  lcd.clear();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void mySwitch() {
  encoderSwitch.poll();
  if (encoderSwitch.onPress()) {
    page++;
    if (page == 3) { page = 1; }
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void myEncoder() {

  if (encoderChanged()) {
    lcd.setCursor(13, 1);
    lcd.print(F("  "));  // on efface l'ancienne valeur
  }
  if (page == 1) {
    lcd.setCursor(13, 1);
    lcd.print(tempRef);  // on met la nouvelle valeur
  }
  if (tempRef <= 9) {  // symbole °
    lcd.setCursor(14, 1);
    lcd.print((char)223);
    lcd.setCursor(15, 1);
    lcd.print(" ");
  } else {  // symbole ° décalé de 1 en dessous de 10
    lcd.setCursor(15, 1);
    lcd.print((char)223);
  }
  if (tempRef <= 0 || tempRef >= 95) {  // limite des températures acceptées
    encoder.write(29 << 2);
  }
  lcd.setCursor(16, 1);
  lcd.print("/ /");
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {

  mySwitch();


  //Serial.println(tempRef);
  if (page == 1) {
    myEncoder();
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      // Lire la température en Celsius depuis le capteur MAX6675
      double temperature = thermocouple.readCelsius();
      // Formater la température avec une décimale
      String formattedTemperature = String(temperature, 1);

      lcd.setCursor(0, 0);
      lcd.print(" / / Mode  Etuve / / ");
      lcd.setCursor(0, 1);
      lcd.print("/ / Objectif ");
      lcd.setCursor(0, 2);
      lcd.print(" Temp Four : ");
      lcd.print(formattedTemperature);  // Afficher la température avec une décimale
      lcd.write((char)223);
      // Allumer ou éteindre la Lampe en fonction de la température
      if (temperature <= tempRef - 1) {
        digitalWrite(relais, LOW);  // Allumer la Lampe
        lcd.setCursor(0, 3);
        lcd.print("  Lampe en chauffe ");
      }
      if (temperature >= tempRef) {
        digitalWrite(relais, HIGH);  // Éteindre la Lampe
        lcd.setCursor(0, 3);
        lcd.print("                    ");
      }
      previousMillis = currentMillis;
    }
  } else {

    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      // Lire la température en Celsius depuis le capteur MAX6675
      double temperature = thermocouple.readCelsius();
      // Formater la température avec une décimale
      String formattedTemperature = String(temperature, 1);

      lcd.setCursor(0, 0);
      lcd.print(" Temperature check  ");
      lcd.setCursor(0, 1);
      lcd.print("/ / / / / / / / / / ");
      lcd.setCursor(0, 2);
      lcd.print(" Temp Four : ");
      lcd.print(formattedTemperature);  // Afficher la température avec une décimale
      lcd.write((char)223);
      lcd.setCursor(0, 3);
      lcd.print("/ / / / / / / / / / ");
      digitalWrite(relais, HIGH);  // Éteindre la Lampe
      previousMillis = currentMillis;
    }
  }
}

Pas certain que ce soit la cause racine de ton problème mais, pourquoi faire ça

alors que print propose déjà le formatage des float.
Ceci devrait se comporter de la même manière et éviterait l'usage des String qui peut poser des problèmes d'occupation mémoire sur le long terme.

  lcd.print(temperature, 1);  // Afficher la température avec une décimale

A part, ça, le code semble propre.
Si le système était en exploitation il devait tourner sur la page 1 qui ne fait pas grand chose.
Il n'est pas impossible que le plantage ait été causé par une microcoupure ou un parasite sur le secteur.

Merci pour ton retour. le système est en cours d'utilisation. j'ai eu encore un freeze. j'ai l'impression que c'est au bout de 10h.

Comme c'est en utilisation dans mon four je ne peux pas changer le code, je ferai demain la correction.

je t'avoue je ne suis pas assez calé pour comprendre la subtilité que tu expliques, quand j'aurais le code avec l'arduino branché j'essaierai de mettre ça au clair :smiley: en essayant de comprendre tout ça

Ce serait bien d'en profiter pour ajouter des sorties sur Serial pour visualiser l'exécution du code et peut-être arriver à voir où il plante.

quand vous faites

      String formattedTemperature = String(temperature, 1);
      lcd.print(formattedTemperature);  // Afficher la température avec une décimale

la première ligne alloue de la mémoire et fait le calcul pour transformer le nombre en chaîne formaté que vous affichez en suite.

si vous faites simplement

lcd.print(temperature, 1);  // Afficher la température avec une décimale

la fonction print va simplement stopper l'affichage du nombre décimal après le premier chiffre. vous n'avez pas eu l'allocation intermédiaire dynamique de mémoire.

Si la mémoire est limitée (c'est souvent le cas sur des petits arduinos) on essaye d'être prudent sur tout ce qui en consomme pour rien