Arduino 10arduino_goodfields_64.jpgClavier analogique
 
Sommaire

Clavier  analogique à diodes Clavier analogique à diodes DEBUG DEBUG listing  10 listing 10
La page principale ... La page principale ...
   
Vers le début Vers Page 2 Vers sommaire Clavier analogique à diodes
Dans le chapitre 7, j'ai décrit un clavier à 10-24 touches sur une entrée analogique.
cliquez pour agrandir : photo/07_clavier10.gif un clavier simple avec 10 touches
cliquez pour agrandir : photo/clavier16_diodes.gif un câblage un peu plus compliqué si le clavier est matricé (prévu pour être multiplexé au départ)
La valeur de tension relevée sur le pin 'clavier' va donc nous permettre de savoir quelle touche est appuyée.
Afin d'éviter d'avoir des valeurs erronées à cause des contacts aléatoires ou des rebonds, on va lire plusieurs fois cette entrée, séparé par 10 ms entre chaque lecture.
Puis rechercher par rapport à la table ci-dessous (dans les déclarations) dans quelle fourchette on est pour retrouver la touche. Les valeurs déclarées sont celles relevés pendanta les tets, on comparera avec la fourchette "moyenne" par la ligne :
* while (itouche > ((xtouche[i]+xtouche[i+1])/2) && i < nbtouche); *
// CLAVIER 10 TOUCHES A DIODES 0,2V
int nbtouche = 10;
// caractère touche renvoyée
//                 <----------------clavier-10 touches------------>                16 touches--->                          24 touches--->
char ltouche[] =  {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '};        // nbtouche
// valeurs analogiques. A ajuster selon valeurs relevées après montage # 41 pour 0,2 Volts/diode
int xtouche[] =   {  0,  45,  90, 136, 181, 226, 270, 313, 354, 396, 437, 1023};  // nbtouche+1

/*
// CLAVIER 24 TOUCHES A DIODES 0,2V
int nbtouche = 24;
// caractère touche renvoyée
//                 <----------------clavier-10 touches------------>                16 touches--->                          24 touches--->
char ltouche[] =  {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', ' '};        // nbtouche
// valeurs analogiques. A ajuster selon valeurs relevées après montage # 41 pour 0,2 Volts/diode
int xtouche[] =   {  0,  45,  91, 136, 181, 226, 270, 313, 354, 396, 437, 478, 519, 560, 601, 642, 683, 724, 765, 806, 847, 888, 929, 970, 1010, 1023};  // nbtouche+1
*/

Ces fonctions sont assurées par le sous-programme 'lecture_clavier' que voici, avec des commentaires supplémentaires :
void ger_scrute_clavier(){
// transfert des anciennes valeurs lues 
  itouche2 = itouche1;
  itouche1 = itouche/facteur;
// lecture à l'instant t
  itouche = analogRead(clavier);

// pour calibrage, affichage des valeurs lues (pour ajuster votre tableau 'xtouche[]'
//  if (itouche < 1020 ) Serial.println(analogRead(clavier));

// si la touche est stable (donc pendant 3 appels)
  if ((itouche/facteur)==itouche1 && itouche1==itouche2) {
// recherche quelle touche est appuyée en comparant aux valeurs déclarées
    i=-1;
    do {
      i++;
    } while (itouche > ((xtouche[i]+xtouche[i+1])/2) && i < nbtouche);
// Ici, i contient le numero de la touche appuyée (avec 'i'='nbtouche' si aucune appuyée)
	
// si la touche a varié, on mémorise sa valeur dans 'vtouche'
    if (ltouche[i] != vtouche ) {
      vtouche = ltouche[i];
	  
// touche valide ( c'est à dire pas 'pas de touche')
      if (i < nbtouche) { 
        touche = vtouche;
// AH ! on gère aussi la 'répétition', c'est à dire que si on garde la touche enfoncée, 
//  ... au bout de 500ms, on va répéter cette touche toutes les 250 ms.
        touche_repeat = vtouche;
// attente 1ère répétition
        tempo_repeat=500;  // duree avant repetition
// pas de touche appuyée = ' '
      } else {
        touche_repeat = ' ';
      }
// si la touche est la même : on la répète
    } else {
      if (i < nbtouche && tempo_repeat == 0 ) {
        touche_repeat = vtouche;
        tempo_repeat=250;  // duree repetition
      }
    }
  }
  return;
}

Ce sous-programme est appelé toutes les 10 millisecondes dans le sous-programme 'ger_top_centieme' qui gère les problèmes de temps.
void ger_top_centieme (){
  unsigned long delta;
  unsigned long currentMillis = millis();

// Centième de secondes
   delta = currentMillis - previousMillis;
   if (delta >= 10) {
// save the last time you come here
    previousMillis = currentMillis;   

// scrutation du clavier toutes les 10ms
    ger_scrute_clavier();		// Gestion du clavier ANALOGIQUE <<<<<<<<<<<
    SUITE ...

Ensuite, comment utiliser ce clavier ? Dans le programme, n'importe où où l'on attends une touche :
	if (touche == '1') {
		TRAITEMENT ...
		touche = ' ';	// pour signifier que la touche est traitée
	}

Si on veut utiliser le traitement de répétition (pour augmenter une valeur par exemple) :
	if (touche_repeat == '1') {
		TRAITEMENT ...
		touche_repeat = ' ';	// pour signifier que la touche est traitée
	}

Vous verrez dans la page 12, l'utilisation dans le menu général ... :
// - sans répétition
    if (touche == '3') {
      mode--;
      grafcet_a = 10;
      touche = ' ';
    }
// + avec répétition
    if (touche_repeat == '4') {
      mode++;
      grafcet_a = 10;
      touche_repeat = ' ';
    }
// Ok
    if (touche != ' ' and touche != '4') {    // 3 est exclue du fait que traitée avant !
      grafcet_a = 100*mode;
      tempo_a = 0;
// debug      lcd.setCursor(0, 1);  lcd << "mod=" << mode << " gr=" << grafcet_a; delay(1000);
      Serial << modex[mode] << endl;
      lcd.clear(); touche_repeat = ' '; touche = ' ';
    }

	SUITE ...
   
Vers le début Vers Page 2 Vers sommaire DEBUG
Il est intéréssant de conditionner l'affichage, en particulier de 'Serial.print' seulement quand on 'debugge'. J'ai défini une constante de compilation 'debug' que l'on positionne par un 'define' :
// DEBUG : 0=pas de debug, valeur selon besoins
#define debug 1

Certaines parties de programme sont alors mises en service ou non par cette syntaxe :
#if debug > 0  
  Serial << "Serial ok" << endl;
#endif

#if debug > 2  
  Serial << "DEBUG est plus grand que 2" << endl;
#endif
   
Vers le début Vers Page 2 Vers sommaire listing 10
Voici le listing complet de la version 10 de mon ARDUINO UNO.
Ici, on ne fait qu'afficher la touche appuyée, c'est déjà pas mal !!!
/*
  GoodFields 10_clavier_analogique
  Clavier analogique à diodes et debug
  LCD
  Gestion du temps
  Compactage des sorties série (intégration d'une bibliothèque : Streaming)
  GRAFCET
  TEMPORISATION basique
  FRONT MONTANT/DESCENDANT
*/
//**********************************************************
// BIBLIOTHEQUES
// incluses dans le package Arduino de base
#include <LiquidCrystal.h>  // LCD

// ajoutées
#include <Streaming.h>
#include <Time.h>

// DEBUG : 0=pas de debug, valeur selon besoins
#define debug 1

//**********************************************************
// DECLARATIONS
// LCD initialize the library with the numbers of the interface pins
/* Câblage du LCD
 * LCD pin 1 to GND
 * LCD pin 2 to VCC 5V
 * LCD pin 3 : contraste sur le point milieu d'un potentiomètre de 10K entre le GND et le VCC (réglé très près de la masse)
 * LCD pin 4 RS to digital pin 4
 * LCD pin 5 RW to GND
 * LCD pin 6 Enable pin to digital pin 2
 * LCD pin 11 D4 pin to digital pin 6
 * LCD pin 12 D5 pin to digital pin 7
 * LCD pin 13 D6 pin to digital pin 8
 * LCD pin 14 D7 pin to digital pin 9
*/
//  LiquidCrystal lcd(RS, Enable,  D4, D5, D6, D7)
  LiquidCrystal lcd(4, 2, 6, 7, 8, 9);

// entrées-sorties
int led_a = 13;

// temporisations
int tempo_a,tempo_b;
// vitesse de clignotement : maintenant en millisecondes
int tempo_a_reset=1000;
int tempo_b_reset=700;
// gestion du temps
int previousSecond;      // secondes de l'horloge
int top_dixieme=false;   // top pour traitements au 1/10 seconde dans le P/P
int top_seconde=false;   // top pour traitements à la seconde dans le P/P
int top_minute=false;   // top pour traitements à la minute dans le P/P
unsigned long previousMillis, previousDecis;
// clavier à 16 touches et diodes sur entrée analogique
int clavier=A0;
int itouche,itouche1=-1,itouche2=-1,vtouche,tempo_repeat;
// touche renvoyée
char touche=' ',touche_repeat=' ';

// CLAVIER 10 TOUCHES A DIODES 0,2V
int nbtouche = 10;
// caractère touche renvoyée
//                 <----------------clavier-10 touches------------>                16 touches--->                          24 touches--->
char ltouche[] =  {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '};        // nbtouche
// valeurs analogiques. A ajuster selon valeurs relevées après montage # 41 pour 0,2 Volts/diode
int xtouche[] =   {  0,  45,  90, 136, 181, 226, 270, 313, 354, 396, 437, 1023};  // nbtouche+1

/*
// CLAVIER 24 TOUCHES A DIODES 0,2V
int nbtouche = 24;
// caractère touche renvoyée
//                 <----------------clavier-10 touches------------>                16 touches--->                          24 touches--->
char ltouche[] =  {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', ' '};        // nbtouche
// valeurs analogiques. A ajuster selon valeurs relevées après montage # 41 pour 0,2 Volts/diode
int xtouche[] =   {  0,  45,  91, 136, 181, 226, 270, 313, 354, 396, 437, 478, 519, 560, 601, 642, 683, 724, 765, 806, 847, 888, 929, 970, 1010, 1023};  // nbtouche+1
*/

// speedomètre = calcul de vitesse ...
int tours_ps,tours;

// GRAFCETS
int grafcet_a,grafcet_b;

//**********************************************************
// INITIALISATIONS
void setup() {
// définition taille du LCD :
  lcd.begin(16, 2);

// mise à l'heure
  setTime(12,15,00,25,12,13); // 12h15 le 25 déc 2013 setupArduinoTime(2013,25,21,12,15,00));
// initialize the pins
  pinMode(led_a, OUTPUT);
  pinMode(clavier, INPUT);
  digitalWrite(clavier, HIGH);       // turn on pullup resistors

// ligne série (pour traces)
  Serial.begin(9600);  // ou 9600 selon votre port COM
#if debug > 0  
  Serial << "Serial ok" << endl;
#endif

// AFFICHAGE sur LCD
  lcd.setCursor(0, 0);  lcd << "Serial OK";     // 1ere ligne
  lcd.setCursor(0, 1);  lcd << "GoodFields";    // 2eme ligne lcd.print ("toto="); lcd.pprint (toto,2);
  delay(1000);        // pour profiter du LCD au démarrage
  lcd.clear();    // Effacement général LCD
  
// on arme les grafcets
  grafcet_a = 1;
  grafcet_b = 1;
}
//**********************************************************
// PROGRAMME PRINCIPAL
void loop() {

// tours par seconde
  tours++;
  
// gestion du temps
  ger_top_centieme ();
  
// opérations à chaque dixième de seconde
  if (top_dixieme) {
    top_dixieme = false;
#if debug > 0  
// premier test
    itouche = analogRead(clavier);
    itouche1 = (itouche+20)/44;
    lcd.setCursor(0, 1);  lcd << "t=" << itouche1 << "," << itouche << "  ";    // 2eme ligne lcd
//    lcd.setCursor(0, 1);  lcd << "b=" << grafcet_b << " a=" << grafcet_a ;    // 2eme ligne lcd
#endif
  }
 
// opérations à chaque seconde
  if (top_seconde) {
    top_seconde = false;
    tours_ps=tours; tours=0;
#if debug > 0  
    lcd.setCursor(12, 1);  lcd << tours_ps ; //<< "t/s  ";    // 2eme ligne lcd
#endif

// horloge
#if debug > 0  
    horodatage_serial(); Serial << " top_seconde " << tours_ps << "t/s  " << endl;
#endif
    lcd.setCursor(0, 0);
    if (second()%10 > 7) {
      lcd << "XXX " << ((day()᝺)?"0":"") << day() << "/" << ((month()᝺)?"0":"") << month() << "/" << year();
    } else {
      lcd << "    " << ((hour()᝺)?"0":"") << hour() << ":" << ((minute()᝺)?"0":"") << minute() << ":" << ((second()᝺)?"0":"") << second() << "    ";
    }
// idéalement, XXX devrait être remplacé par {"Lun","Mar","Mer","Jeu","Ven","Sam","Dim"} (au boulot !)
    
// heart-beat chaque seconde   
//    if (lamp_tempo == 0 ) lamp_tempo = 20;  // ms
    }

//--------------------------------
// GRAFCET A
switch (grafcet_a) {

  case 1:
  if ( tempo_a == 0 ) {        // si la tempo est terminée,
    digitalWrite(led_a, HIGH);   // on allume la LED
    tempo_a = tempo_a_reset;             // on arme la tempo
    grafcet_a++;               // et on passe à l'étape suivante
  }
  break;      // cette instruction vous fait sauter à la fin du "switch"
  // sinon, on continue, et cela fait perdre du temps, et il peut arriver que d'autre "case" fonctionnent ! 

  case 2:
  if ( tempo_a == 0 ) {
    digitalWrite(led_a, LOW);    // turn the LED off by making the voltage LOW
    tempo_a = tempo_a_reset;             // on arme la tempo
    grafcet_a=1;               // on reboucle
  }    
  break;

// si grafcet_a n'a pas une valeur correcte, on passe ici
  default: 
      grafcet_a = 0; // on arrête
  break;
}      // fin du "switch"
// FIN GRAFCET A
//--------------------------------
// GRAFCET B
switch (grafcet_b) {

  case 1:
  if ( tempo_b == 0 ) {        // si la tempo est terminée,
    horodatage_serial(); Serial << " grafcet_b=" << grafcet_b <<  " grafcet_a=" << grafcet_a << endl;
    tempo_b = tempo_b_reset;             // on arme la tempo
    grafcet_b++;               // et on passe à l'étape suivante
  }
  break;      // cette instruction vous fait sauter à la fin du "switch"

  case 2:
  if ( tempo_b == 0 ) {
    horodatage_serial(); Serial << " grafcet_b=" << grafcet_b <<  " grafcet_a=" << grafcet_a << endl;
    tempo_b = tempo_b_reset;             // on arme la tempo
    grafcet_b=1;               // on reboucle
  }    
  break;

// si grafcet_a n'a pas une valeur correcte, on passe ici
  default: 
      grafcet_b = 0; // on arrête
  break;
}      // fin du "switch"
// FIN GRAFCET B
//--------------------------------
}
// ************************************************************************************************
// ************************************************************************************************
// SOUS-PROGRAMMES
// ************************************************************************************************
void ger_scrute_clavier(){
// transfert des anciennes valeurs lues 
  itouche2 = itouche1;
  itouche1 = itouche/facteur;
// lecture à l'instant t
  itouche = analogRead(clavier);

// pour calibrage, affichage des valeurs lues 
//  if (itouche < 1020 ) Serial.println(analogRead(clavier));

// si la touche est stable (donc pendant 3 appels)
  if ((itouche/facteur)==itouche1 && itouche1==itouche2) {
// recherche quelle touche est appuyée en comparant aux valeurs déclarées
    i=-1;
    do {
      i++;
    } while (itouche > ((xtouche[i]+xtouche[i+1])/2) && i < nbtouche);
// Ici, i contient le numero de la touche appuyée (avec 'i'='nbtouche' si aucune appuyée)
	
// si la touche a varié, on mémorise sa valeur dans 'vtouche'
    if (ltouche[i] != vtouche ) {
      vtouche = ltouche[i];
	  
// touche valide ( c'est à dire pas 'pas de touche')
      if (i < nbtouche) { 
        touche = vtouche;
// AH ! on gère aussi la 'répétition', c'est à dire que si on garde la touche enfoncée, 
//  ... au bout de 500ms, on va répéter cette touche toutes les 250 ms.
        touche_repeat = vtouche;
// attente 1ère répétition
        tempo_repeat=500;  // duree avant repetition
// pas de touche appuyée = ' '
      } else {
        touche_repeat = ' ';
      }
// si la touche est la même : on la répète
    } else {
      if (i < nbtouche && tempo_repeat == 0 ) {
        touche_repeat = vtouche;
        tempo_repeat=250;  // duree repetition
      }
    }
  }
  return;
}

// ************************************************************************************************
// Programme au -ieme de seconde
// gestion des temporisations
// NB : le débordement du compteur en (unsigned long) a lieu tous les 50 jours environ ...
void ger_top_centieme (){
  unsigned long delta;
  unsigned long currentMillis = millis();

// Centième de secondes
   delta = currentMillis - previousMillis;
   if (delta >= 10) {
// save the last time you come here
    previousMillis = currentMillis;   

// scrutation du clavier toutes les 10ms
    ger_scrute_clavier();

// gestion des TEMPORISATIONS (en ms mais précise à 10ms près)
    if (tempo_a >= delta ) { tempo_a -= delta; } else { tempo_a = 0; }
    if (tempo_b >= delta ) { tempo_b -= delta; } else { tempo_b = 0; }
    if (tempo_repeat >= delta ) { tempo_repeat -= delta; } else { tempo_repeat = 0; }
  }

// Dixième de seconde
   delta = currentMillis - previousDecis;
   if (delta >= 100) {
    previousDecis = currentMillis;   
    top_dixieme = true;
    
// tops seconde et minute pour traitements dans le main
    if (second() != previousSecond) {
      previousSecond = second();
      top_seconde = true;
      if (previousSecond == 0) top_minute=true;
    }
  }
  return;
}
// ************************************************************************************************
// affichage horloge complete sur la sortie serie, sans fin de ligne
void horodatage_serial() {
// digital clock display of the time
//  Serial << day() << "/" << month() << "/" << year() << " " << hour() << printDigits(minute()) << printDigits(second()) << endl; 
  Serial << ((day()᝺)?"0":"") << day() << "/" << ((month()᝺)?"0":"") << month() << "/" << year() << " " << ((hour()᝺)?"0":"") << hour() << ":" << ((minute()᝺)?"0":"") << minute() << ":" << ((second()᝺)?"0":"") << second();
}
// ************************************************************************************************
// ************************************************************************************************

la suite ... la suite ... La page principale ... La page principale ... PAS DE PAGE 11 !! PAS DE PAGE 11 !!

Photos de la page :

Dernière mise à jour : 11:39:59 18/09/2020