Присоединить прерывание к библиотеке
Я пытаюсь сделать библиотеку для Arduino, которая требует прерывания, но проблема в том, что когда я пробую функцию attachInterrupt
внутри моей библиотеки, возникает проблема с attachInterrupt is static. Прямо сейчас в библиотеке у меня есть это в заголовочном файле:
#ifndef RegletaCMA_h
#define RegletaCMA_h
#include "Arduino.h"
class DimmerGlider {
public:
DimmerGlider(int min, int max, int increase);
int getMin() { return _min; }
int getMax() { return _max; }
int getIncrease() { return _increase; }
void setMin(int min) { _min = min; }
void setMax(int max) { _max = max; }
void setIncrease(int increase) { _increase = increase; }
private:
int _min, _max, _increase;
};
class Dimmer {
public:
Dimmer(DimmerGlider &glider, int outputPin, int t3);
void Dimmer::begin() {
pinMode(_outputPin, OUTPUT);
digitalWrite(_outputPin, false);
}
void Dimmer::dim() {
delayMicroseconds(_DIMMER_counter);
digitalWrite(_outputPin, true); // Включаем _DIMMER_pinDimmer
delayMicroseconds(_t3);
digitalWrite(_outputPin, false); // Выключаем _DIMMER_pinDimmer
if (_DIMMER_dir) _DIMMER_counter += _glider.getIncrease(); // Если dir отрицательный, добавить _DIMMER_increase
else _DIMMER_counter -= _glider.getIncrease(); // Если dir отрицательный, вычитаем _DIMMER_increase
if (_DIMMER_counter > _glider.getMax()) _DIMMER_dir = false; // Изменить dir, если достигнуто дно
if (_DIMMER_counter < _glider.getMin()) _DIMMER_dir = true; // Изменить каталог, если достигнут верх
_DIMMER_lastExecutionTime_micros = micros(); // Сбросить таймер
}
void Dimmer::force(bool status) {
digitalWrite(_outputPin, status);
}
private:
DimmerGlider &_glider;
int _outputPin;
int _DIMMER_counter = 1000;
bool _DIMMER_dir = true;
unsigned long long _DIMMER_lastExecutionTime_micros = 0;
int _t3;
};
class DimmerImplementor {
public:
DimmerImplementor(Dimmer dimmerList[], int optoPin);
void DimmerImplementor::begin(){
attachInterrupt(_optoPin, dimAll, RISING);
}
void DimmerImplementor::dimAllDimmers() {
for (int c = 0; c < sizeof(_dimmerList); c++)
_dimmerList[c].dim();
}
void DimmerImplementor::dimAll() {
DimmerImplementor::dimAllDimmers();
}
private:
int _optoPin;
Dimmer _dimmerList[];
};
#endif
и это в cpp-файле:
#include "Arduino.h"
#include "RegletaCMA.h"
DimmerGlider::DimmerGlider(int min, int max, int increase) :
_min(min),
_max(max),
_increase(increase) {
}
Dimmer::Dimmer(DimmerGlider &glider, int outputPin, int t3) :
_glider(glider),
_outputPin(outputPin),
_t3(t3) {
}
DimmerImplementor::DimmerImplementor(Dimmer *dimmerList, int optoPin) :
_dimmerList(dimmerList),
_optoPin(optoPin) {
for(int c = 0; c < sizeof(dimmerList); c++){
DimmerImplementor::dimmers[c] = dimmerList[c];
}
for (int c = 0; c < sizeof(dimmers); c++) {
Dimmer dimmer = dimmers[c];
dimmer.begin();
}
}
а когда я пытаюсь запустить библиотеку с помощью Arduino IDE, с этим кодом:
DimmerGlider dimmer1Glider = DimmerGlider(_DIMMER_1_tempMin, _DIMMER_1_tempMax, _DIMMER_1_increase);
Dimmer dimmer1 = Dimmer(
dimmer1Glider,
_DIMMER_1_pin,
_DIMMER_t3
);
DimmerGlider dimmer2Glider = DimmerGlider(_DIMMER_2_tempMin, _DIMMER_2_tempMax, _DIMMER_2_increase);
Dimmer dimmer2 = Dimmer(
dimmer2Glider,
_DIMMER_2_pin,
_DIMMER_t3
);
DimmerGlider dimmer3Glider = DimmerGlider(_DIMMER_3_tempMin, _DIMMER_3_tempMax, _DIMMER_3_increase);
Dimmer dimmer3 = Dimmer(
dimmer3Glider,
_DIMMER_3_pin,
_DIMMER_t3
);
Dimmer dimmers[] = {
dimmer1, dimmer2, dimmer3
};
DimmerImplementor implementor = DimmerImplementor(dimmers, _DIMMER_pinOpto);
void Dimmer_Init() {
implementor.begin();
}
Выдает следующую ошибку:
C:\Users\Arnym\Documents\Arduino\libraries\RegletaCMA/RegletaCMA.h: In member function 'void DimmerImplementor::begin()':
C:\Users\Arnym\Documents\Arduino\libraries\RegletaCMA/RegletaCMA.h:73:44: error: invalid use of non-static member function
attachInterrupt(_optoPin, dimAll, 3); // 3 is the same as RISING
^
Я уже несколько дней бьюсь над этой проблемой и не могу найти ответа, поэтому буду очень рад, если вы сможете мне помочь. Если вам нужна дополнительная информация, не стесняйтесь спрашивать. Заранее спасибо.
@Arnyminer Z, 👍1
2 ответа
Лучший ответ:
В C++ необходимо различать две отдельные копии объекта или наличие ссылки на существующий объект. @chrisl правильно понял, когда определил, что вы пытаетесь создать вторую копию DimmerGlider
, поэтому он предложил использовать ссылку, а затем показал, что вместо этого можно использовать указатель (*
).
Он был прав: Dimmer
должен содержать ссылку на объект DimmerGlider
, но это делается с помощью &
. Вам нужно внести следующие изменения в данный код:
В .h
:
class Dimmer {
public:
Dimmer(DimmerGlider &glider, int outputPin, int t3);
.
.
.
private:
DimmerGlider &_glider;
.
.
И в конечном .cpp
:
DimmerGlider::DimmerGlider(int min, int max, int increase) :
_min(min),
_max(max),
_increase(increase) {
}
Dimmer::Dimmer(DimmerGlider &glider, int outputPin, int t3) :
_glider(glider),
_outputPin(outputPin),
_t3(t3) {
}
Синтаксис для конструктора Dimmer
пришлось изменить. Вы присваивали членам класса значения из параметров конструктора. Ссылки нужно инициализировать, а не назначать. Это тот синтаксис, который вам нужен (обратите внимание, что они находятся перед {
?)
Я исправил код конструктора DimmerGlider
, пока был занят...
Также обратите внимание на разницу между использованием ссылки и указателя. Указатель необходимо разыменовать, поэтому вам нужно использовать *ptr
и ptr->_min
для ссылки на исходный объект. Ссылка уже разыменована, поэтому вы можете просто использовать ее как исходный объект: ref
и ref._min
.
Изменение: если вы хотите использовать функцию dimAll()
как функцию обработчика прерываний, то она не может быть (нестатическим) членом класса
. Все функции класса
имеют скрытый указатель this
в качестве первого параметра в списке аргументов, поскольку он должен знать, какие члены DimmerImplementor
изменять. Таким образом, вы должны объявить функцию как static
. И как только вы это сделаете, вы не сможете вызвать dimAllDimmers()
, потому что эта функция обращается к экземпляру переменных DimmerImplementor
. К счастью, у вас есть глобальный объект с именем implementor
, поэтому вы можете использовать его:
static void DimmerImplementor::dimAll() {
implementor.dimAllDimmers();
}
Но обычно эту переменную делают статическим
членом самого класса:
class DimmerImplementor {
.
.
public: // Статические переменные
static DimmerImplementor implementor;
.
.
}; // Реализатор диммера
Вы бы инициализировали это следующим образом:
DimmerImplementor DimmerImplementor::implementor(dimmers, _DIMMER_pinOpto);
В сообщении об ошибке говорится, что в конструкторе Dimmer
не удается найти соответствующий конструктор DimmerGlider
. Проблема здесь в том, что вы передаете параметры по значению, что создает новую переменную указанного типа и содержимого для вызова функции/конструктора. Поэтому, когда вы создаете новую переменную Dimmer
, вы вызываете конструктор класса. Поскольку параметры конструктора содержат экземпляр DimmerGlider
, он также должен быть создан для вас, что означает вызов конструктора. При передаче переменных по значению используется конструктор по умолчанию (без каких-либо параметров). Но у DimmerGlider
нет конструктора по умолчанию (так как вы его не определили). Затем компилятор сообщает вам, что для создания экземпляра DimmerGlider
конструктору нужны некоторые параметры.
Я не знаю способа передать эти параметры для конструктора DimmerGlider
напрямую через конструктор Dimmer
. Также я не думаю, что это желательно для вас. Вы сначала создаете DimmerGlider
и хотите, чтобы объекты Dimmer
ссылались именно на этот экземпляр, а не на другой (клонированный) экземпляр, созданный с помощью конструктора Dimmer
.
Поэтому я предлагаю следующее: Передайте DimmerGlider
по ссылке, то есть вы передаете только указатель на объект DimmerGlider
. В определении конструктора Dimmer
измените на следующее:
Dimmer::Dimmer(DimmerGlider *glider, int outputPin, int t3);
*
говорит, что эта переменная не будет содержать экземпляр класса DimmerGlider
, а только указатель на него. Указатель создать просто, потому что это, по сути, unsigned int
(16-битный адрес памяти).
Затем в вашем скетче вы передаете не саму переменную, а только адрес в памяти (указатель на объект) с помощью &
:
Dimmer dimmer1 = Dimmer(
&dimmer1Glider,
_DIMMER_1_pin,
_DIMMER_t3
);
Теперь конструктор Dimmer
не должен создавать экземпляр DimmerGlider
, а только простой указатель типа Dimmerglider
. &
извлекает адрес памяти (указатель) экземпляра объекта. Конструктор теперь просто записывает указатель, который он получил как параметр, в переменную glider
типа DimmerGlider
-указатель.
Если вы не понимаете, как работают указатели, пожалуйста, поищите в Google руководство по этому вопросу. Это не то, что можно легко объяснить в кратком формате вопросов и ответов на этом сайте.
- Какие Arduino поддерживают ATOMIC_BLOCK?
- Библиотека LiquidCrystal и таймеры кажутся несовместимыми.
- Используйте ISR внутри библиотеки более элегантно
- Как получить исходные файлы для библиотек Arduino?
- Использование millis() и micros() внутри процедуры прерывания
- Ошибка: "недопустимое использование нестатической функции-члена" при вызове функции из моего собственного класса-метода
- Подсчет импульсов с прерыванием
- Как подключить Wi-Fi Shield ESP-12E-ESP8266-UART-WIFI-Wireless-Shield к Arduino
Спасибо, это решило мою первую проблему, но у меня все еще возникают проблемы с attachInterrupt, компилятор выдает
error: invalid use of non-static member function
, см. измененный вопрос для полной программы, @Arnyminer Z@ArnyminerZ Проверьте редактирование моего ответа., @John Burger