Вызов метода класса из прерывания.
- Войдите на сайт для отправки комментариев
Пт, 21/02/2014 - 11:45
Решил освоить классы и их применение. Написал простую программу, но так и не смог добиться её работы.
// Arduino. Test Class & Interrupt.
//
#define IOPort Serial
#define PortSpeed 9600
//
class foo {
public:
foo(): counter(42) {}
void up(){ counter++; }
void dn(){ counter--; }
int get(){return counter;}
private:
int counter;
};
//
foo bar;
//
void setup(){
IOPort.begin (PortSpeed);
attachInterrupt (0, bar.up, FALLING);
attachInterrupt (1, bar.dn, FALLING);
}
void loop(){
IOPort.println (bar.get());
delay (1000);
}
Идея проста, увеличивать или уменьшать значение counter.
Помогите, пожалуйста!
Как-то странно объявлен class foo! А вы компилировали (проверяли) скетч в Arduino IDE?
Как-то странно объявлен class foo! А вы компилировали (проверяли) скетч в Arduino IDE?
Да, проверял. И если менять значения не через прерывания, то работает. А через прерывания - ошибки.
Ошибки чего, компиляции?
foo(): counter(42) {} - подскажите, что значт? Не силен в ООП под С++. Похоже на конструктор, который инициализирует couter значением 42?
Сразу есть подозрение, что в аттаче должна быть функция void (), а не метод класса! Точнее указатель на функцию void ().
Для нормальной работы с переменными в прерываниях переменная должна бать описана как
volatile int counter;
см пример http://arduino.ru/Reference/AttachInterrupt
Ошибки чего, компиляции?
foo(): counter(42) {} - подскажите, что значт? Не силен в ООП под С++. Похоже на конструктор, который инициализирует couter значением 42?
Сразу есть подозрение, что в аттаче должна быть функция void (), а не метод класса! Точнее указатель на функцию void ().
1. Ошибки компиляции, да.
2. foo(): counter(42) {} это конструктор - я по книге делал, не сам придумал :-)
3. Натолкнуло на мысль. Проверю.
Получилось, НО.
То, что получилось полностью не соответствует замыслу :-(
// Arduino. Test Class & Interrupt. // #define IOPort Serial #define PortSpeed 9600 #define N 10 // class foo { public: foo(): counter(42) {} void up(){ counter++; } void dn(){ counter--; } int get(){ return counter; } private: volatile int counter; }; // foo bar[N]; // void UP(){ bar[1].up(); } void DN(){ bar[1].dn(); } // И что же, теперь туеву хучу функций писать??? // void setup(){ IOPort.begin (PortSpeed); } void loop(){ attachInterrupt (0, UP, FALLING); attachInterrupt (1, DN, FALLING); // for (i = 1; i < N ; i++) { detachInterrupt (0); detachInterrupt (1); // attachInterrupt (0, bar[i].up, FALLING); // attachInterrupt (1, bar[i].dn, FALLING); } // ... IOPort.println (bar[1].get()); delay (1000); }Значится так, это не С, а С++.... Вообщем если коротко то учите мат.часть.
А если длинно то это невозможно, дело в том, в attachInterrupt передается указатель на функцию. Но метод класса не возможно вызвать без его инстанса. грубо говоря если раскрутить вызов метода в обычный С то
class A { public: int V; void M() { V++; } // void M( A * this ) { this->V++ } } void IntHandler() { A instance; instance.M(); // ==> A::M( &instance ) }Короче говоря, вызов метода класса, можно рассматривать как вызов обычной функции С, где первый параметр это указатель на класс.
А attachInterrupt ни о какой передаче и ни о каком инстансе и слыхом не слыхивал, можете использовать статические методы класса, там прокатит, но это все равно что писать внешние функции, вообщем С++ не всегда красиво стыкуется с С.
А я думаю, что просто подход неправильный в данном случае у автора. Зачем подстраивать класс под аттач, когда можно сделать все просто. Класс оставляем, но пишем свои функции-обертки, которые будут вызываться в аттачах:
// Arduino. Test Class & Interrupt. // #define IOPort Serial #define PortSpeed 9600 // class foo { public: foo(): counter(42) {} void up(){ counter++; } void dn(){ counter--; } int get(){return counter;} private: int counter; }; // foo bar; // void fUP() {bar.up();} void fDN() {bar.dn();} void setup(){ IOPort.begin (PortSpeed); attachInterrupt (0, fUP, FALLING); attachInterrupt (1, fDN, FALLING); } void loop(){ IOPort.println (bar.get()); delay (1000); }так и приходиться делать, есть более изящные конструкции, но они частенько сложны для понимания если С++ не родной язык :-)
Спасибо за замечания и комментарии.
Получилось не так, как хотелось, но то, что нужно. Теперь с помощью двух прерываний я умею менять значения нескольких переменных.
// Arduino. Test Class & Interrupt. // #define IOPort Serial #define PortSpeed 9600 #define N 6 // class ch { private: byte level; byte pin; public: ch(): level(127){} void up(){ level++;} void dn(){ level--;} byte get(){return level;} } channel[N]; // int i; unsigned long tcount; char msg[30]; // void UP(){ channel[i].up(); } void DN(){ channel[i].dn(); } // void setup(){ IOPort.begin (PortSpeed); attachInterrupt (0, UP, FALLING); attachInterrupt (1, DN, FALLING); } void loop(){ for (i = 0; i <= N; i++){ tcount = millis(); while ( (millis() - tcount) < 1000 ){ sprintf (msg,"channel: %1i, level: &3i", i,channel[i].get()); IOPort.println (msg); } } }Буду продолжать учить матчасть и попробую решить эту задачу поизящнее :-)
Тихий ужас.. i используется в цикле в loop и в прерывании, натурально - обезьяна с гранатой.
Второе, после цикла у Вас i == N, если пойдет прерывание, то получите channel[N].up() или dn(), т.е. выстрел в неизвестность.
На счет классов - не получится решить задачу, только через задницу (как сейчас), либо через вызов статических методов классов.
О чего нарыл - обработчик прерывания статическим методом класса с доступом к private данным.
Правда это код для ARM LeafMaple (attachInterrupt немного другой), но надо проверить под Arduino!
О чего нарыл - обработчик прерывания статическим методом класса с доступом к private данным.
Правда это код для ARM LeafMaple (attachInterrupt немного другой), но надо проверить под Arduino!
Спасибо, почитаю и это. Я сейчас зарылся полностью в изучение "матчасти", думаю ещё на неделю-другую хватит.
Есть сомнения в работоспособности примера - статические методы работают могут работать только со статическими переменными. (ну по крайней мере по другому я не знаю)
Работать не будет, ошибка компилятора, опять не пропускает с разными типами параметров в attach-е, да и в примере они передают 4 параметра, а в доке по libmaple attach с тремя параметрами (тоже не должно скомпилиться, но не могу проверить - сдох АРМ)!