Ardu? No!Les boutons ≫ Diviseur de tension à résistances série

Diviseur de tension à résistances séries

Schéma de base

Voici le schéma de base:

Base pour une diviseur de tension pour boutons avec résistances en série

Si on ne tient pas compte de la résistance de 100kΩ, les résistances de 1kΩ forment un pont diviseur multiple qui va délivrer des tensions de VCC/6, 2VCC/6, 3VCC/6, 4VCC/6, 5VCC/6 et 6VCC/6. La résistance pull-down de 100kΩ et utile pour maintenir un état bas si aucun bouton n'est appuyé. Comme sa valeur est importante vis à vis des résistances du pont, son effet est négligeable si le nombre de boutons est raisonnable.

En utilisant des résistances identiques, et si elles proviennent d'un même lot, il y a des chances pour que les erreurs sur les valeurs des résistances se compensent en partie ce qui fait que ce montage permettra plus de boutons que le montage avec des résistances différentes. Toutefois la résistance de pull-down peut introduire des erreurs de linéarités si le nombre de boutons devient important, mais le programme peut en corriger l'effet.

Notez que normalement le courant dans le pont est quasiment égal à VCC/6kΩ (environ 0,8mA en 5V avec 6 boutons) que l'on appuie ou pas sur un bouton. Mais il peut grimper à 5mA si on appuie sur SW1 et SW6. Ce courant détermine la valeur (minimum) des résistances du pont.

On remarquera que la lecture est mono, car si on presse le bouton le plus en haut, on a du 5V en entrée quel que soient les états des autres boutons.

Influence de la 100kΩ

Je m'intéresse ici à l'erreur que va introduire la résistance de pull-down avec un pont fait avec des 1kΩ et une pull-down de 100kΩ. Je vais par ailleurs supposer tout idéal: le convertisseur et les valeurs des résistances.

Quand on appui sur le bouton du bas, c'est comme si au lieu d'avoir une résistance du pont de 1kΩ on avait une résistance de 0,99kΩ. L'erreur est faible. Si on appuie sur le bouton du haut, l'erreur est nulle car on a les 5V. C'est pour un des boutons vers les deux tiers à partir du bas que l'erreur est la plus importante. Par exemple avec 6 boutons, on désirerait lire pour le quatrième bouton la valeur numérique 683, mais on ne lit que 674, soit une erreur de 9 points sur les 1024 du convertisseur. C'est acceptable car l'écart entre deux lectures de boutons est de 171. Bien entendu l'erreur réelle sera plus importante à cause des erreurs que j'ai admises nulle pour ce calcul (tolérances sur les résistances, erreur du CAN...).

Voici un résumé de l'erreur due à la résistance de pull-down:

  Nb boutons  Erreur  Sur le bouton  
69/1714
10  15/102  7
2029/5113
2738/3818

On voit que pour 6 boutons l'erreur est négligeable, que pour 20 boutons on fait une erreur "d'un demi bouton" et que pour 27 boutons, l'erreur est si grande que si tous les composants étaient parfait cela ne fonctionnerait plus.

Il est toujours possible si on a beaucoup de boutons de diminuer la valeur de 1kΩ, ce qui augmente le courant en cas d'appui simultané des boutons extrêmes. Augmenter la 100kΩ n'est pas trop souhaitable, pour ne pas avoir d'erreurs dus à l'environnement.

Avec des 250Ω il faut 37 boutons pour avoir une erreur de 14 points sur les 28 qui séparent les lectures théoriques.

Une solution intéressante est de corriger la lecture.

Correction de la valeur lue

Cela me semble une bonne idée même quand on a peu de boutons. L'idée est de corriger la valeur lue afin de retrouver des valeurs pour les boutons régulièrement répartis. Cela permet par simple division d'avoir le numéro du bouton. Une meilleure solution serait de stocker les intervalles des valeurs pour chaque bouton (en fait on peut ne garder que les minimums, le maximum pour un bouton est le minimum pour le suivant) par exemple dans un tableau et en fonction de la valeur lue retrouver dans le tableau le bon bouton par une recherche dichotomique. C'est compliqué!

Voici le schéma de base pour ce calcul:

Schéma de base pour calculer la correction

Dans ce schéma P représente l'ensemble des résistances associées aux boutons (les 1kΩ du premier schéma), et R la résistance de pull-down (100kΩ dans le premier schéma). On appuie sur un interrupteur du milieu. Si P est la somme de toutes les valeurs des résistances et α.P la somme de toutes les valeurs des résistances en dessous du bouton, Si il n'y avait pas la pull-down, on aurait en sortie une tension α.VCC. Mais la présence de R va diminuer la tension et on aura β.VCC. α et β sont compris entre 0 et 1 (0 quand on a pas de boutons appuyé et 1 quand on prend le bouton le plus haut) et α≥β (égalité si α=β=0 ou si α=β=1).

On peut calculer β (pont diviseur avec en bas deux résistances en parallèle):

          α
β = ──────────────
    1 + α(1 - α)

On peut voir:
- si α=0 → β=0
- si α=1 → β=1
- α≥β
- sans pull-down (R=∞) → β=α

Mais notre lecture nous donne β et c'est α que l'on cherche (en toute rigueur, notre lecture nous donne 1024β et c'est 1024α que l'on cherche). J'ai cherché une correction simple avec un polynôme du second degré, mais cela ne fonctionne pas bien. Autant utiliser la bonne fonction même si elle est plus complexe. En retournant l'équation on trouve:

                                   _________________________________
                1024.β - 1024 + √(1024 - 1024.β)2 + 4.102422
1024.α = 1024 . ────────────────────────────────────────────────────
                              2.1024.β

Pour la correction, l'ancienne valeur lue c'est 1024.β, et la nouvelle sera 1024.α:

float temp=valeurLue*P/R; // 1024βP/R
valeurLue=1024.0*(temp-1024.0+sqrt(pow(1024.0-temp,2)+4*temp*temp))/(2*temp);

Exemple de programme de lecture

Ci-dessous un programme possible. Au delà de 5 ou 6 boutons, ou si la valeur de la résistance de pull-down n'est pas très grande vis à vis de la valeur totale des diviseurs, rajouter la correction ci dessus est une bonne idée. C'est ce qui est fait:

// Diviseur de tension à 32 résistances séries, 32 boutons

// VCC
//  ├── SWN-1 ─┐
// 1kΩ         │
//  ├── SWN-2 ─┤
// 1kΩ         ├── Vers A5
//  ├── SWN-3 ─┤
// 1kΩ         │
//  ├── SWN-4 ─┤
// 1kΩ         │
//     . . .
//  ├── SW2 ───┤
// 1kΩ         │
//  ├── SW1 ───┤
// 1kΩ         │
//  ├── SW0 ───┤
// 1kΩ       100kΩ
//  │          │
// GND        GND

const float N = 25; // Nombre de boutons; A ajuster
// R=100kΩ Résistance de pull-down
// P=Nx1kΩ Résistance de la chaîne complète sans la pull-down
const float PsurR = N*1.0/100.0; // Pour des 1kΩ et 100kΩ; A ajuster
const byte BOUTONS = A5; // Broche de lecture; A ajuster

void setup()
{
  Serial.begin(115200); // Régler aussi la console à 115200 bauds!
}

int valeurLue, // Résultat de la conversion brute puis corrigée
    oldValeurLue, // Mémorisation pour permettre deux lectures consécutives identiques
    touche, // Numéro de la touche
    oldTouche; // Touche précédente appuyé 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
  float temp=valeurLue*PsurR; // 1024βP/R
  valeurLue=1024.0*(temp-1024.0+sqrt((1024.0-temp)*(1024.0-temp)+4*temp*temp/PsurR))/(2*temp);

  //Extraction
  touche=(valeurLue+(512.0/N))/(1024.0/N); // Cela donne le N° de la touche 0..N-1
  
  // Affichage
  if (touche!=oldTouche) // Si changement
  {
    if (touche) // C'est une nouvelle touche
    {
      Serial.print("Bouton SW");
      Serial.print(touche-1); // Boutons numérotés à partir de 0
      Serial.print("   (erreur:");
      Serial.print(valeurLue-touche*1024.0/N,0); // Valeur de l'erreur
      Serial.print("/");
      Serial.print(512.0/N,0); // On a le droit d'une erreur de 16 maximum
      Serial.println(")");
      delay(100); // Anti-rebond
    }
    oldTouche=touche; // Mémorisation pour ne pas afficher plusieurs fois
  }
}

Et voici l'affichage que j'obtiens:

Bouton SW0   (erreur:-3/8)
Bouton SW1   (erreur:-3/8)
Bouton SW2   (erreur:-3/8)
Bouton SW3   (erreur:-3/8)
Bouton SW4   (erreur:-3/8)
Bouton SW5   (erreur:-4/8)
Bouton SW6   (erreur:-3/8)
Bouton SW7   (erreur:-3/8)
Bouton SW8   (erreur:-4/8)
Bouton SW9   (erreur:-3/8)
Bouton SW10   (erreur:-3/8)
Bouton SW11   (erreur:-3/8)
Bouton SW12   (erreur:-3/8)
Bouton SW13   (erreur:-3/8)
Bouton SW14   (erreur:-3/8)
Bouton SW15   (erreur:-4/8)
Bouton SW16   (erreur:-3/8)
Bouton SW17   (erreur:-3/8)
Bouton SW18   (erreur:-4/8)
Bouton SW19   (erreur:-5/8)
Bouton SW20   (erreur:-3/8)
Bouton SW21   (erreur:-4/8)
Bouton SW22   (erreur:-3/8)
Bouton SW23   (erreur:-3/8)
Bouton SW24   (erreur:-4/8)
Bouton SW25   (erreur:-2/8)
Bouton SW26   (erreur:-3/8)
Bouton SW27   (erreur:-3/8)
Bouton SW28   (erreur:-2/8)
Bouton SW29   (erreur:-3/8)
Bouton SW30   (erreur:-2/8)
Bouton SW31   (erreur:-2/8)
Bouton SW32   (erreur:-2/8)
Bouton SW33   (erreur:-3/8)
Bouton SW34   (erreur:-2/8)
Bouton SW35   (erreur:-2/8)
Bouton SW36   (erreur:-2/8)
Bouton SW37   (erreur:-1/8)
Bouton SW38   (erreur:-1/8)
Bouton SW39   (erreur:0/8)
Bouton SW40   (erreur:-1/8)
Bouton SW41   (erreur:-1/8)
Bouton SW42   (erreur:0/8)
Bouton SW43   (erreur:0/8)
Bouton SW44   (erreur:0/8)
Bouton SW45   (erreur:0/8)
Bouton SW46   (erreur:0/8)
Bouton SW47   (erreur:1/8)
Bouton SW48   (erreur:0/8)
Bouton SW49   (erreur:0/8)
Bouton SW50   (erreur:1/8)
Bouton SW51   (erreur:1/8)
Bouton SW52   (erreur:0/8)
Bouton SW53   (erreur:0/8)
Bouton SW54   (erreur:0/8)
Bouton SW55   (erreur:1/8)
Bouton SW56   (erreur:0/8)
Bouton SW57   (erreur:1/8)
Bouton SW58   (erreur:1/8)
Bouton SW59   (erreur:1/8)
Bouton SW60   (erreur:0/8)
Bouton SW61   (erreur:0/8)
Bouton SW62   (erreur:-1/8)
Bouton SW63   (erreur:-1/8)

On remarquera que j'ai une erreur de -4 au maximum, et que je pourais aller jusqu'à 8. En plus en ajoutant systématiquement 2 points, l'erreur irait de -2 à +3. Il y a de la marge. Cela provient du fait que les résistances que j'ai utilisées proviennent d'un même lot que je n'ai pas trié, et qu'alors les erreurs se compensent. Cemontage permet beaucoup plus de boutons que les autres pour cette raison. On pourrait très certainement monter à 100 boutons (si je les avais).

Je n'ai pas mesuré non plus la résistance de 100kΩ et si sa valeur est supérieure à cette valeur, cela introduirait une erreur négative comme on le voit sur le résultat.

Bilan

- lecture simple, mais avec correction indispensable
- résistances identiques compensant les erreurs
MAIS
- lecture mono
- 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

A cause des valeurs identiques pour les résistances, je crois que c'est le montage qui permet, avec le plus de sécurité, le plus grand nombre de boutons sur une seule broche. Je pense que l'on doit pouvoir lire plus de 100 boutons sur une seule broche. Montage en lecture mono très intéressant