Проблема с написанием библиотеки
- Войдите на сайт для отправки комментариев
Доброго времени суток.
Пишу библиотеку для обработки сигналов (считывание длительности импульса 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, а передавать массив?
А что там за 4-ая строка в файле "Хидер библиотеки". Он что сам себя инклюдит?
Но проблема не в этом.
Проблема в том, что у Вас имя константы совпадает с именем класса - они подрались.
Замените в строках 1 и 2 Famouspilot на Famouspilot_h, например, и ошибки уйдут
Спасибо, исправил то, что вы указали. Но все еще выбивает такую:
Думаю, что-то намутил с указателями и/или типами переменных... Не подскажете?
Передавайте адресс массива
Famouspilot RD(&receiverPins[0], (sizeof(receiverPins)/sizeof(receiverPins[0])));
В третьей строке первый параметр - массив, а в описании функции - целое число. Разберитесь, что надо и сделайте везде одинаково.
Спасибо, разобрался, теперь эти ошибки не вылазят, но валятся другие:
Помню, подобного рода ошибки возникали и с обычными прерываниями, но здесь даже не знаю в чем дело... Может в том, что обработчики прерываний rising() и falling() являются функциями класса?
Может в том, что обработчики прерываний rising() и falling() являются функциями класса?
Нестатическими? ну, это точно беда. Они могут быть либо честными функциями, либо статическими методами. Методами экземпляра они не могут быть никак - где они this-то возьмут?
Прошу прощенния, в ооп я не силен)
Как это можно решить?
Сейчас поздно, давайте завтра или в выходной (не уверен, что завтра смогу).
Давайте для начала немного теории.
Внутри класса можно объявлять переменные (называются «свойства») и функции (называются «методы»). Причём и то и другое можно объявлять как со словом static (статические свойства и методы), так и без него (свойства и методы экземпляра).
Когда Вы объявляете в программе переменную с типом – имя Вашего класса,
МyClass a, b;
такая переменная называется экземпляром класса.
Так вот, статические свойства и методы не привязаны к экземпляру, а существуют в единственном числе для всего класса. А свойства и методы экземпляров – привязаны к своим экземплярам.
Давайте для примера посмотрим на простенький класс для rgb-светодиода.
В классе свойства 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’ы не знает.
Отсюда вывод: в обработчике прерываний можно вызывать отдельно стоящую функцию, можно статический метод класса, но если нужно вызвать метод экземпляра, то нужно этот экземпляр знать и вызывать метод в его контексте.
Вот и думайте как Вам быть. Если у Вас в программе единственный экземпляр Вашего объекта, сделайте его глобальным и вызываетй его методы обычным образом. Если же экземпляров много и прерывания нужны всем, надо как-то определеять для какого именно экземпляра произошло прерывание и вызывать методы в его контексте.