2013-03-27 3 views
5

Ich schreibe eine einfache Bibliothek für einen Ultraschall-Abstandssensor und dachte, ich würde versuchen, mit Interrupts.Kann AttachInterrupt in einer Bibliothek nicht verwenden

Allerdings kann ich meine Funktionen in der attachCallback Methode nicht richtig einstellen.

Ich möchte HCSR04Interrupt::echoHigh() und HCSR04Interrupt::echoLow() aufgerufen werden, wenn der Pin hoch und niedrig geht.

Ich habe dies vergeblich gegoogelt. Die Ardiuno IDE sagt der folgende:

./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp: In member function 'void HCSR04Interrupt::getDistance()': 
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp:31: error: argument of type 'void (HCSR04Interrupt::)()' does not match 'void (*)()' 
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp: In member function 'void HCSR04Interrupt::echoHigh()': 
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp:47: error: argument of type 'void (HCSR04Interrupt::)()' does not match 'void (*)()' 

Hier ist mein Kopf:

#ifndef _HCSR04Interrupt_ 
#define _HCSR04Interrupt_ 

#include "Arduino.h" 

#define HCSR04_CM_FACTOR 58.0 
#define HCSR04_IN_FACTOR 148.0 
#define HCSR04_CM_MODE 0 
#define HCSR04_IN_MODE 1 

class HCSR04Interrupt { 
    public: 
    double distance; 

    HCSR04Interrupt(int trigger_pin, int echo_pin, void (*callback)()); 

    void setUnits(int units); 

    void getDistance(); 
    private: 
    int _trigger_pin; 
    int _echo_pin; 
    int _units; 
    unsigned long _micros_start; 
    void (*_callback)(); 

    void initialize(); 
    void echoHigh(); 
    void echoLow(); 
}; 

#endif 

Und meine Implementierung (nicht vollständig, da ich an den attachInterrupt Schritt cant get):

#include "Arduino.h" 
#include "HCSR04Interrupt.h" 

HCSR04Interrupt::HCSR04Interrupt(int trigger_pin, int echo_pin, void (*callback)()) { 
    _trigger_pin = trigger_pin; 
    _echo_pin = echo_pin; 
    _callback = callback; 

    initialize(); 
} 

void HCSR04Interrupt::setUnits(int units) { 
    _units = units; 
} 

void HCSR04Interrupt::initialize() { 
    pinMode(_trigger_pin, OUTPUT); 
    pinMode(_echo_pin, INPUT); 

    digitalWrite(_trigger_pin, LOW); 
} 

void HCSR04Interrupt::getDistance() { 
    //Listen for the RISING interrupt 
    attachInterrupt(_echo_pin - 2, echoHigh, RISING); 

    //The trigger pin should be pulled high, 
    digitalWrite(_trigger_pin, HIGH); 

    //for 10 us. 
    delayMicroseconds(20); 

    //Then reset it. 
    digitalWrite(_trigger_pin, LOW); 
} 

void HCSR04Interrupt::echoHigh() { 
    _micros_start = micros(); 

    detachInterrupt(_echo_pin - 2); 
    attachInterrupt(_echo_pin - 2, echoLow, FALLING); 
} 

void HCSR04Interrupt::echoLow() { 
    detachInterrupt(_echo_pin - 2); 

    unsigned long us = micros() - _micros_start; 

    distance = us; 

    (*_callback)(); 
} 

Antwort

2

Arduino Interrupt-Handler können nur Funktionen sein. Sie versuchen, Methode eines Objekts einen Interrupt-Handler zu machen. Daher beschwert sich der Compiler.

Um genauer zu sein, Objektmethoden sind wie Funktionen, aber es ist, als ob sie einen "versteckten" Parameter nehmen, der die Objektinstanz spezifiziert. Daher haben sie tatsächlich unterschiedliche Typensignaturen von einfachen Funktionen. Dies verbietet es, einen Methodenzeiger zu übergeben, wenn nach was eine Funktion sucht, ein einfacher Funktionszeiger ist.

Die Lösung besteht darin, Ihre echoHigh() und echoLow() aus der Klasse HCSR04Interrupt zu verschieben und ihnen einfache Funktionen zu machen.

5

So ist der Compiler (nicht die IDE) sagt Ihnen genau, was los ist:

argument of type 'void (HCSR04Interrupt::)()' does not match 'void (*)() 

So, während attachInterrupt() einen Funktionszeiger vom Typ nimmt void (*)(), Sie versuchen es einen nicht passieren statische Elementfunktion,, die Sie nicht können. Sie können versuchen, die Member-Funktion static und Gießen zu machen:

static void echoHigh(); 

// ... 

attachInterrupt(_echo_pin - 2, reinterpret_cast<void (*)()>(&echoHigh), RISING); 
+0

attachInterrupt hat Anforderungen, die die Funktion verweist er auf sein STATISCH. und das bewirkt dann, dass alle Mitgliedsfunktionen von attachInterrupt nach oben gerichtet sind, um statisch zu sein. Ich habe das erfolgreich gemacht. – mpflaga

0

ich, indem eine singleton Basisklasse um diese bekam, die die Hardware als Ganzes darstellt (was irgendwie Sinn in dieser Situation macht sowieso).

Alle Funktionszeiger können dann an die Unterkomponentenklasse übergeben und vom Singleton verarbeitet werden, dessen Mitgliedsvariablen und Methoden alle statisch sind.

Beispiel Header (ungetestet):

// Sub-component 
class LampButton { 
public: 
    LampButton(int pin, void(*pushHandler)()); 
} 

// Sub-component 
class LampLed { 
public: 
    LampLed(int pin); 
    void toggle(); 
} 

// Singleton represents the hardware in it's entirety 
class Lamp { 
public: 
    // Call this instead of a constructor 
    static void initialize(int buttonPin, int ledPin); 

    // Function implemented inline for clarity - don't do this 
    static void handleButtonPush() { 
     led.toggle(); 
    } 

private: 
    static LampButton button; 
    static LampLed led; 
} 
1

Wie ich auf diese Frage gestolpert und es hat eine akzeptierte Antwort nicht gehabt, ich schreibe was ich gefunden habe, die für mich gearbeitet:

Der Interrupt muss von einem globalen Wrapper aufgerufen werden. Dieser Wrapper muss eine handleInterupt-Funktion der Klasse aufrufen. Daher muss es die Klasse kennen. Dies kann durch Speichern in einer globalen Variablen erfolgen. Wenn mehrere Instanzen der Klasse verwendet werden sollen, müssen mehrere derartige globale Variablen verwendet werden.Aber wie die Interrupt-Pins nur wenige sind, können Sie eine globale Variable und Funktion für jeden Stift schreiben:

MyClass theInstance_pin3 = NULL; 
MyClass theInstance_pin7 = NULL; 

// Somewhere, fill in an initialized copy of MyClass, 
// and set theInstance_pin3 or theInstance_pin7 to it 

void ISR_3() 
{ 
    if (theInstance_pin3) 
     theInstance_pin3->handleInterrupt(); 
} 
void ISR_7() 
{ 
    if (theInstance_pin7) 
     theInstance_pin7->handleInterrupt(); 
} 

als Referenz siehe: http://forum.arduino.cc/index.php?topic=41713.0 oder http://forum.arduino.cc/index.php?topic=160101.0

Verwandte Themen