Ardu? No!Les boutons ≫ Suppression de résistances poly

Suppression de résistances poly

L'idée

En mélangeant des boutons et des résistances, on peut obtenir un dipôle dont la résistance va varier en fonction de l'appui sur les boutons. En mesurant cette résistance, on peut en déduire quel(s) bouton(s) est(sont) appuyé(s). Pour la lecture on n'a pas vraiment le choix si on veut rester simple (sans circuit supplémentaire), on fera un pont diviseur à partir du 5V. Ici, l'idée est de court-circuiter des résistances.

Voici le câblage de cette résistance variable:

Montage à suppression de résistances

Ce montage permet une lecture mono ou poly.

L'intérêt de ce montage est un câblage plus simple si les résistances sont soudées directement sur les boutons.

Lecture poly

Voici le montage pour 6 interrupteurs:

Montage à suppression de résistances poly à 6 poussoirs

Pour profiter de la plage complète du CAN, soit les 1024 valeurs, et comme sur la broche analogique on peut avoir du 0V, mais pas de 5V, on utilisera le 1,1V comme référence. Ainsi en fonction des appuis, on se baladera entre 0V et 1,1V.

Le programme récupérera un octet contenant la l'état de tous les boutons, le 0 indique le bit de poids faible associé à SW0 et R0, le 5 indique le bit de poids fort associé à SW5 et R5. J'ai arbitrairement choisi la résistance R5 à 10kΩ. Les autres résistances s'obtiennent par division par 2 des valeurs. La résistance P (le pull-up) est choisie pour avoir 1,1V sur l'entrée de l'Arduino (tension de référence) si la résistance "en bas" vaut 2 fois R5. On aurait une précision un poil plus élevée si on avait choisi la résistance de pull-up de façon à avoir 1,1V quand tous les boutons sont non appuyés, mais le choix fait permet d'avoir une résistance P indépendante du nombre de boutons et un programme plus simple. Si la résistance la plus grande vaut 10kΩ, P prendra la valeur 70,909kΩ quel que soit le nombre de boutons. On peut multiplier ou diviser les valeurs de toutes les résistances par un même facteur.

Comme le résultat de la fonction analogRead() n'est pas linéaire en fonction de la valeur de la résistance équivalente des boutons, il vaut mieux appliquer une correction. La vraie correction permet d'être bonne quel que soit le nombre de boutons. Si R est trop petite, on va perdre des informations si beaucoup de boutons sont appuyés, c'est donc à éviter. Si R est un peu trop grande et qu'à vide on a par exemple 994 au lieu des 1024 attendu, il suffira de multiplier la lecture par 1024/994 avant de faire la conversion.

Voici les informations permettant de réaliser ce montage:

Nombre
de
  boutons  
Écart
entre 2
  lectures  
CAN (1)Ri
228781310kΩ, 5kΩ
311892110kΩ, 5kΩ, 2,5kΩ
45497310kΩ, 5kΩ, 2,5kΩ, 1,25kΩ
52699910kΩ, 5kΩ, 2,5kΩ, 1,25kΩ, 625Ω
613101110kΩ, 5kΩ, 2,5kΩ, 1,25kΩ, 625Ω, 312,5Ω
76101810kΩ, 5kΩ, 2,5kΩ, 1,25kΩ, 625Ω, 312,5Ω, 156,25Ω
83102110kΩ, 5kΩ, 2,5kΩ, 1,25kΩ, 625Ω, 312,5Ω, 156,25Ω, 78,125Ω
(1) C'est la valeur optimale que retourne analogRead() sans appuis.

On notera que l'erreur de lecture possible pour 8 boutons n'est plus que de 3 points sur les 1024 que donne le CAN. Si la lecture est excellente, que les tension sont parfaites et les résistances sans tolérances, on pourrait aller jusqu'à 8 boutons. Dans la pratique 7 semble le maximum.

Dans le programme suivant, à vide, le CNA retournait la valeur 1022 du fait de l'imprécision sur les résistances. Le tableau précédent indiquait une valeur idéale de 1011. Il y a donc une ligne pour cette ajustement dans le programme:

  valeurLue *= 1011.0/1022.0; // Correction due à la résistance P

Cette première correction permet de diminuer les erreurs principalement quand peu de boutons sont actifs. Cela permet ainsi d'avoir un bouton de plus. Attention, la valeur lue sans cette correction ne doit pas être 1023 qui montre une "saturation" que l'on ne peut pas corriger. Dans ce cas augmenter légèrement P jusqu'à avoir moins de 1023 à vide.

Un exemple de programme pour lire 6 boutons:

// Suppression de résistances à lecture poly

//  VCC
//   │
// 70,9kΩ
//   │
//   ├─────┬─── vers A0
//   │     │
// 10kΩ   SW5
//   │     │
//   ├─────┤
//   │     │
//  5kΩ   SW4
//   │     │
//   ├─────┤
//   │     │
// 2,5kΩ  SW3
//   │     │
//   ├─────┤
//   │     │
// 1,25kΩ SW2
//   │     │
//   ├─────┤
//   │     │
// 625Ω   SW1
//   │     │
//   ├─────┤
//   │     │
//  312Ω  SW0
//   │     │
//   ├─────┘
//  GND

const byte N = 6; // Nombre de boutons; A ajuster 
const byte BOUTONS = A0; // Broche de lecture; A ajuster

void setup()
{
  Serial.begin(115200); // Régler aussi la console à 115200 bauds!
  analogReference(INTERNAL); // Pour passer à 1,1V
}

int valeurLue, // Résultat de la conversion brute puis corrigée
    oldValeurLue, // Mémorisation pour permettre deux lectures consécutives identiques
    touche, // Mot de 5 bits contenant les touches (SW4.SW3.SW2.SW1.SW0)
    oldTouche; // Mot précédent pour ne pas l'afficher plusieurs fois

void loop()
{
  do // Lecture brute
  {
    oldValeurLue = valeurLue; // Sauvegarde de la mesure précédente
    valeurLue = analogRead(BOUTONS); // Nouvelle lecture
  } while (valeurLue!=oldValeurLue); // On recommence jusqu'à avoir deux lectures identiques

  // Correction de la valeur
  //      Serial.println(valeurLue);  // Rajouter cette ligne pour lire la valeur
                                      // à mettre au dénominateur de la ligne suivante
  valeurLue *= 1011.0/1022.0; // Correction due à la résistance P
  valeurLue =1024*(1.0-(1.0/(1<<N))) - ((valeurLue * (5.0 - 1.1)) / (5.0 - 1.1*valeurLue/1024));

  //Extraction
  touche=((valeurLue+(512>>N)) >> (10-N)); // Cela donne un mot SW5.SW4.SW3.SW2.SW1.SW0
  
  // Affichage
  if (touche!=oldTouche) // Si changement
  {
    if (touche) // Il y a au moins une touche appuyée
    {
      // Affichage type "   SW4     SW3     SW2     SW1     SW0"
      for (int8_t bouton=N-1; bouton>=0; bouton--)
      {
        Serial.print("   SW");  
        Serial.print(bouton);  
        Serial.print("  ");  
      }
      Serial.println();
	  
      // Affichage des boutons
      for (int8_t bouton=N-1; bouton>=0; bouton--) // Pour chaque bouton
        if (touche & (1<<bouton)) Serial.print(" appuyé ");
        else Serial.print("   --   "); // Non appuyé
      Serial.print("  écart=");
      Serial.print(valeurLue-touche*(1<<(10-N)));
      Serial.print("/");
      Serial.print(512/(1<<N));
      Serial.println(")\n"); // Retour chariot et saut d'une ligne en plus
      delay(100); // Antirebond
    }
    oldTouche=touche; // Mémorisation pour ne pas afficher plusieurs fois
    delay(1000); // Pas trop souvent
  }
}

Pour la correction, j'ai laissé les valeurs 5.0 et 1.1 qui peuvent être ajustées en fonction des valeurs des tensions 5V et 1,1V réelles.

Voici les lignes obtenues:

   SW5     SW4     SW3     SW2     SW1     SW0  
   --      --      --      --      --    appuyé   écart=1/8)
   --      --      --      --    appuyé    --     écart=2/8)
   --      --      --      --    appuyé  appuyé   écart=2/8)
   --      --      --    appuyé    --      --     écart=3/8)
   --      --      --    appuyé    --    appuyé   écart=1/8)
   --      --      --    appuyé  appuyé    --     écart=3/8)
   --      --      --    appuyé  appuyé  appuyé   écart=2/8)
   --      --    appuyé    --      --      --     écart=1/8)
   --      --    appuyé    --      --    appuyé   écart=2/8)
   --      --    appuyé    --    appuyé    --     écart=1/8)
   --      --    appuyé    --    appuyé  appuyé   écart=-1/8)
   --      --    appuyé  appuyé    --      --     écart=2/8)
   --      --    appuyé  appuyé    --    appuyé   écart=2/8)
   --      --    appuyé  appuyé  appuyé    --     écart=-1/8)
   --      --    appuyé  appuyé  appuyé  appuyé   écart=0/8)
   --    appuyé    --      --      --      --     écart=1/8)
   --    appuyé    --      --      --    appuyé   écart=2/8)
   --    appuyé    --      --    appuyé    --     écart=2/8)
   --    appuyé    --      --    appuyé  appuyé   écart=2/8)
   --    appuyé    --    appuyé    --      --     écart=2/8)
   --    appuyé    --    appuyé    --    appuyé   écart=2/8)
   --    appuyé    --    appuyé  appuyé    --     écart=1/8)
   --    appuyé    --    appuyé  appuyé  appuyé   écart=1/8)
   --    appuyé  appuyé    --      --      --     écart=2/8)
   --    appuyé  appuyé    --      --    appuyé   écart=2/8)
   --    appuyé  appuyé    --    appuyé    --     écart=1/8)
   --    appuyé  appuyé    --    appuyé  appuyé   écart=1/8)
   --    appuyé  appuyé  appuyé    --      --     écart=2/8)
   --    appuyé  appuyé  appuyé    --    appuyé   écart=1/8)
   --    appuyé  appuyé  appuyé  appuyé    --     écart=2/8)
   --    appuyé  appuyé  appuyé  appuyé  appuyé   écart=2/8)
 appuyé    --      --      --      --      --     écart=4/8)
 appuyé    --      --      --      --    appuyé   écart=3/8)
 appuyé    --      --      --    appuyé    --     écart=3/8)
 appuyé    --      --      --    appuyé  appuyé   écart=4/8)
 appuyé    --      --    appuyé    --      --     écart=3/8)
 appuyé    --      --    appuyé    --    appuyé   écart=4/8)
 appuyé    --      --    appuyé  appuyé    --     écart=3/8)
 appuyé    --      --    appuyé  appuyé  appuyé   écart=4/8)
 appuyé    --    appuyé    --      --      --     écart=3/8)
 appuyé    --    appuyé    --      --    appuyé   écart=3/8)
 appuyé    --    appuyé    --    appuyé    --     écart=3/8)
 appuyé    --    appuyé    --    appuyé  appuyé   écart=3/8)
 appuyé    --    appuyé  appuyé    --      --     écart=3/8)
 appuyé    --    appuyé  appuyé    --    appuyé   écart=3/8)
 appuyé    --    appuyé  appuyé  appuyé    --     écart=3/8)
 appuyé    --    appuyé  appuyé  appuyé  appuyé   écart=4/8)
 appuyé  appuyé    --      --      --      --     écart=4/8)
 appuyé  appuyé    --      --      --    appuyé   écart=3/8)
 appuyé  appuyé    --      --    appuyé    --     écart=2/8)
 appuyé  appuyé    --      --    appuyé  appuyé   écart=3/8)
 appuyé  appuyé    --    appuyé    --      --     écart=3/8)
 appuyé  appuyé    --    appuyé    --    appuyé   écart=3/8)
 appuyé  appuyé    --    appuyé  appuyé    --     écart=3/8)
 appuyé  appuyé    --    appuyé  appuyé  appuyé   écart=3/8)
 appuyé  appuyé  appuyé    --      --      --     écart=3/8)
 appuyé  appuyé  appuyé    --      --    appuyé   écart=4/8)
 appuyé  appuyé  appuyé    --    appuyé    --     écart=3/8)
 appuyé  appuyé  appuyé    --    appuyé  appuyé   écart=2/8)
 appuyé  appuyé  appuyé  appuyé    --      --     écart=2/8)
 appuyé  appuyé  appuyé  appuyé    --    appuyé   écart=3/8)
 appuyé  appuyé  appuyé  appuyé  appuyé    --     écart=2/8)
 appuyé  appuyé  appuyé  appuyé  appuyé  appuyé   écart=0/8)

On constate que les erreurs sont de 4 au maximum, et que l'on ne doit pas dépasser 8. Avec mes résistances je ne pourrais pas utiliser un bouton de plus. En toute rigueur, si on retire à la valeur corrigée 2 points, tous les écarts vont être diminuée de 2 et ils iront de -3 à +2. On pourrait espérer mettre un bouton de plus (écart permit de +/-4), mais il faut penser au vieillissement des composant et aux variations des résistances avec la température...

Bilan

- lecture simple, avec correction obligatoire au dela de 4 boutons
- lecture poly
- câblage simplifié si on soude directement les résistances sur les boutons
MAIS
- résistances non identiques ne compensant pas les erreurs
- les boutons n'ont pas de borne commune
- une résistance par bouton en plus
- je ne connais pas de bibliothèques pour ce montage
- utilisation d'interruption impossible

Intéressant, mais peu utilisé. On peut peut être aller jusqu'à 7 boutons.