[Arduino Uno] Interruption sur changement d'état d'une broche ne fonctionne pas

Bonjour,

J'ai réalisé un montage avec 1 LCD, 1 bouton poussoir et un encoder rotatif relié a des broches de mon arduino uno, pour que des changements d'état qui interviendrait dessus (suite à des action sur l'encoder et le BP) déclenche des interruptions. Je sais que c'est faisable c'est écrit dans la doc. Je pense avoir tout bien configuré, mais ça ne fonctionne pas. A la place d'un changement de texte sur l'ecran lcd que j'ai relié, les action font scintiller le LCD sans changer le texte.

A noter que seul le texte "boucle principale" s'affiche correctement.

Voici mon code :

/*
  LiquidCrystal Library - display() and noDisplay()
 
 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the 
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.
 
 This sketch prints "Hello World!" to the LCD and uses the 
 display() and noDisplay() functions to turn on and off
 the display.
 
 The circuit:
 * LCD RS pin to digital pin 12 > 2
 * LCD Enable pin to digital pin 11 > 7
 * LCD D4 pin to digital pin 5 > 6
 * LCD D5 pin to digital pin 4 > 5
 * LCD D6 pin to digital pin 3 > 4
 * LCD D7 pin to digital pin 2 >3
 * LCD R/W pin to ground
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 
 Library originally added 18 Apr 2008
 by David A. Mellis
 library modified 5 Jul 2009
 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009
 by Tom Igoe 
 modified 22 Nov 2010
 by Tom Igoe

 This example code is in the public domain.

 http://arduino.cc/en/Tutorial/LiquidCrystalDisplay

 */

// include des lib
#include <avr/io.h>
#include <avr/interrupt.h>
#include <LiquidCrystal.h>

// init lcd
LiquidCrystal lcd(2, 7, 6, 5, 4, 3);

void setup() {
  lcd.begin(16, 2);
  config_encoder();
  print_lcd("init du prog");
}

void loop() {

}

//configuration des int sur les changements d'état des encodeurs + BP.
void config_encoder(){
    DDRC &= ~((1 << DDC0) | (1 << DDC3) | (1 << DDC5)); // C

    PORTC |= ((1 << PORTC0) | (1 << PORTC3) | (1 << PORTC5)); // Pull-up activé
    PCICR |= (1 << PCIE1);     // parametrage int.
    PCMSK1 |= ((1 << PCINT8) | (1 << PCINT11) | (1 << PCINT13));   
    sei();                     // activation des int.
}
//fonction affichage LCD
void print_lcd(String a){
  lcd.setCursor(0,1);
  lcd.print(a);
}

//declaration des fonction des int.
ISR (PCINT8_vect){
  print_lcd("interrupt BP");
}
ISR (PCINT11_vect){
  print_lcd("interrupt Enc. CHA");  
}
ISR (PCINT13_vect){
  print_lcd("interrupt Enc. CHB");
}

Toute aide ou suggestion pour résoudre mon problème est la bienvenue.

D'avance merci

Olivier

Il y a un delay(500) dans la fonction print_lcd appelée par l'interruption.
Les interruptions ne gèrent pas les delay :

attachInterrupt() - Arduino Reference
Inside the attached function, delay() won't work and the value returned by millis() will not increment.

Non ce n'est pas ça (je viens de vérifier), car je n'utilise pas le attacheInterrupt d'arduino (cf : mon code). J'utilise des interrruptions qui ne sont pas gérées par le framework arduino, mais qui sont gérés directement en C...

Edit : j'ai supprimé les delay() pour que ca ne prête pas a confusion.

Bon j'ai eu une idée cette nuit, je me suis dit que j'allais stocker le texte à afficher dans une variable globale, et modifier cette variable dans les routines d'interruption, mais ca ne marche pas ...On voit qu'il se passe quelque chose quand je tourne l'encoder ou que j'appuie sur le BP (l'ecran scintille et si j'écris sur le port série ca ralentie la transmission...).

Tu utilises les PCINTx.
Dans ce cas il faut rechercher qu'elle pin du port (B, C, D) a généré l'interruption.
De plus il faut sauvegarder le registre SREG à l'entrée dans l'interruption et le rétablir à la sortie de l'interruption.

Je m'étais fais un pense bête que j'avais mis à la disposition du forum :
C'est dans la partie Tuto (enfoui au fond)
http://forum.arduino.cc/index.php?topic=100906.0

Si cela peut -aider.

Je potasse ça ce soir ça m'a l'air bien complet. Je me suis inspiré du datasheet pour mon code mais j'ai surement mal comprendre certains points

Olf:

//declaration des fonction des int.

ISR (PCINT8_vect){}
ISR (PCINT11_vect){}
ISR (PCINT13_vect){}

Ces vecteurs d'interruption n'existent pas, tu as d'ailleurs dû avoir un avertissement à la compilation pour te prévenir qu'il y avait un problème de ce côté.

Celle que tu doit utiliser est PCINT1_vect, et elle est commune à tes 3 broches, c'est donc à toi de déterminer à l'intérieur de l'interruption (en fonction de leur état actuel et de l'état précédent) quelle est celle(s) qui a changé d'état.

Oui effectivement j'ai corrigé tout ça grâce au guide proposé ci dessus.
J'ai quasiment tout bon, sauf que dans un sens, tout fonctionne nickel, par contre dans l'autre sens (sens A), j'ai des résultats bizarres, en sortie quand je tourne toujours dans le sens A, j'ai des changements d'état bizarres qui correspondent à des changements d'état du sens B. J'ai vérifié en envoyant les données sur le port série, et c'est bien confirmé.

J'utilise ca comme encodeur : http://www.selectronic.fr/encodeur-numerique-bi-phase-24-impulsions-t.html

Voici mon code commenté :

/*
  LiquidCrystal Library - display() and noDisplay()
 
 The circuit:
 * LCD RS pin to digital pin 12 > 2
 * LCD Enable pin to digital pin 11 > 7
 * LCD D4 pin to digital pin 5 > 6
 * LCD D5 pin to digital pin 4 > 5
 * LCD D6 pin to digital pin 3 > 4
 * LCD D7 pin to digital pin 2 >3
 * LCD R/W pin to ground
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

 */

// include des lib
#include <avr/io.h>
#include <avr/interrupt.h>
#include <LiquidCrystal.h>

// init lcd
LiquidCrystal lcd(2, 7, 6, 5, 4, 3);
boolean chA_old = 0;
boolean chB_old = 0;
boolean chA = 0;
boolean chB = 0;
String texte ="";
void setup() {
  lcd.begin(20, 4);
  config_encoder();
  Serial.begin(9600);
}

void loop() {
}

//configuration des int sur les changements d'état des encodeurs + BP.
void config_encoder(){
  DDRC &= ~(/*(1 << DDC0) |*/ (1 << DDC3) | (1 << DDC5)); // C
  PORTC |= (/*(1 << PORTC0) |*/ (1 << PORTC3) | (1 << PORTC5)); // Pull-up activé
  PCICR |= (1 << PCIE1);     // parametrage int.
  PCMSK1 |= ((1 << PCINT8) | (1 << PCINT11) | (1 << PCINT13));   
  sei();                     // activation des int.
}
//fonction affichage LCD du sens de rota°
void print_channel_output(String texte){
  lcd.setCursor(1,3);
  lcd.print(texte);
}
//fonction affichage LCD des états AV/AP des canaux
void print_channel_output(boolean A, boolean B, boolean A_old, boolean B_old){
  String SA = "";
  String SB = "";
  String SAO = "";
  String SBO = "";
  //conversion des bool en string
  SA = A ? "1" : "0";
  SB = B ? "1" : "0";
  SAO = A_old ? "1" : "0";
  SBO = B_old ? "1" : "0";
  Serial.println(SB + SA);
  lcd.setCursor(1,0);
  lcd.print("CH.B': " + SBO + " CH.A': " + (String) SAO );
  lcd.setCursor(1,1);
  lcd.print("CH.B : " + SB + " CH.A : " + SA );
}

//declaration des fonction des int.
ISR (PCINT1_vect){
  uint8_t SaveSREG = SREG;
  cli();
  chA = (PINC & (1 << PINC3));
  chB = (PINC & (1 << PINC5)); 
  print_channel_output(chA, chB, chA_old, chB_old);
  if(( ~chB_old && ~chA_old && ~chB &&  chA) ||
    (  ~chB_old &&  chA_old &&  chB &&  chA) ||
    (   chB_old &&  chA_old &&  chB && ~chA) ||
    (   chB_old && ~chA_old && ~chB && ~chA))
  {
    texte = "sens A";
  }
  if(( ~chB && ~chA && ~chB_old &&  chA_old) ||
    (  ~chB &&  chA &&  chB_old &&  chA_old) ||
    (   chB &&  chA &&  chB_old && ~chA_old) ||
    (   chB && ~chA && ~chB_old && ~chA_old))
  {
    texte = "Sens B";
  }
  //stocakge de l'etat des canaux pour la prochaine interruption
  chA_old = chA;
  chB_old = chB; 
  //afficahge sens de rotation  
  lcd.setCursor(0,3);
  lcd.print(texte);

  SREG = SaveSREG; 
}

j'ai beau checker et re-checker, je vois pas d'où vient le problème. Donc si y'en a qui ont un avis sur le problème, je suis preneur.

Olivier

Jésus Marie Joseph ! :slight_smile:

Dis-moi, tu n'aurais pas encore une fois un peu ignoré les messages d'avertissement que t'envoie le compilateur par hasard ?

Déjà, l'opérateur « ~ » sert à faire la négation de tous le bits d'une variable un par un (8 bits dans ton cas). Ce que tu veux c'est faire un « non logique » sur la variable elle-même dans son ensemble, donc utilise « ! ». Ce qui fait que ~chB_old devient !chB_old etc.

La bonne blague, je viens de comprendre pourquoi je ne vois pas les messages d'avertissement dont tu me parlais. Par défaut l'installation décoche la case qui dit de les afficher.

Maintenant c'est bon je les vois. j'ai fait les corrections. Il y a du mieux sur le sens qui posait problème, mais j'ai toujours des "sauts" en arrière, ils sont un peu moins répétés. Sur l'autre zero problème. C'es très curieux j'ai le saut en arrière qui arrive de facon irrégulière, j'arrive pas a trouver pourquoi