Calculatrice - concaténer les caractères

Mettez les pins dans un tableau dans le même ordre que les nombres, comme ça pas besoin de répéter 10 fois le même code

J’ai pas regardé comment vous gérez les décimaux assurez vous que des 0 après le point soient bien gérés (12.00005 par exemple ne doit pas faire 12.5)

Bonjour J-M-L,

Avec mon code 12.00005+0 = 12.00005 mais j’ai du rajouter une ligne à ma fonction NbDecimal() pour traiter les chiffres à 5 décimales et modifier le code dans la fonction calcul() (lcd.print(nbActuel,5);). 5 chiffres après la virgule, je pense que c’est suffisant pour moi.

Mes compétences en C sont insuffisantes et je ne comprends pas.

Merci.

Que se passe t il si vous tenez appuyé un bouton plus de 200ms ? Ou si vous en appuyez 3 à la fois ?

J-M-L,
Si j’appuie au delà des 200ms, key s’affiche toutes les 200ms sur l’écran lcd. Si key est égal à 3 :
333333333333…
Si j’appuie sur 3 boutons à la fois, 123 par exemple, il s’affiche sur l’écran lcd : 123123123123…

Merci.

Me revoilà,
Pour info, je vous donne les caractéristiques techniques de mon montage :

  • 18 boutons poussoirs sont soudés sur une carte universelle et reliés à une carte nano, ils sont reliés aux entrées numériques et analogiques du microcontrôleur :

1/ les 11 entrées numériques (D2-D12) sont tirées une par une à la masse par une résistance de 10K ;
2/ Les entrées analogiques A0, A1, A2, A3 et A7 sont également tirées une par une à la masse par une résistance de 10KΩ ;
3/ Les entrées analogiques A4 et A5 sont utilisées pour l’I2C de l’écran LCD ;
4/ l’entrée analogique A6 est tirée à +5V par une résistance de 470Ω, un deuxième bouton poussoir est soudé en parallèle et est connecté entre l’A6 et la masse par une résistance de 1KΩ.

Pour les deux boutons poussoirs connectés à A6, je me suis inspiré de ce tuto :
http://modelleisenbahn.triskell.org/spip.php?article59
Mais je ne suis pas allé jusqu’à contrôler les états (ENFONCE - NON_PRESSE), pour deux boutons seulement, je me suis contenté de relevé que analogRead(A6)==0) pour le premier et analogRead(A6)==697) pour le deuxième.

Voilà je vous donne mon code auquel j’ai ajouté une fonction racine carrée :

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);// défini l'adresse et le type d'écran lcd : 16 x 2

// déclaration des variables
const int bouton0 = 2;
const int bouton1 = 3;
const int bouton2 = 4;
const int bouton3 = 5;
const int bouton4 = 6;
const int bouton5 = 7;
const int bouton6 = 8;
const int bouton7 = 9;
const int bouton8 = 10;
const int bouton9 = 11;
const int bouton10 = 12;
const int bouton11 = A7;
const int bouton12 = A6;

int Statutbouton0 = 0; 
int Statutbouton1 = 0; 
int Statutbouton2 = 0;
int Statutbouton3 = 0;
int Statutbouton4 = 0;
int Statutbouton5 = 0;
int Statutbouton6 = 0;
int Statutbouton7 = 0;
int Statutbouton8 = 0;
int Statutbouton9 = 0;
int Statutbouton10 = 0;

int NbChiApVirgule = 0;

boolean decimal = false;
boolean result = false;

//calculatrice
// variable globale retenant l'opérateur sélectionné
char operateur   ;

// variable globale retenant le précédent nombre
float  nbPrecedent  ;

// variable globale retenant le nombre actuel
float  nbActuel   ;



void setup() {
  lcd.init(); 
  lcd.backlight();
  
  pinMode(bouton0, INPUT);// D2
  pinMode(bouton1, INPUT);// D3
  pinMode(bouton2, INPUT);// D4
  pinMode(bouton3, INPUT);// D5
  pinMode(bouton4, INPUT);// D6
  pinMode(bouton5, INPUT);// D7
  pinMode(bouton6, INPUT);// D8
  pinMode(bouton7, INPUT);// D9
  pinMode(bouton8, INPUT);// D10
  pinMode(bouton9, INPUT);// D11
  pinMode(bouton10, INPUT);//D12
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);
 
}

void loop() {

  
  
  Statutbouton0 = digitalRead(bouton0);
  Statutbouton1 = digitalRead(bouton1);
  Statutbouton2 = digitalRead(bouton2);
  Statutbouton3 = digitalRead(bouton3);
  Statutbouton4 = digitalRead(bouton4);
  Statutbouton5 = digitalRead(bouton5);
  Statutbouton6 = digitalRead(bouton6);
  Statutbouton7 = digitalRead(bouton7);
  Statutbouton8 = digitalRead(bouton8);
  Statutbouton9 = digitalRead(bouton9);
  Statutbouton10 = digitalRead(bouton10);
  
  char key;
  

  if (Statutbouton0 == HIGH) {
   decimal = true;
   key = '.';
   lcd.print(key);
   
   delay(200);  

  } 
   if (Statutbouton1 == HIGH) {
  if (result==true) Efface(),result=false;
  key = '0';
  if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
  nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
  lcd.print(key);
       
  delay(200); 

   }
   if (Statutbouton2 == HIGH) {
    if (result==true) Efface(),result=false;
   key = '1';
   
   if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
   nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
   lcd.print(key);
   delay(200);  
   } 
   if (Statutbouton3 == HIGH) {
    if (result==true) Efface(),result=false;
    key = '2';
   if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
   nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
   lcd.print(key);
    
  delay(200);  
   } 
    if (Statutbouton4 == HIGH) {
  if (result==true) Efface(),result=false;
   key = '3';
   if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
   nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
   lcd.print(key);
    
  delay(200);  
   }
   if (Statutbouton5 == HIGH) {
if (result==true) Efface(),result=false;
   key = '4';
   if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
   nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
   lcd.print(key);
    
  delay(200);  
   } 
   if (Statutbouton6 == HIGH) {
    if (result==true) Efface(),result=false;
    key = '5';
    if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
    nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
   lcd.print(key);
    
  delay(200);  
   } 
   if (Statutbouton7 == HIGH) {
    if (result==true) Efface(),result=false;
    key = '6';
    if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
   nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
   lcd.print(key);
    
  delay(200);  
   }
   if (Statutbouton8 == HIGH) {
   if (result==true) Efface(),result=false; 
   key = '7';
    if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
   nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
   lcd.print(key);
    
  delay(200);  
   }
   if (Statutbouton9 == HIGH) {
    if (result==true) Efface(),result=false;
   key = '8';
    if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
   nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
   lcd.print(key);
    
  delay(200);  
   } 
  if (Statutbouton10 == HIGH) {
    if (result==true) Efface(),result=false;
   key = '9';
   if (decimal==true) NbChiApVirgule = NbChiApVirgule + 1;
   nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
   lcd.print(key);
    
  delay(200);  
   } 
  if (digitalRead(A0) == HIGH) {
    key = '=';
    if (decimal==true) NbDecimal(), decimal=false ;
  Calcul(); 
    
  delay(200);  
   } 
   if (digitalRead(A1) == HIGH) {
   
   key = '+';
   lcd.print(key);
   if (decimal==true) NbDecimal(), decimal=false ;
   NbChiApVirgule = 0 ;
   nbPrecedent = nbActuel ;
   operateur   = key      ;
   nbActuel    = 0        ;
   
    
  delay(200);  
   } 
   if (digitalRead(A2) == HIGH) {
   
   key = '-';
   lcd.print(key);
   if (decimal==true) NbDecimal(), decimal=false ;
   NbChiApVirgule = 0 ;
   nbPrecedent = nbActuel ;
   operateur   = key      ;
   nbActuel    = 0        ;
   
    
  delay(200);  
   } 
   if (digitalRead(A3) == HIGH) {
   
   key = '*';
   lcd.print(key);
   if (decimal==true) NbDecimal(), decimal=false ;
   NbChiApVirgule = 0 ;
   nbPrecedent = nbActuel ;
   operateur   = key      ;
   nbActuel    = 0        ;
   
    
  delay(200);  
   } 
 
   
   if (analogRead(bouton11)> 511) {
   
   key = '/';
   lcd.print(key);
   if (decimal==true) NbDecimal(), decimal=false ;
   NbChiApVirgule = 0 ;
   nbPrecedent = nbActuel ;
   operateur   = key      ;
   nbActuel    = 0        ;
   
    
  delay(200);  
  } 

  if (analogRead(bouton12)==0) {
   key = 'C';
   Efface();
   delay(200);
  } 
  if (analogRead(bouton12)==697) {
  operateur = 'R';
  //lcd.print('R');
  Calcul(); 
  delay(200);
  } 
}

void Calcul()
{
      

      result = true;
      lcd.setCursor(0,1);
         
      if ( operateur == '+' )nbActuel = nbPrecedent + nbActuel,lcd.print ('='),lcd.print(nbActuel,5);
      
      if ( operateur == '-' ) nbActuel = nbPrecedent - nbActuel,lcd.print ('='),lcd.print(nbActuel,5);
      
      if ( operateur == '*' ) nbActuel = nbPrecedent * nbActuel,lcd.print ('='),lcd.print(nbActuel,5);
     
      if ( operateur == '/' ) nbActuel = nbPrecedent / nbActuel,lcd.print ('='),lcd.print(nbActuel,5);
      
      if ( operateur == 'R' ) nbActuel = sqrt(nbActuel),lcd.print ('='),lcd.print(nbActuel,5);
}

 void Efface()
 {
      NbChiApVirgule = 0;
      decimal=false;
      nbActuel = 0; 
      nbPrecedent = 0;
      lcd.clear();
 }
 
void NbDecimal ()
{
  switch (NbChiApVirgule) {
   
    case 1 :
    nbActuel=nbActuel/10;
    break;
    case 2 :
    nbActuel=nbActuel/100;
    break;
    case 3 :
    nbActuel=nbActuel/1000;
    break;
    case 4 :
    nbActuel=nbActuel/10000;
    break;
    case 5 :
    nbActuel=nbActuel/100000;
    break;
       
}
}

J’ai travaillé de manière empirique, c’est quand je n’ai plus eu assez de boutons que j’ai cherché à en brancher plusieurs sur une entrée analogique. Pareil pour le code…
Maintenant je vais brancher une pile 9V reliée à VIN et à GND avec un interrupteur (j’espère que ça va le faire).
Telle quelle la calculatrice est certes très basique mais elle fonctionne très bien.

Voilà je suis preneur de toutes critiques, conseils car je suis débutant et j’ai beaucoup à apprendre de vous.

Merci déjà pour tout ce que vous m’avez apporté.
Philippe

Est ce un comportement désirable ?

Maintenant je vais brancher une pile 9V reliée à VIN et à GND avec un interrupteur

Pour un fonctionnement ponctuel ça devrait aller un moment, mais lisez quand même cet article

Non J-M-L ce n’est pas un comportement désirable :sleepy:
Bonne soirée.

C’est une opportunité d’améliorer encore plus la calculatrice :slight_smile:

Votre gestion des boutons est un peu trop directe. Vous évacuez les rebonds par le délai de 200ms mais vous n’attendez pas le relâchement.

Si vous mettiez des else entre les if vous pourriez n’avoir qu’un seul bouton pris en compte

sinon pour simplifier votre gestion des boutons, éventuellement utilisez la librairie de @bricoleau ou alors la librairie OneButton de Matthias Hertel.

Merci J-M-L
Je vais travailler ce point.
Bonne journée.

hello
j’ai joué avec ton code
les BP sont raccordés entre GND et les entrées D0 à A3
nota A0 est D14, A1 est D15, A2 est D16, A3 est D17
les entrées sont déclarées en INPUT_PULLUP
les PINS 0 et 1 sont utilisées car tu n’utilises pas le moniteur
l’adresse de ton LCD est 0x 27, celle de mon lcd est 0x26
A6 et A7 ne sont pas utilisées.

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x26, 16, 2);// défini l'adresse et le type d'écran lcd : 16 x 2
//LiquidCrystal_I2C lcd(0x27, 16, 2);// défini l'adresse et le type d'écran lcd : 16 x 2
byte bouton[]     = {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17 };//nano
char caractere[]  = { '0','1','2','3','4','5','6','7','8','9','+','-','*','/','R','C','.','='};
int NbChiApVirgule = 0;
long decimal       = 0;
float  nbPrecedent = 0;
float  nbActuel    = 0;
boolean result     = false;
char   operateur;
char   key;

void setup()
{
 lcd.init();
  //lcd.begin();
  lcd.backlight();
  for (byte f = 0; f <= 17; f++)
  {
    pinMode(bouton[f], INPUT_PULLUP);
  } 
}

void loop()
{
  for (byte f = 0; f <= 17; f++)
  {
    if (digitalRead(bouton[f]) == LOW)
    {
      key = caractere[f];lcd.print(key);
      delay(200);
      while (digitalRead(bouton[f]) == LOW){;}    //si le BP à été appuyé
    }
  }

  if (key == 'C') {Efface();}
  if (key == '.') {decimal = 10;}
  if (key == '=') {calculs();}

  for (byte f = 0; f <= 9; f++)
  {
    if (key == caractere[f])
    {
      if ( key >= '0' && key <= '9' )
      {
        if (decimal != 0)
        { 
          nbActuel = (  nbActuel  + (float( key - '0' ) / (decimal))) ;
          decimal = decimal * 10;
          //lcd.setCursor(0, 0); lcd.print(nbActuel, 5);
        }
        else
        { 
          nbActuel = ( ( nbActuel * 10 ) + ( key - '0' ) ) ;
          //lcd.setCursor(0, 0); lcd.print(nbActuel, 5);
        }
        key = '_';
      }
    }
    if ( key == '+' || key == '-' || key == '*' || key == '/' || key == 'R' )
    {
      //lcd.print (key);
      nbPrecedent = nbActuel ;
      operateur   = key      ;
      key = '_';
      nbActuel    = 0;
      decimal     = 0;
    }
  }
}


void Efface()
{
  decimal = 0;
  nbActuel = 0;
  nbPrecedent = 0;
  lcd.clear();
  key = '_';
}
void calculs()
{
  if ( operateur == '+' ) nbActuel += nbPrecedent   ;
  if ( operateur == '-' ) nbActuel -= nbPrecedent   ;
  if ( operateur == '*' ) nbActuel *= nbPrecedent   ;
  if ( operateur == '/' ) nbActuel /= nbPrecedent   ;
  if ( operateur == 'R' ) nbActuel  = sqrt(nbActuel);
  decimal = 0; lcd.setCursor(0, 1); lcd.print ( nbActuel , 12 ) ;
  key = '_';
  decimal = 0;
  nbActuel = 0;
  nbPrecedent = 0;
}

Merci dfgh,
Maintenant je comprends pourquoi J-M-L voulait que je mette les pins dans un tableau !
L’utilisation d’un tableau et d’une boucle simplifie énormément le code.
Encore fallait-il savoir créer un tableau et utiliser une boucle for.
Bravo et merci pour ce partage qui va me faire évoluer plus vite !
Philippe

Oui c’était l’idée d’utiliser les tableaux pour cela

On peut écrire cela juste

while (digitalRead(bouton[f]) == LOW);  // attente relâchement 

Noter que le délai de 200ms ne se justifie plus, 15ms devraient aller Pour la gestion des rebonds

Les pins TX1 et RX0 sont donc également des broches digitales d’entrée / sorti et j’avais pas vu D13.
Oupssssssssssss :sunglasses:

c’était bien le but :grin: (je pense qu’ étudier le code des autres n’est pas une perte de temps)

@JML :+1: merci

dfgh,
J'ai une dernière question :

C'est quoi le moniteur ?

Merci encore.
Philippe

c'est ton écran PC, cette possibilité est utilisée pour faire du debugage
les instructions Serial.print ( ma variable ) ; //ecrivent la valeur de la variable sur ton écran
idempour du texte : Serial.print ( "ma variable est égale a "); // ecrit ma variable est égale a sur ton écran PC

dans un cas comme dans l'autre, si tu rajoutes "ln" au print ( Serial.println(ma variable); il y aura un retour à la ligne a la fin de l'écriture sur le moniteur.

il y a aussi la possibilité de faire des tabulation avec \t ( je crois que c'est t )

ces instructions utilisent la liaison usb de ta carte arduino avec le PC.
il faut initialiser cette liaison serie dans le setup : Serial.begin(vitesse en bauds); exemple : Serial.begin(115200);

le moniteur paux aussi etre utilisé comme traceur, il faut aller dans outil et cliquer sur "moniteur" ou sur "traceur"
le moniteur peut aussi etre ouvert en cliquant sur la petite loupe en haut à droite de la fenetre principale de l'IDE
le traceur ne peut pas etre ouvert de cette façon
pour que le traceur fasse des courbes, il faut utiliser Serial.println(ma variable); cest le "ln" qu'il ne faut pas oublier

et enfin, après avoir ouvert le moniteur ou le traceur, il faut regler la vitesse de com avec le choix multiple en bas à droite du moniteur. bien sur la meme que celle que tu as initialisée dans le setup

dans ton cas, pour pouvoir utiliser les pins 0 et 1 dans ton prg et aussi pour l liaison serie, la seule solution est de ne pas traiter les pins0 et dans tes declarations, setup,loop, et fonctions. ainsi tu peux voir tes Serial.print et debuger ton prg
sans utiliser les chiffres correspondant aux pins 0 et 1.
puis une fois ton prg au point, tu revalides les pins 0 et 1 comme touches. ( et adieu la liaison serie.

tu as du utiliser le lcd pour ton debugage, le moniteur pouvait le faire

Merci beaucoup dfgh pour toutes ces nombreuses informations.
Merci d'avoir consacré ton temps pour m'aider et me donner des explications qui me sont très utiles !

Très sincèrement.
Philippe

Bonsoir,

Afin d'améliorer ma calculatrice en y ajoutant des fonctions, j'ai testé le code de dfgh, en soudant une carte universelle avec une nano et 17 boutons poussoir .
dans un premier temps j'ai souhaité tester mes connexions avec ce code :

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
byte bouton[]     = { 0, 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17 };//nano
char caractere[]  =  = { '0','1','2','3','4','5','6','7','8','9','+','-','*','/','R','C','=','.'};
char   key;



void setup() {
//Serial.begin(9600);
lcd.init();  
lcd.backlight();
  
 
 
    for (byte f = 0; f <= 17; f++)
  {
    pinMode(bouton[f], INPUT_PULLUP);
    
  } 
 

}

//pinMode(bouton[2], INPUT_PULLUP);

void loop() {

  
    //for (byte f = 0; f <= 2; f++)
    for (byte f = 14; f <= 17; f++)
  {
    if (digitalRead(bouton[f]) == LOW)
    {
      key = caractere[f];
      lcd.print(key);
      delay(200);
      while (digitalRead(bouton[f]) == LOW){;}    //si le BP à été appuyé
    }
    }
  }

Mon entrée D13 ne fonctionne pas et je crois que c'est du à la LED témoin sur 13 ?
Je ne trouve pas comment résoudre ce PB.
Dommage, c'était bien sympa de gérer 17 boutons en même temps...

Quelqu'un a t-il déjà rencontré ce PB ?

Merci.

Bonjour,

Essaye de mettre une résistance de pullup externe assez faible (4.7k voire moins) sur D13.