Bonsoir
Bon j'ai acheté un MCP23017 que je connecte en i2C sur ESP32.
La bibliothèque que j'utilise est Adafruit MCP23017 Arduino library.
Je cherche à savoir quel bouton a été appuyé lorsqu'une interruption est déclenchée. Voici le code:
//#include <Wire.h>
#include <Adafruit_MCP23X17.h>
bool buttonWasPressed = 0;
uint8_t pin;
Adafruit_MCP23X17 mcp;
void IRAM_ATTR handleInterrupt() {
buttonWasPressed = 1;
pin = mcp.getLastInterruptPin();
}
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("start");
// Initialiser le MCP23017
if (!mcp.begin_I2C()) { //initialise mcp i2c
Serial.println("Error.");
while (1)
;
}
// Configurer les broches connectées aux boutons comme entrées
mcp.pinMode(0, INPUT);
mcp.pinMode(1, INPUT);
// Configurer l'interruption pour les broches d'entrée
mcp.setupInterrupts(true, false, LOW);
mcp.readGPIOAB(); // Réinitialiser l'interruption
// Attacher l'interruption à la fonction handleInterrupt()
attachInterrupt(digitalPinToInterrupt(mcp.getLastInterruptPin()), handleInterrupt, CHANGE);
}
void loop() {
if (buttonWasPressed = 1) {
buttonWasPressed = 0;
Serial.println("appui détecté");
// Détecter quel bouton a été pressé
if (pin == 0) {
Serial.println("Bouton 0 pressé !");
} else if (pin == 1) {
Serial.println("Bouton 1 pressé !");
}
// Réinitialiser l'interruption
mcp.digitalRead(pin);
}
}
J'obtiens un message d'erreur, j'ai déjà eu un GURU MEDITATION parce que je demandais à la fonction IRAM_ATTR de faire beaucoup trop de choses, mais cette fois je ne lui demande quand-même pas la lune:
attachInterrupt(digitalPinToInterrupt(mcp.getLastInterruptPin()), handleInterrupt, CHANGE);
Or, l'interruption, en l'occurence, doît être une pin de l'Arduino où est raccordée la pin INTA du MCP23017 et c'est dans la fonction handleInterrupt que tu peux faire mcp.getLastInterruptPin()
Dans l'exemple de la bibliothèque mcp23xxx_interrupt.ino c'est INT_PIN qui doit déclencher l'interruption: attachInterrupt(digitalPinToInterrupt(INT_PIN), handleInterrupt, CHANGE);
#include <Adafruit_MCP23X17.h>
bool buttonWasPressed = false;
volatile uint8_t pin;
byte interrPin = 19;
Adafruit_MCP23X17 mcp;
// la fonction d'interruption
void IRAM_ATTR handleInterrupt() {
pin = mcp.getLastInterruptPin(); //récupère le numéro du bouton qui a provoqué l'interruption
buttonWasPressed = true;
}
void setup() {
Serial.begin(115200);
pinMode(19, INPUT);
// Initialiser le MCP23017
if (!mcp.begin_I2C()) { //initialise mcp i2c
Serial.println("Error.");
while (1)
;
}
// Configurer les broches connectées aux boutons comme entrées
mcp.pinMode(0, INPUT);
mcp.pinMode(1, INPUT);
// Configurer l'interruption pour les broches d'entrée
mcp.setupInterrupts(true, false, LOW); // là je ne comprends pas bien ce LOW si quelqu'un peut expliquer en deux mots...
mcp.readGPIOAB(); // Réinitialiser l'interruption
// Attacher l'interruption à la fonction handleInterrupt()
attachInterrupt(digitalPinToInterrupt(interrPin), handleInterrupt, RISING);
}
void loop() {
if (buttonWasPressed) {
Serial.println(pin); // affiche quel bouton a été pressé
delay(250);
// Réinitialiser l'interruption
mcp.readGPIOAB();
buttonWasPressed = false;
}
}
Qu'est ce que je ne comprends pas ? Ca ne fonctionne toujours pas...
Bon entre temps j'ai demandé à chatGPT pour voir, il ajoute des erreurs XD
typiquement (mais ça peut aussi être l'inverse ... ) , l'état actif des sorties d'interruption du mcp23017 est "LOW"
donc , si je ne m'abuse , dans ton attachInterrupt(...) , la condition de niveau doit être "LOW" ou éventuellement "FALLING"
// Configurer les interruption pour le MCP23017
// Leinterruptions A et B sont regroupées sur la pin INTA
// false = INTA et INTB ont une résistance de PULLUP
// low = signal actif à LOW donc FALLING
mcp.setupInterrupts(true, false, LOW); // là je ne comprends pas bien ce LOW si quelqu'un peut expliquer en deux mots...
donc l'interruption de l'Arduino doit s'initialiser ainsi: attachInterrupt(digitalPinToInterrupt(interrPin), handleInterrupt, FALLING);
La réinitialisation des interruptions ainsi: mcp.clearInterrupts(); // clear
Tu n'as pas initialisé l'interruption des pin 0 et 1 du MCP:
◆ getLastInterruptPin()
uint8_t Adafruit_MCP23XXX::getLastInterruptPin ( )
Gets the pin that caused the latest interrupt, from INTF, without clearing any interrupt flags.
la lecture des flags ne les efface pas , il faut sans doute faire une lecture du PORTA en fin de routine ...
Je dois bien admettre que je n'y comprends plus rien, là.
Les interruptions c'est quand-même un monde à part...
Le plus bizarre pour moi c'est de ne pas trouver un bête code d'exemple qui fonctionne avec quelques boutons.
Certainement car ce n'est en général pas une bonne idée de traiter les boutons par une interruption.
Mais ça peut être un exercice intellectuel intéressant..
Si je veux pouvoir exécuter du code avec un peu d'algorithmique (jeu de lumières avec un ruban led) et qu'un compteur se stoppe net quand j'appuie sur un bouton, je pense que je n'ai pas vraiment le choix. Je peux me tromper. dans tous les cas, même si j'essaie autrement, il faut que je surveille chacun des boutons en boucle pour voir qui est appuyé... Je trouve ça tellement lourd...
C'est vrai, semble-t-il, mais honnêtement je ne comprends pas pourquoi. Les interruptions ne sont pas utilisables avec de la mécanique? Juste avec du hall ou de l'optique? C'est à cause des rebonds?
Je vois bien que je m'acharne à faire un truc débile mais je ne comprends pas pourquoi c'est si stupide
Oui, mais, une fois que tu maîtrises, c'est super à utiliser.
Des boutons gérés par interruption, sont légion, c'est souvent "caché" dans une bibliothèque, par contre, dans ton cas, des boutons en interruption via un MCP23017, c'est vrai que je n'ai pas croisé souvent.
J'ai fait l'exercice sur un ESP32 (M5Stick) en faisant l'exemple de la bibliothèque Adafruit_MCP23X17.hmcp23xxx_interrupt.ino. Ca ne déclenche pas d'interruption au niveau de l'ESP, mais ça la signale, pour autant que tu aies relié la pin INTA du MCP à la pin que tu a désignée pour recevoir l'interruption (INT_PIN). Après ça, il te suffira de mettre un LOW sur l'entrée BUTTON_PIN de l'ESP pour voir dans le moniteur, à 9600:
Interrupt detected on pin: 1
Une fois que tu as maîtrisé ça, on fera marcher l'interruption sur l'ESP.
Le temps d'appui sur un bouton par un humain va être de l'ordre de la centaine de ms (voire de plusieurs centaines de ms). Ce n'est en général pas la peine de prendre en compte cet appui à la microseconde.
On a le temps de lire le bouton dans la boucle principale pour peu qu'elle dure moins de 100 ms (c'est pour ça que j'ai écrit en général).
Oui mais justement, c'est le but, d'être au millième. Même si ça semble un peu tiré par les cheveux, je veux vraiment tirer le meilleur de la machine. Je comprends ce que tu veux dire mais l'idée sur ce truc, c'est vraiment d'être au millième.
je construis un jeu de la taupe où c'est l'ESP32 qui jouera et affrontera un humain. Mais ça, c'est top secret...