2013-03-27 2 views
5

Я пишу простую библиотеку для ультразвукового датчика расстояния и думал, что попробую использовать прерывания.Не могу использовать attachInterrupt в библиотеке

Однако я не могу правильно установить свои функции в методе attachCallback.

Я хочу, чтобы HCSR04Interrupt::echoHigh() и HCSR04Interrupt::echoLow() вызывали, когда штырь идет соответственно высоким и низким.

Я искал это безрезультатно. Ardiuno IDE говорит следующее:

./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 (*)()' 

Вот мой заголовок:

#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 

И моя реализация (не завершена, так как я не могу пройти шаг attachInterrupt):

#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)(); 
} 

ответ

2

Arduino Обработчики прерываний могут быть только функциями. Вы пытаетесь сделать метод объекта обработчиком прерываний. Поэтому компилятор жалуется.

Чтобы быть более точным, методы объекта подобны функциям, но они как будто принимают «скрытый» параметр, задающий экземпляр объекта. Поэтому на самом деле они имеют разные типы подписей от простых функций. Это запрещает передавать указатель метода, когда то, что ищет функция, является указателем простой функции.

Решение должно переместить echoHigh() и echoLow() из класса HCSR04Interrupt и сделать их простыми функциями.

5

Так компилятор (не IDE) говорит вам именно то, что случилось:

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

Таким образом, в то время как attachInterrupt() принимает указатель на функцию типа void (*)(), вы пытаетесь передать его не- статическая функция-член,, которую вы не можете. Вы можете попробовать сделать функцию-член static и литье:

static void echoHigh(); 

// ... 

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

attachInterrupt имеет требования, что функция на которую он указывает, что STATIC. и это приводит к тому, что все функции-члены вверх от attachInterrupt становятся статическими. Я сделал это успешно. – mpflaga

0

Я получил вокруг этого, делая singleton базовый класс, который представляет собой аппаратное обеспечение в целом (что своего рода имеет смысл в этой ситуации так или иначе).

Любые указатели функций могут быть переданы классу подкомпонентов и обработаны одноточечным элементом, чьи членные переменные и методы являются статическими.

Пример заголовков (непроверенные):

// 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

Как я наткнулся на этот вопрос, и он не имел принятый ответ, я пишу то, что я нашел, что работал для меня:

Прерывание должен быть вызван глобальной оболочкой. Эта оболочка должна вызвать функцию класса handleInterupt. Поэтому он должен знать класс. Это можно сделать, сохранив его в глобальной переменной. Если необходимо использовать несколько экземпляров класса, необходимо использовать несколько таких глобальных переменных.Но, как прерывание булавки всего лишь несколько вы можете написать глобальную переменную и функцию для каждого штыря:

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(); 
} 

как справочник См: http://forum.arduino.cc/index.php?topic=41713.0 или http://forum.arduino.cc/index.php?topic=160101.0

Смежные вопросы