[résolu] matrice de boutons et résistances pull up

Bonjour,

J'essaie de réaliser une matrice de boutons poussoirs pour en faire un clavier. Le principe de fonctionnement : les boutons sont organisés en une matrice de 5 colonnes et 10 lignes. Chaque colonne est connectée, via une résistance 10k, à une sortie (pin A1 à A5 utilisées en digital) et chaque ligne est connectée à une entrée en pull up (pin 2 à 12). L'arduino envoie successivement un signal dans chaque colonne et, si un un signal est reçu en sortie, on peut en déduire la position du bouton pressé.

Pour éviter que les signaux prennent des chemins inattendus (le "ghosting"), j'ai ajouté à la suite de chaque bouton poussoir une diode. Elles sont orienté avec le + du côté des sorties (pin A1 à A5) et le - du côté des entrées.

Côté programmation, tous les outputs sont à LOW, sauf celui de la colonne que je teste. Quand un input est à HIGH, j'en conclus qu'on appuie sur un bouton. Je mets le code en dessous si vous voulez vous pencher dessus.

Et là ça coince : toutes mes entrées sont en permanence à HIGH, même quand le clavier est complètement débranché de l'arduino !

A force d'essais, je trouve une situation dans laquelle j'obtiens le résultat attendu : Je mets toutes les sorties à HIGH sauf celle que je teste. Quand une entrée est à LOW, j'en déduis qu'on appuie sur un bouton. Mais, pour que ça marche, je dois court-circuiter mes diodes.

Pour ce que j'en comprends, j'aurais dû inverser la polarité des diodes car les résistances de pull up font que le courant circule dans l'autre sens.

Avant de dessouder et ressouder mes 50 diodes, pouvez-vous confirmer que c'est le bon diagnostic ?

Merci si vous m'avez lu jusque là !

Le code :

// to listen keyboard with python :
// >>> import serial
// >>> ser = serial.Serial('/dev/ttyACM0')
// >>> while True:
// >>>     print(ser.readline())
// >>>

const int first_col = A1;
const int last_col = A5;

const int first_line = 2;
const int last_line = 12;

const long unsigned int wait_time = 50;
long unsigned int last_time;
int current_col;
int current_button_id;

void setup() {
    for(int pin=first_col; pin<=last_col; pin++) {
        pinMode(pin, OUTPUT);
        digitalWrite(pin, LOW); // HIGH
    }

    for(int pin=first_line; pin<=last_line; pin++)
        pinMode(pin, INPUT_PULLUP);

    last_time = millis();
    current_col = first_col;

    Serial.begin(9600);
}

void refresh_cols() {
    if(millis() > last_time + wait_time) {
        last_time = millis();
        if(current_button_id != 0)
            Serial.println(current_button_id);

        digitalWrite(current_col, LOW); // HIGH
        if(++current_col > last_col)
            current_col = first_col;
        digitalWrite(current_col, HIGH); // LOW

    }
}

void check_lines() {
    current_button_id = 0;
    for(int pin=first_line; pin<=last_line; pin++)
        if(digitalRead(pin) == HIGH) // LOW
            current_button_id = current_col*100 + pin;            
}

void loop() {
    check_lines();   
    refresh_cols();   
}

sobriquet:
A force d'essais, je trouve une situation dans laquelle j'obtiens le résultat attendu : Je mets toutes les sorties à HIGH sauf celle que je teste. Quand une entrée est à LOW, j'en déduis qu'on appuie sur un bouton. Mais, pour que ça marche, je dois court-circuiter mes diodes.

Bonjour,

C'est bien ce qu'il faut faire.

Effectivement habituellement on met un ligne à HIGH et les autres à LOW, donc sur les schémas qu'on trouve les diodes sont dans ce cas.

C'est sur qu'avec des diodes à l'envers ça ne doit pas fonctionner.

A mon avis tu dois pouvoir te passer de diodes et de résistance de 10k en mettant les sorties des lignes inactives non à l'état haut, mais en entrée avec INPUT_PULLUP.

Si tu n'as pas envie de modifier toutes tes diodes, tu peux aussi ne pas utiliser INPUT_PULLUP et mettre des pulldown sur les entrées.

Merci beaucoup Kamill !

Maintenant ça marche, mettre des pulldown m'a probablement épargné beaucoup de travail !

Par contre, j'ai tenté sans succès de mettre les sorties des lignes inactives en INPUT_PULLUP et, pour l'instant, le circuit est dans un état bâtard avec toutes les sorties en OUTPUT, sans aucune résistance. Ça risque de poser un soucis si je garde le circuit comme ça ?

Merci beaucoup pepe pour cette réponse très complète !

Du coup, je me demande comment on détermine le temps de rebond maximum des boutons : il y a une formule pour ça, ou une valeur couramment utilisée ? Ou bien on la détermine plutôt par essais successifs ?

Et pour être exhaustif et ne pas oculter une autre méthode anti rebond il y a le condensateur (céramique 100nF) placé en parallèle avec le contact.

Différence de fonctionnement :

Le retard logiciel laisse les coupures de signal provoquées par les rebonds se manisfester avec leur effets électrostatiques qui si l'électronique est sensible peuvent être néfastes . Bon si c'est pour allumer une del (led) on s'en fout mais autant le savoir.

Le condensateur traite le problème à la base en empêchant la coupure du signal. Le condensateur dispense d'écrire des lignes de code pas vraiment utiles.

Nous ne sommes pas d'accord avec pepe qui refuse d'indiquer cette solution mais qui pour moi consiste à cacher la poussière sous le tapis.

Le grand débat (sur ce forum) est : "est-ce que le courant de court-circuit dans le condensateur ne risque-t-il pas de le détruire" et faut-il ajouter une résistance avec le condensateur pour le protéger ?
Personne n'a de résultats de test à présenter, mais ce que je constate c'est que de grands assembliers placent un simple condensateur dans leur matériel.

Conclusion : Tu es libre, tu connais les deux solutions, tu prend celle que tu préfères.

Merci pour toutes ces informations, je ne m'attendais pas à des échanges aussi instructifs !

Comme je n'utiliserai pas d'interruption et que je ne prévois pas une utilisation du clavier à plus de 20 appuis par secondes, j'ai pris le parti de laisser de côté la question des rebonds. Toutes les 50 ms, j'envoie la référence du dernier bouton appuyé s'il y en a un. Je retiens qu'afin de préserver la durée de vie du microcontrôleur, j'aurais intérêt à éviter d'avoir un output à HIGH

Je marque le sujet comme résolu, mais si vous avez envie de compléter, n'hésitez pas !