Affichage LCD 2 chiffres avec un clavier 4x4 et encodeur

Bonjour,
J'essaye de me programmer un compte pose pour ma chambre noire argentique (photo avec agrandisseur).

Pour mon besoin, j'ai donc :

  • Un écran LCD I2C
  • Un clavier 4x4
  • Un sélecteur type potentiomètre

Sur mon afficheur LCD, j'affiche deux lignes :

  • Nbr Etapes
  • Nbr Secondes

Pour définir le nombre d'étapes et le nombre de seconde je souhaite les entrer via le clavier (j'arrive à faire le programme de 0 à 9 mais dès que je souhaite faire 10 ou plus ca coince :))
Pour changer de ligne j'utilise le sélecteur qui affiche un petit triangle.

J'ai trouvé un exemple de code pour mettre 2 digits, mais mon problème vient pour libérer la fonction une fois la valeur entrée et valider (par la touche #), en effet, je n'arrive plus à utiliser le sélecteur pour changer de ligne si j'utilise la fonction "getKeypadIntegerMulti"

Si vous pouvez me donner une piste pour libérer la fonction afin que le sélecteur passe à la ligne suivante.
Merci beaucoup

voici mon code dans son intégralité

#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#define I2C_ADDR 0x27
LiquidCrystal_I2C lcd(0x27,20,4);

// This section sets up the rotary encoder on D2 and D3 with interrupts to minimise load. Potentially change the volatile data to byte to save space
static byte pinA = 2; // Our first hardware interrupt pin is digital pin 2
static byte pinB = 3; // Our second hardware interrupt pin is digital pin 3
static byte pinC = 4; // Rotary push button on pin 4
volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to byte or uin16_t instead of byte if you want to record a larger range than 0-255
volatile byte oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent

int menuSelection = 0; //to detect which menu is selected. Do not let menuselection <= 0
byte menuSelectionState = HIGH;  //to detect pushbutton on rotary, rotary is NC switch i.e. pressing the button equals to a LOW and not high
byte menuSelectionMode = 0; //determine if menu selection 0 (no changing) 1 (changing mode)
byte mainFunction = 10; 
byte menuChangemode = 0;

const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {
  {'1','4','7', '*'},
  {'2','5','8', '0'},
  {'3','6','9', '#'},
  {'A','B','C', 'D'}
};
byte rowPins[ROWS] = {12, 11, 10, 9};
byte colPins[COLS] = {8, 7, 6, 5};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
char customKey = customKeypad.getKey();

long getKeypadIntegerMulti()
{
  long value = 0;
  long keyvalue;
  int isnum;
  int validation;
  
  do
  {
    keyvalue = customKeypad.getKey();
    isnum = (keyvalue >= '0' && keyvalue <= '9' || keyvalue == 'A'  || keyvalue == 'B'  || keyvalue == 'C'  || keyvalue == 'D');
    validation = (keyvalue == 'A'  || keyvalue == 'B'  || keyvalue == 'C' || keyvalue == 'D' );
    
    if (isnum && !validation)
    {
      value = value * 10 + keyvalue - '0';
    }
  } while (isnum|| !keyvalue);
  return value;

}

byte selectorL[8] = //icon creation for menu arrow pointing left 
{
	B00010,
	B00110,
	B01110,
	B11110,
	B01110,
	B00110,
	B00010,
	B00000
};

byte selectorR[8] = //icon creation for menu arrow pointing right
{
	B01000,
	B01100,
	B01110,
	B01111,
	B01110,
	B01100,
	B01000,
	B00000
};

byte NbrEtape = 0 ;
byte NbrSec = 0 ;

String selectionEtape;

void setup() {
	lcd.init();
  lcd.setBacklight(HIGH);
	lcd.home();
	lcd.createChar(1,selectorL);
	lcd.createChar(2,selectorR);
	lcd.clear();
  pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
	pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
	pinMode(pinC, INPUT_PULLUP); // designate rotary encoder push button for pin change intterupt input
	attachInterrupt(0,PinA,RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
	attachInterrupt(1,PinB,RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)
}

void loop() {
  lcd.setCursor(0,0);
  lcd.print(F("Nbr Etapes : "));
  lcd.setCursor(0,1);
  lcd.print(F("Nbr secondes :"));
  lcd.setCursor (17,menuSelection);
	lcd.write(1); // Triangle postion 1 = pointe à gauche 2 = Pointe à droite
 
  if (oldEncPos != encoderPos){ //Allows selection of editing with rotary selector
				menuSelection = menuSelection + (encoderPos - oldEncPos);
				if (menuSelection > 1){  //recheck if this is >3 is better or more accurate
					menuSelection = 0;
				}
				if (menuSelection < 0){  //recheck if this is <1 is better or more accurate
					menuSelection = 1;
				}
				oldEncPos = encoderPos;
				lcd.clear();
			}

	if (menuSelection == 0){  //Change the number of steps - now maximum is 9 steps
      int NbrEtape = getKeypadIntegerMulti();
      lcd.setCursor(14,0);
      lcd.print(NbrEtape);
      //lcd.clear();
	}
  if (menuSelection == 1){  //Change the number of steps - now maximum is 9 steps
      int NbrSec = getKeypadIntegerMulti();
      lcd.setCursor(14,1);
      lcd.print(NbrSec);
	}
}

void PinA(){ //to monitor rotary position
	cli(); //stop interrupts happening before we read pin values
	reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
	if(reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
		encoderPos --; //decrement the encoder's position count
		bFlag = 0; //reset flags for the next turn
		aFlag = 0; //reset flags for the next turn
	}
	else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
	sei(); //restart interrupts
}

void PinB(){ //to monitor rotary position2
	cli(); //stop interrupts happening before we read pin values
	reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
	if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
		encoderPos ++; //increment the encoder's position count
		bFlag = 0; //reset flags for the next turn
		aFlag = 0; //reset flags for the next turn
	}
	else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
	sei(); //restart interrupts
}

:warning:
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

Je pense que ça vient de ta gestion de l'encodeur. Ces lignes :

Tu devrais te faire un petit code simple pour apprendre à te servir de l'encodeur et obtenir le résultat que tu veux.
Tu n'expliques pas comment tu veux t'en servir donc pas facile d'aider pour le moment. Mais s'il sert uniquement à changer de ligne, tu peux dire par exemple que la détection de (mettons) 4 positions en plus fait descendre le curseur et 4 positions en moins le fait monter.
Fais un code qui affiche la valeur de menuSelection à chaque déplacement de l'encodeur et regarde comment l'utiliser.

Mais, à mon avis tu te compliques la vie pour rien : tu peux aussi affecter ces fonctions à un des boutons de ton clavier. Par exemple :

  • A : ligne du haut
  • B : ligne du bas
  • C : validation de la valeur entrée
  • 0-9 : valeurs

Ca me semble plus simple. Plus besoin d'interruptions...

hello
je ne comprends pas ce que tu veux faire avec un nombre d'étapes et de secondes

les secondes je comprends,
mais les étapes sur un compte pose pour un agrandisseur photos ??
peux tu expliquer ?

Bonjour,
Oui effectivement, il s'agit d'un compte pose pour controler un agrandisseur photo argentique.
Voici ma première version de ma "boite" en photo :

Dans cette version tout fonctionne, c'est à dire le changement par le sélecteur pour changer le menu, et entrer le chiffre que je veux. Mais le problème réside sur le fait que je peux aller que jusqu'au chiffre 9 ! impossible de mettre deux digits.
Cela pour faire des bandes tests, les étapes correspondent au nombre d'exposition par seconde que je souhaite afin de déterminer le meilleur temps global.

C'est parce que je n'arrivais pas à mettre deux digits, que je me lance dans une V2 de mon code. Pour le moment j'ai isolé uniquement cette partie de bande test pour réussir à mettre deux digits.

Pour répondre à "Lesept", le code pour changer le menu est opérationnel et fonctionne très bien quand je n'utilise pas la fonction "getKeypadIntegerMulti".

J'espere que cela est plus claire et plus facile à comprendre.

Merci beaucoup

hello
j'ai revu ton code
tu tournes le codeur pour sélectionner le memu
tu appuies sur le switch du codeur pour passer en saisie clavier pour le menu sélectionné
tu saisies ton nombre au clavier. pour terminer la saisie, il faut taper #. et tu effaces avec *

tu dézippes le fichier joint dans ton répertoire de travail
compte_pose_v2.zip (3,4 Ko)

Bonjour,
Merci beaucoup dfgh !
J'ai chargé ton code et effectivement cela fait ce que je souhaite !!
Je vais intégrer tout ca dans ma V2.
Pour la V1 j'utilisais un Arduino Uno mais pour la V2 je vais utiliser un MEGA, car j'ai pleins d'idées pour améliorer ce compte pose et le nombre I/0 analogiques et numériques ne sont pas suffisants avec mes idées et un UNO :slight_smile:
En tout cas merci beaucoup, je vais décortiquer ton code pour mieux comprendre ta démarche et comprendre pourquoi je n'y arrivais pas. Merci beaucoup

Hello, tu peux aussi traiter le switch de l'encodeur en : appui court = pose
Appui long= validation choix menu
Appui très long = ce que tu veux...

Tiens nous au courant.

Ton prog se mord la queue.
Au départ menu sélectionné= 0, par le if, départ saisie au clavier. Dont tu ne ressort pas. ( Value n'as jamais de valeur, donc 0x10=0. Pas de dizaine)
Les interruptions s'execute quand même , mais le retour d'interruption se fait dans la routine de saisie.

Nota: j'ai modifié le titre

Re nota: plutôt qu'un clavier, tu peux envisager de modifier les valeurs avec l'encodeur.
Exit le clavier et retour de 8 pins digitales.

hello
je viens de faire un petit code, veux tu l'essayer...

Uno,Nano,Mega
encodeur voie A, voie B, Switch central
écran lcd 4x20 en I2C

affiche un menu tournant de 12 lignes dans une fenêtre de 4 lignes
cette fonctionnalité est assurée par rotation de l'encodeur.
lors des changements de sens de rotation, une flèche se déplace
sur les 4 lignes de la fenêtre, signalant ainsi
quelle est la ligne du menu sélectionnée.
chaque ligne du menu est composée d'un libellé et d'un nombre lui étant rattaché.
un appui de plus d'une seconde permet de saisir le nombre et d'en changer
la valeur par rotation de l'encodeur. un nouvel appui long
valide la nouvelle valeur du nombre.
une rotation de l'encodeur recommencera à faire défiler les lignes du menu,
la ligne sélectionnable étant signalée par le triangle.
un appui de moins d'une seconde permet d'exécuter la fonction pointée par la ligne de menu.
exemple:
à la mise sous tension, les 4 premières lignes du menu sont affichées à l'écran.
par rotation de l'encodeur on choisi:
la ligne 2 " temps de pose "qui à pour nombre associé "5"
ce nombre correspond au temps d'exposition pour faire une photo.
après un appui de plus d'une seconde ( appui long), il est possible
de changer ce temps d'exposition.
un nouvel appui long permet de valider le nouveau temps d'exposition.
un appui court déclenchera l'exposition par allumage de la lampe de l'agrandisseur.

autre exemple:
pour faire plusieurs photos identiques ou une bande test
( expositions multiples avec déplacement d'un cache ),
après avoir sélectionné la ligne 3 "nbr tirages"
un appui long permet de régler le nombre de tirages
un appui long valide le nouveau nombre et reviens au mode de rotation du menu
en sélectionne en suite la ligne 4 "temps entre 2"
un appui long permet de régler le temps entre 2 expositions
un appui long valide le nouveau nombre et reviens au mode de rotation du menu
on reviens sur la ligne 3 du menu.
un appu court déclenchera une exposition, une tempo, une exposition, une tempo etc...
selon les nombres validés précédemment.

compte_pose_v3.zip (8,1 Ko)

:thinking: peut être faire une sauvegarde automatiques des paramètres en eeprom, et une relecture de ceux ci à la mise sous tension...
mettre les décomptages sur le lcd ( ceux qui sont sur le moniteur)...

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.