我正在为超声波距离传感器编写一个简单的库,并且我想尝试使用中断。
但是我无法在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)();
}
答案 0 :(得分: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);
答案 1 :(得分:2)
Arduino中断处理程序只能是函数。您正在尝试使方法对象成为中断处理程序。因此编译器抱怨。
更准确地说,对象方法就像函数一样,但就好像它们采用了一个“隐藏”参数,它指定了对象实例。因此,它们实际上具有与普通函数不同的类型签名。当函数查找的是普通函数指针时,这不允许传递方法指针。
解决方案是将echoHigh()
和echoLow()
移出HCSR04Interrupt
类,并使其成为普通函数。
答案 2 :(得分: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
答案 3 :(得分: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;
}