Проблема с написанием библиотеки
- Войдите на сайт для отправки комментариев
Доброго времени суток.
Пишу библиотеку для обработки сигналов (считывание длительности импульса c приемника для радиоуправления, тот же управляющий сигнал для сервопривода) c аналоговых пинов на Mega 2560. Сама библиотека основана на другой библиотеке, PinChangeInterrupt.
В чем суть - при компиляции выскакивают следующие ошибки:
C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot/Famouspilot.h:18:17: error: expected unqualified-id before 'unsigned'
Famouspilot(unsigned int pins, unsigned int count);
^
C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot/Famouspilot.h:18:17: error: expected ')' before 'unsigned'
C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot/Famouspilot.h:16:19: error: an anonymous struct cannot have function members
class Famouspilot {
^
C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot/Famouspilot.h:39:2: error: abstract declarator '<anonymous class>' used as declaration
}; //
^
sketch_mar02c:3: error: expected constructor, destructor, or type conversion before '(' token
exit status 1
expected constructor, destructor, or type conversion before '(' token
Использовал следующий скетч:
#include <Famouspilot.h>
unsigned int receiverPins[3]={0, 1, 2};
Famouspilot RD(receiverPins, 3);
void setup() {
}
void loop() {
}
Хидер библиотеки:
#ifndef Famouspilot
#define Famouspilot
#define NO_PORTB_PINCHANGES
#include <Famouspilot.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
class Famouspilot {
public:
Famouspilot(unsigned int pins, unsigned int count);
boolean Error();
void Launch();
void Stop();
unsigned int GetRCvalue(unsigned int channel);
unsigned int GetPulseDuration(unsigned int channel);
boolean test();
void setNewBounds(unsigned int channel, unsigned int newLowBound, unsigned int newHighBound);
private:
boolean Fuse = false, workState = false;
unsigned int receiverPinCount;
void rising();
void falling();
//inline byte highlightPin();
unsigned int *pulseDuration;
unsigned long int *lastTime;
unsigned int *usedPins;
const byte pciPins[8] = {A8, A9, A10, A11, A12, A13, A14, A15};
unsigned int *lowBound;
unsigned int *highBound;
unsigned long int timeBuffer;
}; //
//
#endif
СРР:
#include <PinChangeInt.h>
#include <Famouspilot.h>
#if defined (ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
Famouspilot::Famouspilot(unsigned int pins, unsigned int count){
receiverPinCount = count;
usedPins = (unsigned int*)malloc(receiverPinCount*sizeof(unsigned int));
for(int i = 0; i<receiverPinCount; i++) usedPins[i]=pins[i]
if(receiverPinCount<8){
Fuse = true;
for(int i = 0; i<receiverPinCount, i++) {
if(usedPins[i]>7) Fuse = false;
else
pinMode(pciPins[usedPins[i]], INPUT_PULLUP);
}
}
else Fuse = false;
if (Fuse) {
pulseDuration = (unsigned int*)malloc(receiverPinCount*sizeof(unsigned int));
lastTime = (unsigned long int*)malloc(receiverPinCount*sizeof(unsigned long int));
lowBound = (unsigned int*)malloc(receiverPinCount*sizeof(unsigned int));
highBound = (unsigned int*)malloc(receiverPinCount*sizeof(unsigned int));
}
}
void Famouspilot::Launch(){
if (Fuse) {
for(int i = 0; i<receiverPinCount, i++) {
PCintPort::attachInterrupt(pciPins[usedPins[i]], rising(), FALLING);
PCintPort::attachInterrupt(pciPins[usedPins[i]], falling(), RISING);
}
workState = true;
}
}
void Famouspilot::Stop(){
if (Fuse) {
for(int i = 0; i<receiverPinCount, i++) {
PCintPort::detachInterrupt(pciPins[usedPins[i]]);
PCintPort::detachInterrupt(pciPins[usedPins[i]]);
}
workState = false;
}
}
unsigned int Famouspilot::GetRCvalue(unsigned int channel) {
if(Fuse) {
if (channel<=receiverPinCount)
return constrain(map(pulseDuration[channel-1], lowBound[channel-1], highBound[channel-1], 0, 180), 0, 180);
else return (NULL);
}
else return (NULL);
}
unsigned int Famouspilot::GetPulseDuration(unsigned int channel) {
if(Fuse) {
if (channel<=receiverPinCount)
return (pulseDuration[channel-1]);
else return (NULL);
}
else return (NULL);
}
boolean Famouspilot::Error(){
return (!Fuse);
}
void Famouspilot::rising() {
timeBuffer = micros();
for (int i = 0; i<receiverPinCount; i++){
if (pciPins[usedPins[i]] == PCintPort::arduinoPin)
lastTime[i]=timeBuffer;
}
}
void Famouspilot::falling() {
timeBuffer = micros();
for(int i = 0; i<receiverPinCount; i++){
if(pciPins[usedPins[i]] == PCintPort::arduinoPin)
pulseDuration[i] = timeBuffer - lastTime[i];
}
}
boolean Famouspilot::test() {
if(Fuse) {
boolean testBody = true;
unsigned long int currentTestBodyTime = micros();
for(int i = 0; i<receiverPinCount; i++) {
if(currentTestBodyTime>lastTime[i]+100000) testBody = false;
}
return (testBody);
}
else return (false);
}
void Famouspilot::setNewBounds(unsigned int channel, unsigned int newLowBound, unsigned int newHighBound) {
if(channel<=receiverPinCount) {
lowBound[channel - 1] = newLowBound;
highBound[channel - 1] = newHighBound;
}
}
Библиотеку писал (пытался) по шаблону, данному на этом же сайте. Раньше успешно запустил подобную библиотеку (правда, с "обычными" attachInterrupt), но без "класса".
В чем мои ошибки?
Прошу прощения, что в .h и .CPP слишком много (быдло)кода, по идее, он здесь не играет рояля. Если нужно, опишу что и как работает (по крайней мере, должно).
Тыкните меня лицом во все неувязки/проблемные места которые заметите, для "общего развития"
P.s. может так оказаться, что в коде какой-то элемент не используется (сырая еще).
P.p.s. в ардуино и программировании я новичок =)
Я конечно не большой спец в С, но можно ли объявить входной параметр как unsigned int, а передавать массив?
Famouspilot(unsigned int pins, unsigned int count); ........................................................................ unsigned int receiverPins[3]={0, 1, 2}; Famouspilot RD(receiverPins, 3);А что там за 4-ая строка в файле "Хидер библиотеки". Он что сам себя инклюдит?
Но проблема не в этом.
Проблема в том, что у Вас имя константы совпадает с именем класса - они подрались.
Замените в строках 1 и 2 Famouspilot на Famouspilot_h, например, и ошибки уйдут
Спасибо, исправил то, что вы указали. Но все еще выбивает такую:
sketch_mar02c:3: error: invalid conversion from 'unsigned int*' to 'unsigned int' [-fpermissive] C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot/Famouspilot.h:19:5: error: initializing argument 1 of 'Famouspilot::Famouspilot(unsigned int, unsigned int)' [-fpermissive] Famouspilot(unsigned int pins, unsigned int count); ^ exit status 1 invalid conversion from 'unsigned int*' to 'unsigned int' [-fpermissive]Думаю, что-то намутил с указателями и/или типами переменных... Не подскажете?
unsigned int receiverPins[3]={0, 1, 2}; Famouspilot RD(receiverPins, 3);Передавайте адресс массива
Famouspilot RD(&receiverPins[0], (sizeof(receiverPins)/sizeof(receiverPins[0])));В третьей строке первый параметр - массив, а в описании функции - целое число. Разберитесь, что надо и сделайте везде одинаково.
Спасибо, разобрался, теперь эти ошибки не вылазят, но валятся другие:
C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot\Famouspilot.cpp: In member function 'void Famouspilot::Launch()': C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot\Famouspilot.cpp:50:69: error: no matching function for call to 'PCintPort::attachInterrupt(const byte&, <unresolved overloaded function type>, int)' PCintPort::attachInterrupt(pciPins[usedPins[i]], rising, FALLING); ^ C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot\Famouspilot.cpp:50:69: note: candidate is: In file included from C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot\Famouspilot.cpp:1:0: C:\Program Files (x86)\arduino-1.6.6\libraries\PinChangeInt/PinChangeInt.h:421:8: note: static int8_t PCintPort::attachInterrupt(uint8_t, PCIntvoidFuncPtr, int) int8_t PCintPort::attachInterrupt(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, int mode) ^ C:\Program Files (x86)\arduino-1.6.6\libraries\PinChangeInt/PinChangeInt.h:421:8: note: no known conversion for argument 2 from '<unresolved overloaded function type>' to 'PCIntvoidFuncPtr {aka void (*)()}' C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot\Famouspilot.cpp:51:69: error: no matching function for call to 'PCintPort::attachInterrupt(const byte&, <unresolved overloaded function type>, int)' PCintPort::attachInterrupt(pciPins[usedPins[i]], falling, RISING); ^ C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot\Famouspilot.cpp:51:69: note: candidate is: In file included from C:\Program Files (x86)\arduino-1.6.6\libraries\Famouspilot\Famouspilot.cpp:1:0: C:\Program Files (x86)\arduino-1.6.6\libraries\PinChangeInt/PinChangeInt.h:421:8: note: static int8_t PCintPort::attachInterrupt(uint8_t, PCIntvoidFuncPtr, int) int8_t PCintPort::attachInterrupt(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, int mode) ^ C:\Program Files (x86)\arduino-1.6.6\libraries\PinChangeInt/PinChangeInt.h:421:8: note: no known conversion for argument 2 from '<unresolved overloaded function type>' to 'PCIntvoidFuncPtr {aka void (*)()}' exit status 1 Ошибка компиляции.Помню, подобного рода ошибки возникали и с обычными прерываниями, но здесь даже не знаю в чем дело... Может в том, что обработчики прерываний rising() и falling() являются функциями класса?
Может в том, что обработчики прерываний rising() и falling() являются функциями класса?
Нестатическими? ну, это точно беда. Они могут быть либо честными функциями, либо статическими методами. Методами экземпляра они не могут быть никак - где они this-то возьмут?
Прошу прощенния, в ооп я не силен)
Как это можно решить?
Сейчас поздно, давайте завтра или в выходной (не уверен, что завтра смогу).
Давайте для начала немного теории.
Внутри класса можно объявлять переменные (называются «свойства») и функции (называются «методы»). Причём и то и другое можно объявлять как со словом static (статические свойства и методы), так и без него (свойства и методы экземпляра).
Когда Вы объявляете в программе переменную с типом – имя Вашего класса,
МyClass a, b;
такая переменная называется экземпляром класса.
Так вот, статические свойства и методы не привязаны к экземпляру, а существуют в единственном числе для всего класса. А свойства и методы экземпляров – привязаны к своим экземплярам.
Давайте для примера посмотрим на простенький класс для rgb-светодиода.
class RGBLed { public: inline RGBLed(const int8_t pR, const int8_t pG, const int8_t pB) { pinRed = pR; pinGreen = pG; pinBlue = pB; } inline void setColor(const uint8_t r, const uint8_t g, const uint8_t b) const { analogWrite(pinRed, colorConvert(r)); analogWrite(pinGreen, colorConvert(g)); analogWrite(pinBlue, colorConvert(b)); } static uint8_t colorConvert(const uint8_t c) { return (uint8_t) (((int) c) * 100 / ((int) pwmResolution)); } private: uint8_t pinRed, pinGreen, pinBlue; static uint8_t pwmResolution; }; uint8_t RGBLed::pwmResolution = 255; void setup() { RGBLed led1(9,10,11); RGBLed led2(3,5,6); led1.setColor(20, 40, 100); led2.setColor(50, 50, 50); uint8_t c = RGBLed::colorConvert(80); }В классе свойства pinRed, pinGreen, pinBlue объявлены как свойства экземпляра (строка 21), а свойство pwmResolution (строка 22) – статическое для всего класса.
В строках 27 и 28 мы создаём два экземпляра класса: led1 и led2.
Таким образом, у нас в памяти будет существовать одна на всех переменная pwmResolution и два независимых комплекта переменных pinRed, pinGreen, pinBlue – по одному комплекту на каждый созданный экземпляр.
Поэтому pinRed, pinGreen, pinBlue будут свои для led1 и свои для led2, а вот pwmResolution будет одна на всех.
Теперь о методах.
Метод setColor привязан к экземпляру. Поэтому, вызывать его можно только в контексте экземпляра (строки 28 и 29). При этом при вызове в строке 28, метод будет использовать (в строках 9-11) переменные pinRed, pinGreen, pinBlue экземпляра led1, а при вызове в контексте экземпляра led2 (строка 29) в строка 9-11 будут использоваться pinRed, pinGreen, led2. Метод setColor нельзя вызвать вне контекста экземпляра, т.к. он просто не будет знать с какими именно переменными pinRed, pinGreen, pinBlue ему работать, т.к. в памяти есть два комплекта этих переменных.
Метод же colorConvert – статический. Он один и не привязан к экземпляру. Его необходимо вызывать вне всякого контекста (строка 30). Он не имеет права обращаться к переменным, pinRed, pinGreen, pinBlue т.к. он сам не привязан к экземпляру и потому понятия не имеет каким из двух комплектов этих переменных пользоваться.
И последнее, как именно организован вызов метода «в контексте экземпляра»? Очень просто. При вызове нестатического метода, ему всегда передаётся скрытый параметр this – указатель на экземпляр в контексте которого его вызывают.
Надеюсь, это понятно? Если нет, спрашивайте про непонятные места.
Теперь Вы готовы понять, почему нельзя использовать метод экземпляра класса в качестве обработчика прерываний. Вектор обработки прерывания – это просто адрес программы в памяти. Сам-то адрес метода можно запихать в вектор, только вот this-то ему кто передаст? Система обработки прерываний ничего ни про какие this’ы не знает.
Отсюда вывод: в обработчике прерываний можно вызывать отдельно стоящую функцию, можно статический метод класса, но если нужно вызвать метод экземпляра, то нужно этот экземпляр знать и вызывать метод в его контексте.
Вот и думайте как Вам быть. Если у Вас в программе единственный экземпляр Вашего объекта, сделайте его глобальным и вызываетй его методы обычным образом. Если же экземпляров много и прерывания нужны всем, надо как-то определеять для какого именно экземпляра произошло прерывание и вызывать методы в его контексте.