Affichage et réglage de variables sur afficheur

Bonjour,

C'est mon premier "gros" projet sur Arduino uno, et je bloque sur une partie : L'affichage de le réglage d'une variable par un afficheur LCD.

Je m'explique :

Un capteur analogique et/ou digital doit déclencher un relais, cependant je voudrais régler le délai, la sensibilité (pour l'analogique) et l'état (High ou Low) pour le digital.

Mon principal problème vient de l'affichage (sur afficheur 16x2) et du réglage (par potentiomètre).
Je voudrait pouvoir switcher l'affichage des différentes valeurs par appui sur un seul poussoir (delai, sensibilité, etat, le tout en boucle) et modifier la valeur avec un seul potentiomètre.

Je n'arrive pas a structurer le code nécessaire, si vous avez quelques pistes je vous remercie d'avance de vos réponses.

Salut,

Chose très simple,

Il suffit que tu crée un variable, puis que tu incrément quand tu appui sur le bouton
Genre

if (digitalRead(Bouton)==LOW){
Parametre++; // Incrémente l'état
While(digitalRead(Bouton)==LOW;} // Evite le rebond

If (Parametre ==1){
Fonction affichage de ton premier paramètre;}

If (Parametre ==2){
Fonction affichage de ton second paramètre;}
....
If (Parametre == n){
Affichage = 1;}

Les If peuvent être remplacés par un switch case:

switch (Parametre) {
  case 0:
    // Fonction ici.
    break;
  case 1:
    // Autre fonction ici.
    break;
  case 2:
    // Blablabla
    break;
[...]
}

Indépendamment du code, tu risque d'avoir des problèmes à vouloir utiliser un seul potentiomètre pour régler plusieurs paramètres. Imagine le cas suivant :

  • Tu est en train d'ajuster une variable A, et tu veux la mettre au minimum -> tu tourne donc le potar à fond jusqu'à la butée « basse »
  • Passage au réglage de la variable suivante B, que tu veux également diminuer : comment fais-tu ?

Bien sûr, tu peux toujours essayer de ruser en remettant le potentiomètre « au milieu » entre deux ajustements, lorsque le bouton n'est pas appuyé, mais il arrivera toujours un moment ou tu seras bloqué (ie la course physiquement disponible sur le potentiomètre ne correspondra pas à la modification que tu veux appliquer à ta variable).

Je ne dis pas que c'est impossible, mais ça va quand même pas mal compliquer les choses, et surtout ça sera toujours un peu « merdique »...

À mon avis tu ferais mieux d'utiliser un codeur rotatif à la place du potentiomètre, c'est l'objet idéal pour ça.

Ces problèmes peuvent être facilement comblées:

  • On appuie sur le bouton pour prendre la variable a modifier
  • On tourne le potentiometre pour choisir la valeur, et celle-ci est affichée en meme temps sur l'ecran
  • On appuie une nouvelle fois pour mettre cette valeur dans la variable
  • On passe à la variable suivant.

On peut également faire différents calculs sur la valeur lue du potard en fonction des variables à modifier.
Pour une course de 0 a 1023, on peut diviser pour certains variables dont on à besoin d'avoir seulement des valeurs entre 0 et 100 par exemple ou multiplier et rajouter un offset pour les variables dont on veut apposer de grandes valeurs.

Mouais. En fait, pour préciser un peu ma pensée, dans ce cas d'utilisation le potentiomètre agit un peu comme un codeur rotatif « absolu ». Et le problème c'est qu'au moment ou tu va entrer dans la fonction de modification d'une variable, la position physique du potentiomètre ne correspondra pas forcément à l'ancienne valeur de cette variable.

Il est bien sûr possible de s'en accommoder, mais perso je pense que le résultat final sera toujours un peu « merdeux », même si c'est totalement subjectif. Un codeur rotatif incrémental me paraît beaucoup plus indiqué pour ce cas-là.

unsigned long pushTime = 0;
long pushDelay = 1000;
int modifValeur = 0;
int variable1 = 0;
int variable2 = 0;

if ((digitalRead(Bouton)==LOW) && (millis() - pushTime >> pushDelay ){   //on temporise avec millis pour accuenter la protection contre les rebonds.
Parametre++; // Incrémente l'état
pushTime = millis();
While(digitalRead(Bouton)==LOW;} // Evite le rebond
}

switch (Parametre) {
  case 0:
    // Parametre == 0 est l'état où le menu de changement des variables n'est pas affiché/actionné
    // Mettre ici les fonctions appellées en temps normal à l'endroit 
    // où devrais s'afficher le menu de variables.
    // Exemple: Heure / Date
    break;
  case 1:
    // Changement de la variable 1.
    modifValeur = (analogRead(0) / 100);   // En admettant que le potard se trouve sur A0.
    lcd.setCursor(0,1);
    lcd.print("                ");       // Efface le texte précèdent
    lcd.setCursor(0,1);
    lcd.print("Nomvariable1");
    lcd.setCursor(0,14);
    lcd.print(modifValeur);
    break;                               // Il faut ensuite Réappuyer sur le bouton pour passer au case 2.
  case 2:
    // On sauvegarde la variable 1 avec la valeur qu'on choisie.
    variable1 = modifValeur;
    // Puis, on continue sur la prochaine variable.
    modifValeur = (analogRead(0) / 20);   // Cette fois-ci, on parametre pour obtenir des valeurs de 1 a 51.
    lcd.setCursor(0,1);
    lcd.print("                ");       // Efface le texte précèdent
    lcd.setCursor(0,1);
    lcd.print("Nomvariable2");
    lcd.setCursor(0,14);
    lcd.print(modifValeur);
    break;
  case 3:
    variable2 = modifValeur;
    // Et ainsi de suite...
    break;
}

Grosso-modo une première approche peut être réalisée comme ça.
Néanmoins le gros souci de ce code pour l'instant (j'y travaille), est que toutes les variables doivent être changées à chaque fois que l'on accède à l'étape de modification.

EDIT: @haifger: Je suis complétement d'accord avec toi qu'un codeur rotatif serait beaucoup plus adapté, plus simple et plus précis et avec un rendu "pro" mais pour le moment l'auteur du sujet ne nous à signaler seulement le bouton et le potard, et je doute qu'il possède un codeur et c'est pour cela qu'il faut essayer de faire quelque chose avec ce qu'il possède actuellement.

unsigned long pushTime = 0;
long pushDelay = 1000;
int modifValeur = 0;
int variable1 = 0;
int variable2 = 0;
int variable3 = 0;
int potVal = 0;
boolean previousHasChanged = false;

if ((digitalRead(Bouton)==LOW) && (millis() - pushTime >> pushDelay) ){   //on temporise avec millis pour accuenter la protection contre les rebonds.
Parametre++; // Incrémente l'état
pushTime = millis();
while(digitalRead(Bouton)==LOW; // Evite le rebond
}

switch (Parametre) {
  case 0:
    // Parametre == 0 est l'état où le menu de changement des variables n'est pas affiché/actionné
    // Mettre ici les fonctions appellées en temps normal à l'endroit 
    // où devrais s'afficher le menu de variables.
    // Exemple: Heure / Date
    potVal = analogRead(0);    // En admettant que le potard se trouve sur A0.
    previousPotVal = potVal;
    previousHasChanged = false;
    break;
  case 1:
    // Changement de la variable 1.
    potVal = analogRead(0);
    if (previousPotVal == potVal) {
      modifValeur = variable1;
    }
    else {
      modifValeur = (potVal / 100);
      previousHasChanged = true;
    }
    lcd.setCursor(0,1);
    lcd.print("                ");       // Efface le texte précèdent
    lcd.setCursor(0,1);
    lcd.print("Nomvariable1");
    lcd.setCursor(0,14);
    lcd.print(modifValeur);
    break;                               // Il faut ensuite Réappuyer sur le bouton pour passer au case 2.
  case 2:
    // On sauvegarde la variable 1 avec la valeur qu'on choisie.
    variable1 = modifValeur;
    
    // Puis, on continue sur la prochaine variable.
    potVal = analogRead(0);
    
    if (previousHasChanged = true) {
      previousPotVal = potVal;
      previousHasChanged = false;
    }
    else {
      previousHasChanged = false;
    }
      
    if (previousPotVal == potVal) {
      modifValeur = variable2;
    }
    else {
      modifValeur = (potVal / 20);    // Cette fois-ci, on parametre pour obtenir des valeurs de 1 a 51.
      previousHasChanged = true;
    }
    lcd.setCursor(0,1);
    lcd.print("                ");       // Efface le texte précèdent
    lcd.setCursor(0,1);
    lcd.print("Nomvariable2");
    lcd.setCursor(0,14);
    lcd.print(modifValeur);
    break;
  case 3:
    variable2 = modifValeur;
    // Et ainsi de suite...
       potVal = analogRead(0);
    
    if (previousHasChanged = true) {
      previousPotVal = potVal;
      previousHasChanged = false;
    }
    else {
      previousHasChanged = false;
    }
      
    if (previousPotVal == potVal) {
      modifValeur = variable3;
    }
    else {
      modifValeur = (potVal / 20);    
      previousHasChanged = true;
    }
    lcd.setCursor(0,1);
    lcd.print("                ");       // Efface le texte précèdent
    lcd.setCursor(0,1);
    lcd.print("Nomvariable3");
    lcd.setCursor(0,14);
    lcd.print(modifValeur);
    break;
    
  case 4:
    variable3 = modifValeur;
    // Et on continue...
    
    break;

  case 20: //20 Est a titre d'exemple, cela correspond au dernier case pour pouvoir retourner au case 0
    Parametre = 0;
    break;

    
}

Voila, normalement comme cela les variables ne sont pas changées tant que l'on ne tourne pas le potard.
Par contre, il faut que l'entrée analog soit totalement dénuée de bruit.

Merci pour toutes ces réponses.

J'ai en fonction de vos réponse décidé d'ajouter quelques trucs :

1 - un bouton pour défiler les menus le deuxièmes qui sur un click autorise le réglage au deuxième click enregistre.

2 - Mettre un condo de filtrage pour le signal

3 - Effectivement ce serait plus pro avec un incrémenteur voir un incrémenteur clicable, mais pour l'instant je dispose seulement d'un potentiomètre, et j'avoue que je trouve ça intéressant au niveau de la gestion de la résistance et du code.

4 - Je ne connais pas la fonction Switch / Case, qu'elle est la différence avec if / elseif ?

5 - Pour le bruit, la valeur sera visible à l'écran, donc le bruit aussi, ca peut effectivement être agaçant mais ça reste contrôlable.

Je vais regarder comment coder le 2eme bouton !

La différence entre un switch case et la même chose en if:

switch (variable) {
  case 0:
    FonctionQuiS'ExecuteQuandVariable=0
    break;
  case 1:
    FonctionQuiS'ExecuteQuandVariable=1
    break;
  case 2:
    FonctionQuiS'ExecuteQuandVariable=2
    break;
       .
       .
       .
  case 70:
     FonctionQuiS'ExecuteQuandVariable=70
     break;

La même chose avec des if:

if (variable == 0) {
FonctionQuiS'ExecuteQuandVariable=0
}

if (variable == 1) [
FonctionQuiS'ExecuteQuandVariable=1
}

if (variable == 2) {
FonctionQuiS'ExecuteQuandVariable=2
}
                .
                .
                .
if (variable == 70) {
FonctionQuiS'ExecuteQuandVariable=70
}

Dans un switch case, la valeur de "variable" ne seras que vérifiée une fois au début du switch case alors que avec les if, les conditions seront vérifiées à chaque if different.
Le switch case est plus simple pour faire une liste et plus rapide.

Quand au deuxième bouton, il n'est pas forcément obligatoire car tu remplis deja la fonction d'acces au menu / Validation de la valeur de la variable avec la partie de code que j'ai mis.

D'accord, c'est donc aussi plus leger en calcul.

je vais utiliser Switch !

Je vais finalement utiliser un codeur incremental (celui qui controlait le volume de mon poste radio), ce système de codage absolu est trop compliqué à stabiliser au niveau des tensions de sortie. par contre je ne vois plus comment faire la relation entre l'incrément et la valeur (j'ai toujours fait ça avec des valeurs analogiques)

Dans ce cas effectivement je ne met pas le deuxième bouton de toute manière.

Demain je vous donne le schéma de montage que j'ai effectué avec le code qui va avec (en grande partie le votre)

Je voulais vous tenir au courant de l'avancée du code, je vous montre pas de photo du montage en phase de test, il ressemble a un sac de nœuds :slight_smile:

J'ai utilisé la librairie "RotaryEncoder" du module S65 avec quelques modification parce que mon encodeur est différent, et j'ai évité les rebonds avec une autre librairie "MsTimer2"

Le code en est au stade de la construction, il comporte quelques erreurs (notamment une au niveau de la déclaration de "timer"), j'ai repris la logique et la construction de BananaFanatics, merci encore.

/* High speed photography flash trigger device */
// --- Que fait ce programme ? ---
/* il déclanche un flash en fonction de l'état logique d'une sonde, il comporte des réglages de sensibilité, de délai et d'état. */

//librairies
#include <LiquidCrystal.h>
#include <RotaryEncoder.h>
#include <MsTimer2.h>



//déclaration des constantes
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
byte Sortie = 6 ;
byte Bouton = 7 ;
RotaryEncoder encodeur ; 
int modifValeur = 0;
int Delais = 0;
int sensibiliteV = 0;
int etatdigital = 0;


void setup()   {
  //intialisation de RotaryEncoder
  encodeur.init();
  MsTimer2::set(1, timer); // période 1ms
  MsTimer2::start(); // active Timer 2
}


void loop(){
  
void timer() { // debut de la fonction d'interruption Timer2

encodeur.service(); // appel de la de gestion de l'encodeur

int test=encodeur.step(); // lit une fois l'état de step




if (encodeur.sw()==SW_PRESSED){   //si j'appui sur le bouton de l'encodeur
Parametre++; // Incrémente l'état
}
switch (Parametre) {
 case 0:
    lcd.setCursor(0,1);
    lcd.print("                ");       // Efface le texte précèdent
    lcd.setCursor(0,1);
    lcd.print("DLS SENS ETAT");
    lcd.setCursor(0,14);
    lcd.print(Delais, sensibiiteV, etatdigital);
    break;                               // Il faut ensuite Réappuyer sur le bouton pour passer au case 2.
 case 1:
    // Changement du délais
    if (test==1) { // si rotation + encodeur
      Delais=Delais+1;
    }
     else if (test==-1) { // si rotation - encodeur
       Delais=Delais-1;   
    }
    lcd.setCursor(0,1);
    lcd.print("                ");       // Efface le texte précèdent
    lcd.setCursor(0,1);
    lcd.print("Delais en MS");
    lcd.setCursor(0,14);
    lcd.print(Delais);
    break;                               // Il faut ensuite Réappuyer sur le bouton pour passer au case 2.
    
    case 2:
    
    if (test==1) {
       sensibiliteV=sensibiliteV+1;
    }
    else if (test==-1) {
       sensibiliteV=sensibiliteV-1;
    }
    lcd.setCursor(0,1);
    lcd.print("                ");       // Efface le texte précèdent
    lcd.setCursor(0,1);
    lcd.print("sensibilite en V");
    lcd.setCursor(0,14);
    lcd.print(Delais);
    break;
    
  case 3:
  if (test==1) {
       etatdigital=etatdigital+1;
    }
    else if (test==-1) {
       etatdigital=etatdigital-1;
    }
    lcd.setCursor(0,1);
    lcd.print("                ");       // Efface le texte précèdent
    lcd.setCursor(0,1);
    lcd.print("Etat de declanchement");
    lcd.setCursor(0,14);
    lcd.print(etatdigital);
    break;
}
}
}

EDIT : Les librairies ne fonctionnant pas avec la V1.0.1 du compilateur j'ai du passer par ici : playground.arduino.cc/Main/RotaryEncoders

Voici le code qui me semble clean qui permet de choisir la variable et de la modifier, j'ai considéré le bouton du codeur comme un simple bouton et j'ai traité le signal du codeur rotatif avec les indications données ici : playground.arduino.cc/Main/RotaryEncoders.

/* High speed photography flash trigger device */
// --- But du programme ---
/* il déclanche un relais en fonction de l'état logique d'un capteur avec un réglage de délais et de sensibilité
Dans cette partie du code, on ne s'occupe que de la modification du Délais et de l'affichage*/

//librairies
#include <LiquidCrystal.h>
#include <MsTimer2.h>


//déclaration
//entrées sorties
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
byte Sortie = 6 ; //sortie pour activation du relais
byte CapteurDigital = 7 ; //Sensor Digital 
int Bouton = 10 ; //Bouton du codeur rotatif
byte PHA = 9 ; //Borne A du codeur
byte PHB = 8 ; //Borne B du codeur

//valeurs
unsigned long pushTime = 0; //Le pushtime en MS
long pushDelay = 1000; //La variable de référence du push en MS

//initialisation des réglages à 0
int Delais = 0; 
int sensibiliteV = 0;
int etatdigital = 0;
int Parametre = 0;


void setup() {
  
  pinMode(Bouton, INPUT); //met la broche en entree 
  digitalWrite(Bouton, HIGH) ; // activation du pullup de la broche en entr?©e
  pinMode(PHA, INPUT); 
  pinMode(PHB, INPUT);
  // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, actionPHA, CHANGE);
  // encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, actionPHB, CHANGE);

  lcd.begin(16, 2);
}


void loop(){
  if ((digitalRead(Bouton)==LOW) && (millis() - pushTime >> pushDelay) ){   //on temporise avec millis pour accuenter la protection contre les rebonds.
Parametre++; // Incrémente l'état
pushTime = millis();
while(digitalRead(Bouton)==LOW); // Evite le rebond
}
}

//Fonction interrupt quand le codeur est tourné vers la borne A (+)
void actionPHA(){
         switch (Parametre) {
 case 0: //cas de repos quand la variable parametre est a 0, ici on protège les réglage en ne faisant rien si on tourne le codeur
    lcd.setCursor(0,1);
    lcd.print("                ");      
    lcd.setCursor(0,1);
    lcd.print("Projet photo trigger v1.0");
    break;
    
case 1: //quand la variable parametre est sur 1 (ici le délais)
  // Recherche d'une variation sur le Pin A
  if (digitalRead(PHA) == HIGH) { 
    // Check du pin B pour connaitre la direction de rotation
    if (digitalRead(PHB) == LOW) {  
      Delais = Delais + 1;         // CW
    } 
    else {
      Delais = Delais - 1;         // CCW
    }
  }

  else   // HIGH -> LOW sur le pin A                                       
  { 
    // check du pin B pour connaitre le sens de rotation 
    if (digitalRead(PHB) == HIGH) {   
      Delais = Delais + 1;          // CW
    } 
    else {
      Delais = Delais - 1;          // CCW
    }
  }

}

//affichage sur le LCD de la variable et sa valeur
lcd.setCursor(0,1);
    lcd.print("                ");       
    lcd.setCursor(0,1);
    lcd.print("Delais en MS");
    lcd.setCursor(0,14);
    lcd.print(Delais);
}

//meme principe avec le Pin B
void actionPHB(){
  switch (Parametre) {
 case 0:
    lcd.setCursor(0,1);
    lcd.print("                ");       
    lcd.setCursor(0,1);
    lcd.print("Projet photo Trigger 1.0");
    break;
 case 1:
  if (digitalRead(PHB) == HIGH) {   

    if (digitalRead(PHA) == HIGH) {  
      Delais = Delais + 1;         // CW
    } 
    else {
      Delais = Delais - 1;         // CCW
    }
  }


  else {   
    if (digitalRead(PHA) == LOW) {   
      Delais = Delais + 1;         
    } 
    else {
      Delais = Delais - 1;        
    }
    }
    lcd.setCursor(0,1);
    lcd.print("                ");       
    lcd.setCursor(0,1);
    lcd.print("Delais en MS");
    lcd.setCursor(0,14);
    lcd.print(Delais);
    break;                               
  }
}

Et 'image du montage avec un capteur de proximité infrarouge qui pilote le relais.
Je n'arrive pas a constituer de protection contre les rebonds, sur le schéma il n'y a donc pas.