Tester une entrée à tous moments

Bonsoir,

Voilà, je bloque depuis quelques heures sur un gros problème... J'ai programmé un bouton poussoir pour qu'il fasse une fonction switch.
Mon projet étant un séquenceur midi (5 séquences différentes et indépendantes à activer ou désactiver, contenant chacune 16 notes qui seront activées ou désactivées aussi. Au total, 5 switches pour lancer les séquences, et 16 switches pour gérer les 16 notes d'une des cinq séquences. Il faudra compter aussi un bouton start/stop.)
Pour ça, je ne vois pas d'autre solution que lire l'état de l'entrée du bouton poussoir à tous moments du programme. Mais comment faire ? J'avais cru comprendre avec la fonction millis mais ce n'est pas ça.

Voilà mon programme : (l'entrée qui doit être lue étant "BP1reading", "state" est la variable on/off)
Code du switch venant de là : http://www.arduino.cc/en/Tutorial/Switch

void loop ()

{

  BP1reading = digitalRead (BP1); // Lecture BP marche

  
  
  // switch and debounce
   if (BP1reading == HIGH && BP1previous == LOW && millis() - time > debounce) { 
    if (state == HIGH)
      state = LOW;
    else
      state = HIGH;

    time = millis();    
  }
  
  // Séquence
  
     while (state == LOW) {

// step 1
sensorValue = analogRead(sensorPin);
  digitalWrite (L2, LOW);
  digitalWrite (L5, HIGH);
  MIDImessage(noteON, 50, 115);
  delay(sensorValue);
  
//step 2
sensorValue = analogRead(sensorPin);
  digitalWrite (L2, HIGH);
  digitalWrite (L3, LOW);
  MIDImessage(noteON, 52, 115);
  delay(sensorValue);
  
//step 3
sensorValue = analogRead(sensorPin);
  digitalWrite (L3, HIGH);
  digitalWrite (L4, LOW);
  MIDImessage(noteON, 54, 115);
  delay(sensorValue);
  
//step 4
  sensorValue = analogRead(sensorPin);
  digitalWrite (L4, HIGH);
  digitalWrite (L5, LOW);
  MIDImessage(noteON, 56, 115);
  delay(sensorValue);  
}
BP1previous = BP1reading;
}
 
 void MIDImessage(int command, int MIDInote, int MIDIvelocity) {
  Serial.write(command);//send note on or note off command 
  Serial.write(MIDInote);//send pitch data
  Serial.write(MIDIvelocity);//send velocity data
}

Quelqu'un pour me sauver ? :grin:

Utilise une interruption :

http://arduino.cc/en/Reference/AttachInterrupt

Merci
Je ne connaissais pas cette fonction, mais d'après ce que je viens de lire, il n'y a qu'un nombre spécifique d'entrées pour ça. Or dans le cadre de mon projet, j'aurai besoin de 5 BP différents pour interrompre 5 séquences individuellement.

Tu fais que chaque BP actionne l'interruption sur la même pin et en même temps change l'état d'une autre pin.... et hop XD

sinon si tu ne veux pas utiliser d'interruptions, tu utilise une machine à état et un sketch qui boucle en permanence, avec une lecture des boutons au début de la boucle.

Bonjour,

Un truc bien sympa dans ce genre de cas, les interruptions de port :wink:
http://www.arduino.cc/playground/Main/PcInt

Et comme j'avais du temps à perdre je joint le .h prés à être utilisé :wink:
(oui c'est un bête copier coller :P)
(pour l'utiliser il suffit de le mettre dans le même dossier que le sketch)

Code d'exemple :

#include <Arduino.h>
#include "AnyPinInterrupt.h"

volatile long ticktocks = 0;
long i = 0;

void tick(void) {
   ticktocks++;
}

void tock(void) {
   ticktocks--;
}

void setup()
{
   Serial.begin(9600);
   pinMode(4, INPUT);
   pinMode(5, INPUT);
   delay(3000);
   PCattachInterrupt(4, tick, CHANGE);
   PCattachInterrupt(5, tock, CHANGE);
}

void loop() {
   i++;
   delay(1000);
   Serial.print(i, DEC);
   Serial.print(" ");
   Serial.println(ticktocks);
   if (i > 256) {
     PCdetachInterrupt(4);
     PCdetachInterrupt(5);
   }
}

AnyPinInterrupt.h (3.44 KB)

@ Jean-Francois: J'ai pas trop compris ce que tu veux dire...
@ Bricofoy: C'est de ça dont tu parles ? Programming Finite State Machines
J'ai l'impression que ça devient un peu compliqué, non ? :grin:

@ skywood: En fait en ayant poussé la réflexion un peu plus loin, comme c'est un séquenceur et que les 16 notes seront activées et désactivées avec un switch pour chaque... Ca me fera beaucoup de boutons d'interruption !
Ta solution est peut être la bonne, seulement va falloir que je comprenne un peu plus...

Si j'ai bien compris, la bibliothèque AnyPinInterrupt permet de transformer n'importe quelle pin en une entrée "interrupt" ? Et c'est quoi cette bibliothèque pins_arduino.h ? Je n'ai pas trop compris le code d'exemple non plus... Si tu pouvais m'expliquer comment faire quoi, parce-que je me perds un peu avec tous ces morceaux de code par-ci par là :grin: J'ai compris qu'il fallait inclure la bibliothèque mais le reste...

Merci à vous :wink:

Sinon j'ai pensé à autre-chose aujourd'hui, c'est d'utiliser une deuxième carte Arduino qui fera exclusivement des lectures d'entrée en boucle, et qui les communiquera à la carte du programme. Ca peut bien marcher et permettre d'alléger le code, non ?

kevo:
@ Bricofoy: C'est de ça dont tu parles ? Programming Finite State Machines
J'ai l'impression que ça devient un peu compliqué, non ? :grin:

oui, c'est bien ça. Mais la complexité dépend de ce que tu va faire dans ton programme, il n'y a pas forcément une multitude d'état avec des conditions multiples pour passer de l'un à l'autre.

Sinon j'ai pensé à autre-chose aujourd'hui, c'est d'utiliser une deuxième carte Arduino qui fera exclusivement des lectures d'entrée en boucle, et qui les communiquera à la carte du programme. Ca peut bien marcher et permettre d'alléger le code, non ?

oui, mais à ce moment là, il te faudra encore utiliser soit un principe de machine à états soit des interruptions pour pouvoir lire ce que ton arduino qui s'occupe des boutons aura à raconter au second... je ne suis pas certain que ça simplifie, au final :slight_smile:

Pour ce genre de cas, j'utilise les PCINT, c'est très pratique. Il suffit de déclarer dans les registres les pins concernées, et à chaque fois que l'une de ces pins va changer d'état, une interruption sera déclenchée. Tu crées la routine d'interruption concernée (ISR(PCINT_vect){...}) dans laquelle tu viens lire toutes tes entrées, et tu regardes celles qui ont changé. Je fais ça pour les claviers matriciels, on n'a pas besoin de scanner les touches, puisque ça se fait par interruption.

On rentre un peu dans le hard, mais je t'assure que ça vaut le coup.

ouais, je ne connaissait pas ce truc, mais je crois que moi aussi je vais m'y mettre, ça simplifiera mes machines à état :slight_smile:

http://arduino.cc/forum/index.php/topic,100906.0.html

bricofoy:

kevo:
@ Bricofoy: C'est de ça dont tu parles ? Programming Finite State Machines
J'ai l'impression que ça devient un peu compliqué, non ? :grin:

oui, c'est bien ça. Mais la complexité dépend de ce que tu va faire dans ton programme, il n'y a pas forcément une multitude d'état avec des conditions multiples pour passer de l'un à l'autre.

Sinon j'ai pensé à autre-chose aujourd'hui, c'est d'utiliser une deuxième carte Arduino qui fera exclusivement des lectures d'entrée en boucle, et qui les communiquera à la carte du programme. Ca peut bien marcher et permettre d'alléger le code, non ?

oui, mais à ce moment là, il te faudra encore utiliser soit un principe de machine à états soit des interruptions pour pouvoir lire ce que ton arduino qui s'occupe des boutons aura à raconter au second... je ne suis pas certain que ça simplifie, au final :slight_smile:

Donc il est impossible que la 1ère carte puisse quand elle en a besoin aller chercher l'état d'une variable qui est lue et stockée par la 2ème carte ?

Ca me fait peur ce truc d'interruptions, de pointeurs.. Ca m'a l'air très barbare :grin: Mais bon, j'ai bien peur que va falloir y passer alors, je vais tenter de lire le tuto !

Super_Cinci, tu parles de la même chose que les autres en fait ?

kevo:
Si j'ai bien compris, la bibliothèque AnyPinInterrupt permet de transformer n'importe quelle pin en une entrée "interrupt" ?

Oui c'est ça, en gros c'est comme si tu avait une "vrai" interruption attachInterrupt() mais sur n'importe quelles broches de ton choix.

kevo:
Et c'est quoi cette bibliothèque pins_arduino.h ?

C'est pas une librairie :wink:
C'est un fichier de base du "core" arduino qui contient les correspondances n° de pin <-> registre / bitmask bas niveau.

kevo:
Je n'ai pas trop compris le code d'exemple non plus... Si tu pouvais m'expliquer comment faire quoi, parce-que je me perds un peu avec tous ces morceaux de code par-ci par là :grin: J'ai compris qu'il fallait inclure la bibliothèque mais le reste...

C'est exactement pareil qu'avec attachInterrupt(), tu rajoute juste "PC" devant le nom de la fonction :wink:
Et au lieu d'avoir un numéro d'interruption en 1er argument tu donne directement le numéro de la broche.

kevo:
Sinon j'ai pensé à autre-chose aujourd'hui, c'est d'utiliser une deuxième carte Arduino qui fera exclusivement des lectures d'entrée en boucle, et qui les communiquera à la carte du programme. Ca peut bien marcher et permettre d'alléger le code, non ?

Ça n'aurait aucun intérêt, tu devras quand même gérer la réception des données sur l'autre arduino.
En gros tu déporte le problème sans le résoudre :wink:

Ok, bref c'est compliqué tout ça :grin: Je vais voir ta solution en détails alors, merci pour les précisions :wink:

kevo:
Super_Cinci, tu parles de la même chose que les autres en fait ?

Oui, mais au lieu de passer par le core arduino qui ralentit énormément les choses, je passe en direct sur les registres, on y gagne un temps énorme...

Ca pourrait être grandement utile alors si ça permet d'alléger le code, parce-que je pense qu'une fois que le code de base sera fini il sera bien lourd :astonished:

Sinon j'ai essayé ça aussi : http://arduino.cc/en/Tutorial/ButtonStateChange
Mais ça fonctionne pas pendant que j'ai une boucle qui tourne.

Je viens de relire ce topic depuis le début. Et franchement je comprends rien.
Au début, il y avait un bouton puis ensuite cinq un peu plus loin tu parles de seize.
Au début tu parles d'une séquence puis ensuite cinq.
Enfin de compte, si tu décrivais clairement le besoin et ses contraintes on pourrait être largement plus efficaces.

Ben c'est à dire que à la base je voulais juste savoir comment ça pouvait fonctionner pour un seul bouton pour pas trop compliquer les choses, je fais ça pas à pas.

C'est seulement quand on m'a proposé la solution avec le pin interrupt que j'ai du préciser que j'en aurais besoin de plusieurs, parce-que j'ignorais que ça ne pouvait fonctionner que avec 1 pin sur la UNO. Logique quoi, je m'attendais pas à ça...

Désolé si ça embrouille un petit peu mais je voulais pas exposer un problème impossible dès le début. Si je trouve une solution pour un seul bouton poussoir je serai déjà bien content et je me débrouillerai pour le faire avec plusieurs :wink:
J'ai édité mon premier post pour que ça soit plus clair...

Tu as encore la solution du clavier matriciel. J'en ai codé un qui utilise les PCINT et est bien plus rapide et efficace que la librairie keyboard. Ca remplit un buffer tout seul, un peu à la manière de Serial. Le fonctionnement est totalement transparent tant qu'on n'appuie sur aucune touche, la moindre touche déclenche une PCINT

Il faut juste choisir précisément l'emplacement des connexions pour que les colonnes ou lignes se retrouvent sur la même interruption (ça mériterait un tuto, ça, non? car ce n'est pas avec la base arduino que l'on pourra s'en sortir), mais ça réduit le nombre de pins (pour un clavier de A x B boutons, on a besoin de A+B pins). L'exemple d'une cible de fléchette que j'ai mise sur un arduino MEGA2560 : la cible représente 64 contacts en matrice de 8 x 8, soit l'utilisation de 16 pins.

Merci Super_cinci, mais comme tu dis pour un débutant c'est peut-être pas évident de se lancer là dedans ^^. Je préfère faire simple pour commencer !

J'ai eu un peu de temps pour évoluer dans mon projet, j'ai finalement compris tout le système des interruptions et j'ai eu une idée, qui est en fait celle que Jean-François m'avait proposée et que je n'avais pas compris.

L'idée est de relier chaque bouton poussoir en parallèle à la pin interrupt. J'ai fait un test avec un bouton poussoir qui actionne l'interrupt et en même temps un switch. Seulement il est fort instable, ne répond qu'une fois sur 3... Si vous pouviez jeter un oeil sur mon programme et voir si je n'ai rien oublié. Pour l'anti-rebond, j'ai mis un condensateur sur le bouton poussoir pour alléger un peu le code pour commencer.

J'explique le programme en quelques mots : Il y a une boucle qui fait clignoter une led (L2) tant que l'état du switch est sur on. Le switch a aussi une led témoin pour son état (LED).

int BP1 = 3; // BP switch
int LED = 7; // LED état on/off
int L2 = 8;  // LED loop

// Switch
int state = HIGH;      
int reading;           
int previous = LOW;    



void setup()
{
  pinMode(BP1, INPUT);
  pinMode(LED, OUTPUT);
  pinMode (L2, OUTPUT);
  
  attachInterrupt (0, actionBP, LOW); // Interrupt
}

void loop()
{
  
  
  while (state == LOW) { // Clignottement de L2 quand état = ON
    digitalWrite (L2, LOW);
    delay(500);
    digitalWrite (L2, HIGH);
    delay(500);
  }
}


void actionBP () // Action interrupt
{
  reading = digitalRead(BP1); // Lecture BP1

  
  if (reading == HIGH && previous == LOW) { // Switch BP1
    if (state == HIGH)
      state = LOW;
    else
      state = HIGH; 
  }

  digitalWrite(LED, state); // LED d'état ON/OFF

  previous = reading; // Switch BP1
}