Ardu? No!Les boutons ≫ Matrice triangulaire triple

Matrice triangulaire triple

La lecture est mono, on s'autorise à faire des erreurs de lecture si plus d'un bouton est appuyé.

En voici le principe: Avec N entrées (N>1), on va mettre systématiquement trois boutons entre deux entrées quelconques. Pour comprendre, regardons ce qui se passe avec 2 entrées. On aura donc trois boutons, câblés de la façon suivante:

Schéma pour la matrice triangulaire triple avec 3 boutons

On va faire une lecture dans les deux sens:
- on met D0 en sortie à LOW et on lit D1 (qui est en INPUT_PULLUP)
- on met D1 en sortie à LOW et on lit D0 (qui est en INPUT_PULLUP)

Si on a lu HIGH et HIGH, aucun bouton n'est appuyé
Si on a lu HIGH et LOW, SW3 est appuyé
Si on a lu LOW et HIGH, SW2 est appuyé
Si on a lu HIGH et HIGH, SW1 est appuyé

Notez bien que l'on est obligé de lire des deux côtés et donc de mémoriser au moins la première lecture.

Bien entendu l'appui sur SW1 cache les appuis sur SW2 ou SW3, et l'appui simultané de SW2 et SW3 fera croire à un appui sur SW1. La lecture est mono, sans possibilité de savoir si on appuie sur un bouton ou plusieurs. Mais cela permet de tripler le nombre de boutons par rapport à la matrice triangulaire, au prix d'un algorithme un peu plus long.

Cela pourrait donner par exemple pour 5 entrées:

Schéma pour la matrice triangulaire triple premier jet

Mais cela nécessite d'avoir des actions chez un fabricant de diodes. Dans la pratique, comme on ne poura pas détecter même avec ce montage si deux boutons sont appuyés ou pas, on peut regrouper les diodes ainsi:

Schéma pour la matrice triangulaire triple correcte

Pour lire un seul bouton, on commence par mettre toutes les broches en INPUT_PULLUP. On passe ensuite un côté du bouton en sortie à LOW, puis on procède comme indiqué en tout début de page (une lecture dans un sens, une lecture dans l'autre. On peut aussi ne faire les lectures qu'une fois:
- mettre D0 à LOW et lire D1, D2, D3, ... DN
- mettre D1 à LOW et lire D0, D2, D3, ... DN
- mettre D2 à LOW et lire D0, D1, D3, ... DN
...
- mettre DN-1 à LOW et lire D0, D1, ... DN-2, DN
- mettre DN à LOW et lire D0, D1, ... DN-2, DN-1

Si on numérote les entrées D0, D1, D2, D3, ... DN, et que l'on fait un tableau pour noter le numéro des boutons possibles, cela peut donner avec 6 entrées:

Lecture à LOW
D0D1D2D3D4D5
S
o
r
t
i
e

à

L
O
W
D0N°1 ou N°31N°2 ou N°32N°3 ou N°33N°4 ou N°34N°5 ou N°35
D1N°16 ou N°31N°6 ou N°36N°7 ou N°37N°8 ou N°38N°9 ou N°39
D2N°17 ou N°32N°21 ou N°36N°10 ou N°40N°11 ou N°41N°12 ou N°42
D3N°18 ou N°33N°22 ou N°37N°25 ou N°40N°13 ou N°43N°14 ou N°44
D4N°19 ou N°34N°23 ou N°38N°26 ou N°41N°28 ou N°43N°15 ou N°45
D5N°20 ou N°35N°24 ou N°39N°27 ou N°42N°29 ou N°44N°30 ou N°45

On ne peut rien mettre dans la matrice sur la diagonale car on ne peut pas mettre les deux entrées d'un bouton sur la même entrée. Sans les diodes on aurait une matrice triangulaire, on a triplé le nombre de boutons, on obtient une matrice triangulaire triple.

Pour N entrées, la matrice carrée à N2 cases. En retirant la diagonale de N cases (N2-N) on a le nombre de cases remplies. Pour avoir le nombre total de boutons possibles, il faut encore en rabouter la moitié. On peut avoir au maximum 3(N2-N)/2 boutons.
- avec 2 entrées: 3 bouton (mais deux fois le montage "2 boutons, 1 broche" permet plus de boutons et une lecture plus simple)
- avec 3 entrées: 9 boutons, cela commence à devenir intéressant
- avec 4 entrées: 18 boutons
- avec 8 entrées: 84 boutons, à comparer avec les 16 boutons d'une matrice carrée hexadécimal classique

Si on veut un clavier téléphone 12 touches, ou un clavier hexadécimal 16 touches, on n'a plus besoin que de 4 broches contre 7 ou 8 avec le montage classique. Mais c'est au prix d'une complexité supplémentaire pour le décodage.

On notera aussi sur le schéma que les diodes du haut sont pour plusieurs boutons et qu'à mesure ou on descend, les diodes sont moins communes. Si on n'a pas besoin de tous les 3(N2-N)/2 boutons, cela économisera des diodes (enlever deux boutons en bas économise deux diodes).

Pour la programmation, le plus compréhensible est de faire une fonction qui recherche les boutons entre deux broches. Ce n'est pas économique en temps car pour chaque bouton, je suis obligé de mettre une broche en sortie puis en entrée 4 fois, alors que dans certains cas une fois serait suffisant.

Dans le programme qui suit, je ne mémorise rien. Mais du coup pour l'affichage, il faut que j'appelle trois fois la même fonction à cause de l'ordre d'affichage.

// Matrice triangulaire triple, pour chacun des couples d'entrées, trois boutons sont mis:
// (2,3), (2,4), (2,5), (2,6), (2,7), (3,4), (3,5), (3,6), (3,7), (4,5), (4,6), (4,7), (5,6), (5,7) et (6,7)



void setup()
{
  Serial.begin(115200); // Régler aussi la console à 115200 bauds!
  for (byte broche=2; broche <=7; broche++) pinMode(broche, INPUT_PULLUP); // Repos, toutes les broches en INPUT_PULLUP
}



byte lecture(byte ligne, byte colonne)
// Cette fonction retourne 0 si le bouton sans la diode est appuyé, 1 ou 2 si un
// des deux boutons avec une diode est appuyé, 3 si aucun des trois n'est appuyé
// Il faut que ligne > colonne
{
  byte resultat = 0;

  // lecture dans un sens
  digitalWrite(ligne, LOW); pinMode(ligne, OUTPUT); // Mettre la ligne à LOW et la colonne étant déja en INPUT_PULLUP
  if (digitalRead(colonne) == HIGH) resultat = 2; 
  pinMode(ligne, INPUT_PULLUP); // Remettre la ligne en entrée
  
  // lecture dans l'autre sens
  digitalWrite(colonne, LOW); pinMode(colonne, OUTPUT); // Mettre la colonne à LOW et la ligne en INPUT_PULLUP
  if (digitalRead(ligne) == HIGH) resultat += 1; 
  pinMode(colonne, INPUT_PULLUP); // Remettre la colonne en entrée
  
  // Fin
  return resultat;
}



void loop()
{
  Serial.println("\n\n(2,3) (2,4) (2,5) (2,6) (2,7) (3,4) (3,5) (3,6) (3,7) (4,5) (4,6) (4,7) (5,6) (5,7) (6,7)");
  
  // Pour les boutons sans diode
  for (byte ligne=2; ligne<=6; ligne++) for (byte colonne=ligne+1; colonne<=7; colonne++) // Pour tous les couples
    if (lecture(ligne, colonne) == 0) Serial.print("appui ");
    else Serial.print("  -   "); // Bouton non appuyé
  Serial.println();
  
  // Pour les boutons avec une diode anode vers le bouton
  for (byte ligne=2; ligne<=6; ligne++) for (byte colonne=ligne+1; colonne<=7; colonne++) // Pour tous les couples
    if (lecture(ligne, colonne) == 1) Serial.print("appui ");
    else Serial.print("  -   "); // Bouton non appuyé
  Serial.println();
  
  // Pour les boutons avec une diode cathode vers le bouton
  for (byte ligne=2; ligne<=6; ligne++) for (byte colonne=ligne+1; colonne<=7; colonne++) // Pour tous les couples
    if (lecture(ligne, colonne) == 2) Serial.print("appui ");
    else Serial.print("  -   "); // Bouton non appuyé
  Serial.println();
  
  delay(500); // Pas trop souvent
}

On peut obtenir cet affichage si un bouton (broche 3 - anode-diode-cathode - bouton appuyé - broche 6):

(2,3) (2,4) (2,5) (2,6) (2,7) (3,4) (3,5) (3,6) (3,7) (4,5) (4,6) (4,7) (5,6) (5,7) (6,7)
  -     -     -     -     -     -     -     -     -     -     -     -     -     -     -   
  -     -     -     -     -     -     -     -   appui   -     -     -     -     -     -   
  -     -     -     -     -     -     -     -     -     -     -     -     -     -     -   

Mono?

La lecture est donc mono et on ne peut même pas savoir qu'il y a plus d'un bouton appuyé. Si on appuie sur le bouton qui n'est pas en série avec une diode par exemple, il va masquer ses deux confrères avec diode.

Variante: matrice double à 2 diodes

Ce n'est pas parce que l'on peut mettre jusqu'à 3(N2-N)/2 boutons qu'on est obligé de les mettre. Si on n'a besoin que de N2-N boutons, on peut retirer un tiers des boutons de la matrice, pour avoir une matrice triangulaire double. On essaie par exemple d'économiser le code. Voici ce que cela donne pour 2 entrées (donc 2 boutons):

Schéma pour la matrice triangulaire triple à 2 diodes, 2 entrées

La lecture dans un sens donne l'état d'un bouton, la lecture dans l'autre sens donne l'état du deuxième bouton. Le lecture est stéréo. On n'a plus besoin de mémoriser une lecture. L'algorithme est donc plus simple. Par contre cela ne diminue pas le nombre de diodes.

Pour 5 entrées, cela donne:

Schéma pour la matrice triangulaire triple à 2 diodes

Et la matrice pour 6 boutons devient:

Lecture à LOW
D0D1D2D3D4D5
S
o
r
t
i
e

à

L
O
W
D0N°1N°2N°3N°4N°5
D1N°16N°6N°7N°8N°9
D2N°17N°21N°10N°11N°12
D3N°18N°22N°25N°13N°14
D4N°19N°23N°26N°28N°15
D5N°20N°24N°27N°29N°30

Pour la programmation, on peut par exemple faire:

// Matrice triangulaire double à deux diodes, pour chacun des couples d'entrées, deux boutons sont mis:
// (2,3), (2,4), (2,5), (2,6), (2,7), (3,4), (3,5), (3,6), (3,7), (4,5), (4,6), (4,7), (5,6), (5,7) et (6,7)

void setup()
{
  Serial.begin(115200); // Régler aussi la console à 115200 bauds!
  for (byte broche=2; broche <=7; broche++) pinMode(broche, INPUT_PULLUP); // Repos, toutes les broches en INPUT_PULLUP
}

boolean lecture(byte ligne, byte colonne)
// Cette fonction retourne true si le courant colonne -> ligne peut passer
{
  boolean resultat = false;
  digitalWrite(ligne, LOW); pinMode(ligne, OUTPUT); // Mettre la ligne à LOW et la colonne étant déjà en INPUT_PULLUP
  if (digitalRead(colonne) == LOW) resultat = true; 
  pinMode(ligne, INPUT_PULLUP); // Remettre la ligne en entrée
  return resultat;
}

void loop()
{
  Serial.println("\n\n(2,3) (2,4) (2,5) (2,6) (2,7) (3,4) (3,5) (3,6) (3,7) (4,5) (4,6) (4,7) (5,6) (5,7) (6,7)");

  // Pour les boutons avec une diode dans un sens
  for (byte ligne=2; ligne<=6; ligne++) for (byte colonne=ligne+1; colonne<=7; colonne++) // Pour tous les couples
    if (lecture(ligne, colonne)) Serial.print("appui ");
    else Serial.print("  -   "); // Bouton non appuyé
  Serial.println();  

  // Pour les boutons avec une diode dans l'autre sens
  for (byte ligne=2; ligne<=6; ligne++) for (byte colonne=ligne+1; colonne<=7; colonne++) // Pour tous les couples
    if (lecture(colonne, ligne)) Serial.print("appui ");
    else Serial.print("  -   "); // Bouton non appuyé
  Serial.println();  

  delay(500); // Pas trop souvent
}

Variante: matrice double à 1 diodes

Si on n'a besoin que de N2-N boutons, on peut aussi tenter d'économiser le nombre de diodes. Voici ce que cela donne pour 2 entrées (donc 2 boutons):

Schéma pour la matrice triangulaire triple à 1 diodes, 2 entrées

La lecture dans un sens donne l'état d'un bouton, la lecture dans l'autre sens donne l'état des deux boutons. Si le courant passe dans les deux sens, c'est SW1 qui est appuyé, si le courant ne passe que dans un sens, c'est SW2 qui est pressé. Le lecture est mono, si SW1 est appuyé, on ne peut plus savoir si SW2 l'est ou pas. L'algorithme est un peu plus compliqué qu'avec deux diodes car il faut lire dans les deux sens et mémoriser au moins pour les boutons en série avec une diode.

Pour 5 entrées, cela donne:

Schéma pour la matrice triangulaire triple à 1 diodes

Et la matrice pour 6 boutons devient:

Lecture à LOW
D0D1D2D3D4D5
S
o
r
t
i
e

à

L
O
W
D0N°1 ou N°16N°2 ou N°17N°3 ou N°18N°4 ou N°19N°5 ou N°20
D1N°16N°6 ou N°21N°7 ou N°22N°8 ou N°23N°9 ou N°24
D2N°17N°21N°10 ou N°25N°11 ou N°26N°12 ou N°27
D3N°18N°22N°25N°13 ou N°28N°14 ou N°29
D4N°19N°23N°26N°28N°15 ou N°30
D5N°20N°24N°27N°29N°30

Il n'y a pas vraiment plus simple que l'algorithme de la matrice triangulaitre triple, sauf que l'affichage se fait sur deux lignes au lieu de trois. On peut le penser comme une matrice triangulaire triple pour laquelle im manque un tiers des boutons. En conséquence, le montage à 1 diode économise la moitié des diodes par rapport à la matrice triangulaire à 2 diodes, mais la lecture est plus compliquée. Il n'y a pas de solution meilleure entre l'une que l'autre.

Bilan

- pour N entrées, 3(N2-N)/2 boutons
- plus de boutons qu'avec les autres montages digitaux
MAIS
- lecture mono
- pour N entrées, il faut jusqu'à 2(N-1) diodes
- algorithme plus compliqué
- on ne trouve pas de claviers pré-connectés ainsi
- je ne connais pas de bibliothèque pour ce montage
- utilisation d'interruption impossible

Intéressant si on a vraiment beaucoup de boutons et si on ne veut pas passer en analogique (pour être certain du fonctionnement).