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:

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:

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 |
2 | 287 | 813 | 10kΩ, 5kΩ |
3 | 118 | 921 | 10kΩ, 5kΩ, 2,5kΩ |
4 | 54 | 973 | 10kΩ, 5kΩ, 2,5kΩ, 1,25kΩ |
5 | 26 | 999 | 10kΩ, 5kΩ, 2,5kΩ, 1,25kΩ, 625Ω |
6 | 13 | 1011 | 10kΩ, 5kΩ, 2,5kΩ, 1,25kΩ, 625Ω, 312,5Ω |
7 | 6 | 1018 | 10kΩ, 5kΩ, 2,5kΩ, 1,25kΩ, 625Ω, 312,5Ω, 156,25Ω |
8 | 3 | 1021 | 10kΩ, 5kΩ, 2,5kΩ, 1,25kΩ, 625Ω, 312,5Ω, 156,25Ω, 78,125Ω |
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.