Multi-boutons sur PinAnalogique

Bonjour,
j'aimerais pouvoir gérer plusieurs interrupteurs (x12 boutons poussoirs) avec les PINs Analogique de la carte arduino UNO rev3.

j'ai créer un projet théorique sur tinkercad d'après mes recherches sur internet.
j'aimerais savoir si je suis sur la bonne voie ?

le projet fonctionne sur le simulateur, mais je ne sais pas si il y a un risque pour une vrai carte arduino, étant débutant, j'ai des doutes...
(cours circuit entre +5v et GND >> 5.6Kohm ?)

je poscède déjà les boutons, les résistances...
-- je me demande quel reférence de diode de devrais utiliser pour le vrai projet, lesquelles commander ?
-- est-ce que mon montage est correct ?

merci d'avance a ceux ou celles qui prendront le temps de me lire et de m'éclairer.

const byte boutonA = A0;  //Entrée analogique des 6 boutons
const byte boutonB = A1;  //Entrée analogique des 6 boutons

byte BP_appuye = 0;  //Variable : le bouton appuyé

const int inter = 2; // pin d'interruption

//const int resistance_1 = 330;
//const int resistance_2 = 680;
//const int resistance_3 = 1200;
//const int resistance_4 = 2200;
//const int resistance_5 = 3300;
//const int resistance_A = 5600;

const int limit_1 = 46;
const int limit_2 = 125;
const int limit_3 = 231;
const int limit_4 = 361;
const int limit_5 = 474;
const int limit_6 = 816;

bool carteA = false; // bool carte A
bool carteB = false; // bool carte B 

void setup() {
  Serial.begin(9600);
  pinMode(boutonA, INPUT); //entrée analogique des boutons réglée en entrée
  pinMode(boutonB, INPUT); //entrée analogique des boutons réglée en entrée
  Initialisation_Interuption();
  
} 

void loop()    {
  
}


void Initialisation_Interuption(){
  attachInterrupt(digitalPinToInterrupt(inter), InterruptBouton, FALLING); //interruption sur pin D2
}
 

void InterruptBouton()  {
  int ValeurBoutonA = analogRead(boutonA);
  int ValeurBoutonB = analogRead(boutonB);
  
   Serial.println("-- -- -- -- -- -- --");
  
  if( ValeurBoutonA < 1020 ){ 
    carteA = true;  
  	Serial.print("READ_A0 : ");
  	Serial.println(ValeurBoutonA);    
  }
  if( ValeurBoutonB < 1020 ){ 
    carteB = true;
    Serial.print("READ_A1 : ");
  	Serial.println(ValeurBoutonB);   
  }
  
  Serial.println("-- -- -- -- -- -- --");

  
  if(ValeurBoutonA < limit_6 || ValeurBoutonB < limit_6) {
    if(carteA){ BP_appuye = 6;}
    if(carteB){ BP_appuye = 12;}
  }
  if(ValeurBoutonA < limit_5 || ValeurBoutonB < limit_5) {
    if(carteA){ BP_appuye = 5;}
    if(carteB){ BP_appuye = 11;}
  }
  if(ValeurBoutonA < limit_4 || ValeurBoutonB < limit_4) {
    if(carteA){ BP_appuye = 4;}
    if(carteB){ BP_appuye = 10;}
  }
  if(ValeurBoutonA < limit_3 || ValeurBoutonB < limit_3) {
    if(carteA){ BP_appuye = 3;}
    if(carteB){ BP_appuye = 9;}
  }
  if(ValeurBoutonA < limit_2 || ValeurBoutonB < limit_2) {
    if(carteA){ BP_appuye = 2;}
    if(carteB){ BP_appuye = 8;}
  }
  if(ValeurBoutonA < limit_1 || ValeurBoutonB < limit_1) {
    if(carteA){ BP_appuye = 1;}
    if(carteB){ BP_appuye = 7;}
  }
  
  Serial.println("-- -- -- -- -- -- --");
  Serial.println(BP_appuye);
  
  // raz boolean carteA & carteB
  carteA = false;
  carteB = false;  
 
}

Bonjour,

Pourquoi mettre des diodes ?!..

Cf. le projet "Plusieurs boutons poussoir sur une entrée analogique"

A suivre...

c'est pour pouvoir gérer les interruptions sur D2,

car la gestion des boutons se fait indépendanment du programme principale (pas dans le loop).

merci pour ton lien, j'ai de quoi lire sur le sujet :innocent:

en effet ton lien aborde le cas des POINTEURs, que je ne maitrisse pas pour l'instant, intéressant... merci

Juste une information pratique.
Pour les habitués de l'électronique, il est beaucoup plus facile de comprendre un montage avec le schéma électrique.

Il existe même des habitués du forum, dont je fais partie, qui refusent d'examiner les schémas de câblage.

Je sais très bien qu'un schéma de câblage "parle" plus à un débutant.

Mais, si on a fait un schéma de câblage Tinkercad ou Fritzing, le schéma électrique est simple à produire : il suffit de chercher le bon bouton et de cliquer dessus.
Et tu auras plus de personnes qui le regardera et plus de réponse :grinning_face:.

Je te signale une autre possibilité pour multiplier les boutons : les expenseurs comme le MCP23007 ou 23017 qui apporte 8 ou 16 entrées numériques supplémentaires.
Des bibliothèques existent pour les gérer.

Ils se commandent en I2C qui n'utilise que A5 et A5.
On peut en mettre 8 sur le bus I2C, ce qui "peut faire" 128 entrées/sorties supplémentaires.
On les trouve facilement sous forme de modules déjà câblés sur les sites chinois pour 2 ou 3 €

PS : fuir le PCF 8574, toujours présent chez les "gourous" internet, mais qui est antédiluvien et usine à gaz.

Edit : le PCF8574 est galère car il utilise une interruption pour détecter une modification d'une entrée. C'est le programme qui doit rechercher l'entrée qui a été modifiée.
Au vu des précisions que je n'avais pas encore vues, le côté galère est peut-être un avantage.

il n'y a pas besoin de faire cela si vous utilisez analogRead(). La broche n'est plus considérée comme une broche numérique, elle est routée vers l'ADC et un échantillonnage est effectué.


Il n'y a qu'un seul ADC sur UNO et faire une lecture consécutive rapprochées sur deux broches différentes peut conduire (suivant l'impédance d'entrée) à des résultats faussés. Vous verrez souvent une double lecture dont on jette la première valeur.

par exemple

  int vA = (analogRead(boutonA), analogRead(boutonA));
  int vB = (analogRead(boutonB), analogRead(boutonB));

enfin notez que les interruptions doivent être les plus courtes possibles... faire un print dans une ISR (même si arduino a fait un hack pour que ça ne bloque pas) n'est pas une bonne idée.

L'interruption est elle vraiment nécessaire ? Si votre loop tourne assez vite, vous pouvez simplement échantillonner les boutons à chaque tout de loop.

merci je vais étudier tes propositions...

mais le shema de cablage chez tinkercad, n'est vraiment pas clair en plus il faut 2 pages en pdf, et pas de possibilté de faire tenir sur une seul feuille , même avec si peu de composants.

merci je ne connaissais pas cette particularité,
ni cette syntaxe de déclaration :face_with_monocle:
ça ressemble à une déclaration de tableau, comment s'appel ce type de déclaration ?

oui j'ai vu ça, d'ailleur je vais au final enlever TOUS les print, c'est juste pour la simulation et les tests...
mais sans les print ça devrai être suffisament court, non ? comment le quantifié ?

oui le Loop() va être bien chargé, le programme principale est découpé en 6 phases avec des boucles et des boolean... bref
c'est pour ça que la solution de l'intéruption me semblais adéquat
néamoins rien de définitif.

merci.

Bonjour

concernant les diodes, des 1N4148 de base iront bien.

pour la broche 2 d’interruption, il ne faut pas oublier un pullup, sinon elle est en l’air à cause des diodes. pinMode(inter, INPUT_PULLUP);

les déclarations const int resistance_1 etc. ne servent pas dans le programme, les mettre en commentaire.

au début de void InterruptBouton() , il faudrait inhiber de nouvelles interruptions (rebond poussoirs?) detachInterrupt(inter(2));puis valider de nouveau à la fin.

en espérant que la lecture analogique soit fiable si les poussoirs ont des rebonds.

sinon il faudra placer un condensateur sur chaque entrée analogique, et insérer un retard avant de lire la valeur (le temps que le condensateur soit à une valeur stable)

avec condensateur, il faudra mettre une pause de 2ms avant de lire une valeur stabilisée, et après lecture, attendre que A0-A1 soit remonté à 5V avant de re-valider l’interruption, sinon nouvelle interruption (ce sera aussi le cas sans condensateur)

C’est une déclaration de variable standard avec valeur initiale genre

int variable = 42;

Sauf qu’ici j’utilise l’opérateur virgule qui a la particularité d’évaluer la première expression avant la virgule puis d’évaluer la seconde expression après la virgule et retourner cette valeur

Ici la première expression c'est l’appel à analogRead qui est donc évaluée ce qui a pour effet de connecter la pina l’ADC et donc de charger le petit condensateur associé à l’échantillonnage. On lit la valeur et on ne la conserve pas puis après la virgule on fait la même chose mais la broche était déjà connectée donc le Condo a eu plus de temps pour se charger et la lecture sera bonne ce coup ci. C’est la valeur qui est retournée par l’expression et donc celle qui est mis dans ma variable.

J’ai mis les deux appels de fonction entre parenthèses car on est dans la définition d’une variable et la virgule est trompeuse - mon intention va être confondue avec la double déclaration de variable parce qu’on a le droit d’écrire

int x = 42, y;

Et là, ce n’est pas l’opérateur « virgule » mais bien la déclaration de deux variables X qui prend la valeur initiale 42 et Y qui n’est pas initialisée.

Ceci n’est utile que si vous avez deux analogRead() sur des pins différentes et surtout que l’impédance est très différente entre les broches, ce qui fait que on pourrait avoir potentiellement un peu de tension résiduelle de la charge précédente dans le petit condensateur de l’ADC (ou pas le temps de charger si la constante de temps n’est pas bonne) au moment où on fait la lecture d’après.

(je suis plus soft que hard alors ces histoires d’impédance à regarder je ne me pose pas trop la question et je fais la double lecture -Les pros du hard vous diront sans doute que ce n’est pas nécessaire dans votre cas.)

inutile : voir ici, rubrique How it Works

Bonjour,

Ok, je n'avais pas vu la logique...

Maintenant, @ pascal0171, je serais partisan de ne pas mettre de condensateur qui va impacter la stabilisation de l'entrée analogique au profit d'une gestion logicielle des anti-rebonds (2 timers hard ou soft pour ce faire et totalement reconfigurables en fonction de la qualité des boutons ;-)

S'agissant du code de l'interruption void InterruptBouton(), sauf erreur de ma part, celui-ci est "très lourd" dans son exécution voire incompréhensible (manque cruellement de commentaires) car par exemple qu'est-ce qui empêche d'avoir carteA à true ET carteB à true et là c'est carteB qui gagne dans la m.a.j. de BP_appuye ...

Je me trompe sans doute (à confirmer / infirmer)

A suivre...

Il me semble qu’il serait intéressant d'étudier le comportement avec un condensateur directement sur D2, aprés les diodes, avec un pullup de charge et un pulldown de décharge, pour éviter les rebonds sur l’entrée D2 et avoir malgré tout (si possible) quelque chose qui ressemble â un front montant ou descendant.

5_cylindres: ok erreur de ma part, je suis novice et ne me suis pas encore servi d’interruptions…

je suis plutôt hard que soft :expressionless_face:

le rebond poussoir se répercute sur la lecture analogique non stable pendant ce rebond.

oui les diode empèche le tirage du pull up, je vois ...
donc pour le pull-up sur D2, je peux imaginer ajouter une resitance R7(10k) si je désire plutôt un pull-up en externe de la carte Arduino.

et donc pas besoin d'ajouter de condensateur 0.1uF ? ... ça tombe bien j'en avais pas sous la main.

ah oui j'avais pas penser à cette éventualité, merci.
mais lorsqu'un bouton est poussé la valeur tombe forcément en dessous de 1023 sur A0 ou A1 sur une des deux carte d'essais... normalement. mais merci je vais réécrire...et prendre en compte cette eventualité.

merci beaucoups pour vos retours jusqu'ici.
je vais reformater le code.

j'ai trouvé en récupe des diodes aujourd'hui justement, elle sont minuscules,mais à la loupe se sont bien des 1N4148.

a priori pas de risque de court circuit, je vois pas de liaison direct possible entre +5v > GND
donc je peux le tester ce schéma sur ma carte sans risque demain?

par contre je ferai un clean des print() et à la place je peux imaginer un appel d'une fonction qui allume une led de test pour visualiser le bon fonctionnement :

void testBoutonAppuye() {
digitalWrite(ledPin, HIGH);
}

void testBoutonRelache() {
digitalWrite(ledPin, LOW);
}

Tu fais bien comme tu veux, tu ne risque rien.

Mais pour l’avoir mainte fois testé, c’est trés rare que je n’ai pas constaté de rebond sur la fermeture ou l’ouverture d’un contact de BP.

Qui dit rebonds dit fronts montants et descendants…

Donc selon le type d'interruptions recherchées (sur fronts, sur niveaux, sur changement f’état) on est parfois obligé de filtrer pour supprimer les rebonds de tension.

À toi de faire tes tests et évaluer la pertinence d’un condensateur sur D2.

tu as surment raison... :sweat_smile:
mais comme je débute il faut bien que j'apprenne.

j'ai peut etre un type composant qui ressemble a un condensateur :
0.1 K 250 MKT
mais j'arrive pas à trouver le datasheet

Metallized Polyester Film Capacitor. MKT series
ça dois etre pour du 250v max non?

ça pourrais fonctionner pour du 0-5v ?

si tu n'as que ça pour faire tes essais ça ira très bien (la tension de service indiquée est une tension max)

pas grave, c'est une particularité des AVR (mais pas que) : si tu ne sais pas tu ne peux pas l'inventer

ça tombe bien [humour] elle est implémentée de façon matérielle, contrairement aux sauvegardes de registres que le compilateur effectue à notre place

Je crois qu'il s'agit de lire 12 boutons en lecture mono c'est à dire que l'on a une lecture fiable si on presse sur un seul bouton à la fois. Le cahier des charges ne le précise pas.
Il peut aussi s'agir d'une lecture mono sur 6 boutons et une lecture mono sur 6 autres boutons. Par exemple on peut appuyer sur un bouton câblé sur A0 et un autre bouton en même temps si il est câblé sur A1.

Dans le premier cas on peut tout mettre sur A0 et 2, dans le deuxième cas il faut effectivement utiliser A, A1 et 2.

Faire une lecture de plusieurs boutons en même temps est possible jusqu'à 6 boutons sur une seule broche analogique. Pas 12 en tout cas.

Il faut donc préciser si on peut appuyer sur plusieurs boutons à la fois. L'intérêt de mettre les 12 boutons sur la même broche est que l'on n'a qu'un seul potentiel à lire et que l'on n'a pas besoin d'une double analogRead().


La page http://arduino.dansetrad.fr/Boutons/accueil_Btn.php donne différents montages pour une lecture analogique (passer la souris sur le nom des montages.

Si on est marchand de diodes, le montage avec plein de diodes est une solution. Personnellement, je suis peu attiré par des montages avec un maximum de composants.

Quand on fait une lecture analogique de plusieurs boutons, l'état de repos (aucun bouton appuyé) envoie sur la broche en général 0V ou 5V (avec la Uno qui semble être utilisée).
Quand on appui sur un bouton, la tension d'entrée va changer.
Si on se réfère à la datasheet de la Uno:


On voit qu'une entrée NUMERIQUE comme la broche 2 voit un état bas entre 0V et 0,3Vcc soit entre 0V et 1,5V. De même un état haut est entre 3,5V et 5V.
Si on a 12 boutons et que l'on veut utiliser une interruption sur la broche 2, on peut relier le broche 2 et la broche A0, l'une donne les interruptions, l'autre la valeur de la conversion.

Parmi les montages que je choisirais, j'en retiens deux.

Premier montage

Diviseur de tension à résistances séries. Je l'ai testé avec 63 boutons et n utilisant des résistances carbone à 10%.
Si aucun bouton n'est appuyé, on lit 0V. Si on appuie sur un bouton, avec 63 boutons, la tension va de 0,08V à 5V. Comme nous voulons aller de 3,5V à 5V, il suffit d'ignorer les boutons du bas.

On met par exemple 12 boutons avec les 12 résistances de 1kΩ côté 5V et en bas, au lieu de mettre plein de résistances de 1kΩ, on y met une résistance d'au moins 28kΩ, par exemple une 33kΩ.

Ainsi, on n'a que 12 résistances de 1kΩ, une de 100kΩ et une de 33kkΩ. Adieu les diodes

Si besoin je peux fournir le schéma. Pour la lecture, comme tu utilises une table, on peut faire pareil ou utiliser la méthode décrite dans la page. A et la broche 2 sont connectées

C'est ce montage qui donne à mon avis le meilleur résultat. On peut aussi diminuer les valeurs des résistances même par 10 pour être moins sensible au bruit (avec 100Ω et 3,3kΩ, on a un courant d'environ 1,5mA).

Deuxième montage

Si on est radin, et que 14 résistances c'est trop, on peut utiliser un clavier matriciel. Cela fonctionne super bien avec une matrice de 20 boutons, mais les essais d'aujourd'hui me disent que je pourrais même passer à à plus du double. Mais ici ce n'est pas utile.

Il faut alors clavier 4x3. J'utilise dans l page la référence de tension de 1,1V, par conséquent:
− si aucun bouton n'est appuyé, on a du 5V. Si on a un bouton appuyé, on a forcément en dessous de 1,1V. Ce qui permet les interruptions en reliant A0 et 2.

On a alors 6 résistances et 0,0 diodes.