attachInterrupt dans une bibliothèque

Salut à tous,
j'aimerai savoir comment faire un attachInterrupt dans une bibliothèque, en sachant que le attachInterrupt ne prend comme argument qu'une fonction sans argument et ne retournant rien, le problème étant qu'une fonction créée dans une bibliothèque à forcément l'argument this ...
Merci de vos réponse !

Bonjour,

Il suffit que tu déclares ta fonction static.
Le problème est qu'une fonction statique ne peut pas accéder (directement) aux membres non static de la class.

Bonjour

Ton problème n'est pas lié aux bibliothèques mais aux classes.
Une classe n'est qu'une description d'objet.

Derrière, ton programme utilise une ou plusieurs instances de cette classe.

Par exemple, si on part d'une classe définissant l'objet "bouton poussoir", il est probable que le programme utilisera plusieurs objets appartenant à cette classe.

Là, on voit bien l'utilité du pointeur this passé implicitement en paramètre d'appel des diverses méthodes de la classe. Il permet à la méthode de savoir sur quelle instance de la classe elle est exécutée.

Imaginons que l'une d'elle soit void bouton::traiterAppui()

La tentation est grande de lui associer une interruption.
Sauf qu'avec seulement bouton::traiterAppui(), on ne sait pas quel objet bouton est associé à l'interruption.

Le principe est alors d'utiliser une variable globale (ou bien variable static de la classe, ce qui revient au même) de type pointeur vers un objet bouton, et avoir comme routine d'interruption :

void ISR()
{
  pointeur->traiterAppui();
}

Pour le code, ça donnerai cela ? :
.h

class Test
{
  public:
  void fonctionContenantAttachInterupt();
  private:
  void traiterAppui();
  static float pointeur;
  static void ISR();
};

.cpp

void Test::ISR()
{
  pointeur->traiterAppui();
}
void Test::fonctionContenantAttachInterrupt()
{
  ISR();
  attachInterupt(0, pointeur, RISING);
}

Presque (enfin non, pas du tout) :smiling_imp:

traiterAppui() est appelée depuis l'extérieur, donc à mettre dans la section public de la classe

attachInterrupt() doit prendre en paramètre une fonction void(), et non un pointeur vers un objet

le pointeur d'objet doit être initialisé à NULL et affecté, par exemple dans un constructeur

Donc plutôt un truc du style

.h

class test
{
  private :
    static test *pointeur;
    static void ISR0();

  public :
    test(); //Constructeur
    void traiterAppui();
    uint32_t nb_appuis;
};

.cpp

test * test::pointeur = NULL; //Init d'une static de classe

void test::ISR0()
{
  test::pointeur->traiterAppui();
}

test::test()
{
  test::pointeur = this;
  attachInterrupt(0, ISR0, RISING);
  nb_appuis=0;
}

void test::traiterAppui()
{
  nb_appuis++;
}

Mais là attention : cela ne marche que si on crée un seul objet pour cette classe.
Sinon c'est le dernier créé qui est associé à l'interruption.

Pour avoir plusieurs interruptions sur plusieurs objets, il faut autant de pointeurs initialisés correctement, mais le principe est le même.

Bon, après quelque jour de test, je n'y arrive toujours pas, je vais donc donner les parties de mon code concernant l'attachInterrupt

.h

#include "Arduino.h"
#include <Wire.h>
#include <I2Cdev.h>
#include "MPU6050_6Axis_MotionApps20.h"

class GY88
{
  public:

    GY88();
    void initialize();
    void compute();
    void dmpDataReady();
    
    //des variables

  private:

    volatile bool mpuInterrupt = false;
    static GY88* pointeur;
    static void ISR();
    // des variables

    
};

#endif

.cpp

#include "Arduino.h"
#include <I2Cdev.h>
#include <Wire.h>
#include "GY88.h"



GY88 * GY88::pointeur = NULL;

GY88::GY88()
{
}

void GY88::ISR()
{
  GY88::pointeur->dmpDataReady();
}

void GY88::dmpDataReady() {
    mpuInterrupt = true;

}

void GY88::initialize()
{
//du code ici

GY88::pointeur = this;

// du code ici

attachInterrupt(0, ISR, RISING);
// du code ici

}

void GY88::compute()
{
  //du code ici
}

Les erreurs :

Arduino : 1.6.8 (Windows 10), Carte : "Arduino/Genuino Uno"

In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:30:0,

                 from sketch\GY88.cpp:1:

GY88.h:44: error: expected unqualified-id before string constant

     static void ISR();

                 ^

GY88.h:44: error: expected unqualified-id before 'void'

     static void ISR();

                 ^

GY88.h:44: error: expected ')' before 'void'

GY88.cpp:14: error: expected unqualified-id before 'extern'

 void GY88::ISR()

            ^

GY88.cpp:14: error: expected unqualified-id before 'void'

 void GY88::ISR()

            ^

GY88.cpp:14: error: expected ')' before 'void'

sketch\GY88.cpp: In member function 'void GY88::initialize()':

GY88.cpp:63: error: expected primary-expression before 'extern'

         attachInterrupt(0, ISR(), RISING);

                            ^

GY88.cpp:63: error: expected primary-expression before 'void'

         attachInterrupt(0, ISR(), RISING);

                            ^

GY88.cpp:63: error: expected ';' before 'void'

exit status 1
expected unqualified-id before string constant

Ce rapport pourrait être plus détaillé avec
l'option "Afficher les résultats détaillés de la compilation"
activée dans Fichier -> Préférences.

Cela ne résoudra pas le problème général que tu rencontre mais tu peux le contourner.
On savait gérer les interruptions sur avr bien avant l'écriture d'attachinterupt().

Lecture de la datasheet, quelques valeurs à modifier dans les registres et utilisation de la macro ISR(vecteur) de l'avr-libc ATMEL et cela roule.
Dès fois il est préférable de ne pas utiliser des marteaux-pilons pour enfoncer des clous.

Il est admis par tous que dans une interuption il faut réaliser le minimum d'action pour que la perturbation soit la plus courte possible.
Ajouter une fonction qui avant d'utiliser la macro ISR va à chaque appel configurer les registres me parait être d'une efficacité très moyenne.

Les registres se configurent une seule fois et autant utiliser ISR directement.
Je me rappelle d'un conseil reçu jeune débutant : le mieux est l'ennemi du bien.

Merci de ta réponse !
Malheureusement, je ne pense vraiment pas avoir les compétences pour comprendre ce que tu dis :stuck_out_tongue: Je ne sais même pas qu'est la macro ISR, encore moins l'avrlibc ATMEL :confused:
Sauf si tu me guide (et je ne veux pas exploiter (trop) ton temps), je serais probablement pas en mesure le faire.
En attendant, j'ai trouvé une autre solution : découper ma fonction en deux : GY88.initialize1 et 2, et je fait mon attachInterrupt() dans mon programme, entre les deux fonctions.