Вызов attachInterrupt из объекта класса.
- Войдите на сайт для отправки комментариев
Переписываю библиотеку (переделываю DHT на прерываниях - не нравятся мне задержки при получении показаний с датчика - но не об этом речь). И столнулся с интересной проблемой.
Для наглядности приведу код (думаю, проще будет понять, что мне необходимо):
Скетч (буду удалять ненужное, чтоб не захламлять код):
#include <DHT.h>
#define DHT22_PIN 2
#define DHTTYPE_22 DHT22
DHT dht(DHT22_PIN, DHTTYPE_22);
void setup()
{
//............
delay(1000);
//............
}
void loop()
{
//............
dht.mainfunc(); // Крутится постоянно
if(millis()-prevTime >= interval)
{
if (dht.NachIzmer(true)) //запускаем измерения
prevTime=millis();
}
//............
}
Ну, соответственно, класс в хидере:
class DHT
{
private:
//....................
public
//....................
void mainfunc(void);
void Interrupt(void);
//....................
};
И собственно, cpp:
// Основная функция
void DHT::mainfunc()
{
//....................
// Если что-то там..., то нужно запустить прерывание
if (ctoto_tam)
attachInterrupt(0, Interrupt, RISING);
//....................
}
// Обработчик прерывания
void DHT::Interrupt()
{
int a=1;
}
Понятное дело, что не работает. Компилятор жалуется на несовпадение типов: error: argument of type 'void (DHT::)()' does not match 'void (*)()'
На буржуйском форуме нашел почти такую же тему. Начинаю понимать, что совсем не понимаю что там предлагают.
Суть проблемы, как мне видится то, что у обработчика прерывания судя по описанию не должно быть ни параметров ни возвращаемого значения. А когда вызывается эта функция объектом класса он как минимум передаёт параметром this (возможно я не прав, поэтому и создаю тему и прошу разъяснить).
Функция attachInterrupt объявляется в WInterrupts.h как
void attachInterrupt(uint32_t pin, void (*callback)(void), uint32_t mode);
И определение ее:
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)
{
if(interruptNum < EXTERNAL_NUM_INTERRUPTS)
{
intFunc[interruptNum] = userFunc;
switch (interruptNum)
{
//Дальше идет включение прерываний
}
}
}
Не понятна строчка выше:
static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS]; // volatile static voidFuncPtr twiIntFunc;
Может не туда полез - в общем, запутался окончательно. Отказываться от такой конструкции не хотелось бы, потому как на два прерывания можно повесить два датчика (два объекта класса), однако, в обработчике прерывания хотелось бы оперировать именно с переменными данного объекта.
Надеюсь, хоть немного понятно объяснил.
Посему вопрос. Как заставить данную конструкцию работать и возможно ли это в принципе?
Прошу помидорами не кидать, а разъяснить по существу.
Спасибо.
Interrupt должна быть обычной функцией без параметров. А у Вас это метод класса (нужно помнить, что в методы и функции класса, первым параметром неявно передается указатель на объект). Вообще иногда так делают, но тогда этот метод должен быть статическим, но Вам нужен доступ к членам класса, а из статического метода к ним доступа нет, по понятной причине, статический метод не знает из какого объекта его запустили.
Самое тупое - передать в конструктор DHT указатель на эту функцию и использовать его в методе mainfunc.
Возможно в Вашем случае лучше сделать два обработчика, каждый из них будет знать только свой объект, хотя вполне возможно, что каждый обработчик будет выывать метод класса для определенного объекта.
Приблизительный скелет такой:
... extern void callback1(void); extern void callback2(void); DHT dht1( DHT22_PIN, DHTTYPE_22, callback1 ); DHT dht2( DHT21_PIN, DHTTYPE_21, callback2 ); ... void callback1(void) { dht1.Interrupt(); } void callback2(void) { dht2.Interrupt(); }Понятно, что можно завести переменную (например, указатель на активный объект) и отслеживать, какой именно объект сейчас перехватывает прерывания, но это гемор еще тот, а если Вам нужно одновременно, тогда этот метод не подойдет.
А можно "живой" пример?
Учите мат.часть, изучайте примеры. Тем более компилятор Вам всё сказал корректно, а я Вам объяснил, почему он это сказал. А если вообще ничего непонятно, то может и браться не стоит?
Спасибо за напутствие. Разобрался.
Пример обработчика в виде статического метода класса, возможно кому то будет интересно. Это только скелет и код не рабочий, но компилируется.
#include <Arduino.h> #define INT_NUM 0 class MyClass { public: MyClass() { mParameter = 0; } ~MyClass(); void startInterrupt(); protected: static void interruptHandler(void); private: int mParameter; }; // static void MyClass::interruptHandler(void) { /* Увы, отсюда ничего недоступно из объекта */ /* потому этот код не будет компилироваться mParameter++; */ } void MyClass::startInterrupt() { attachInterrupt( INT_NUM, interruptHandler, RISING ); } MyClass::~MyClass() { detachInterrupt( INT_NUM ); } MyClass myClass; void setup() { myClass.startInterrupt(); } void loop() { }Т.е. я правильно понял, что использовать attachInterrupt в экземпляре класа не получиться ?
Использовать можно, только особого смысла в этом нет. Если в двух словах опишите задачу, попробую пояснить конкретней
Спасибо.
в частности , используется примерно такой код
int NbTopsFan; void rpm () { NbTopsFan++; } void setup() { pinMode(2, INPUT); Serial.begin(9600); attachInterrupt(0, rpm, RISING); } void loop () { NbTopsFan = 0; sei(); delay (1000); cli(); Calc = (NbTopsFan * 60 / 7.5); Serial.print (Calc, DEC); }Для удобочитаемости, т.к. таких мелких функций подучения данных от разных датчиков много, я решил освоить библиотеки :) Попытался пененести это в библиотеку и столкнулся с уже обсуждаемой проблемой.
#ifndef WoterSensor_h #define WoterSensor_h #include "Arduino.h" class WoterSensor { public: WoterSensor(); WoterSensor(int pin); WoterSensor(int pin, int del, int rate); int getRPM(); int getRate(); private: int _pin; int _delay; int _int; int _rate; int NbTopsFan; void irq(); void rpm(); int count(); }; #endif#include "WoterSensor.h" #include "Arduino.h" WoterSensor::WoterSensor() { } WoterSensor::WoterSensor(int pin) { pinMode(pin, INPUT); _pin = pin; _delay = 1000; _rate = 7.5; //attachInterrupt(0, rpm, RISING); } WoterSensor::WoterSensor(int pin, int del, int rate) { pinMode(pin, INPUT); _pin = pin; _delay = del; _rate = rate; if(pin==2) _int = 0; if(pin==3) _int = 1; } int WoterSensor::getRPM(){ return count(); }; int WoterSensor::getRate() { return count() * _delay /_rate; }; int WoterSensor::count() { NbTopsFan = 0; sei(); delay(_delay); cli(); return NbTopsFan; } void WoterSensor::irq(){ attachInterrupt(0, rpm, RISING); } void WoterSensor::rpm() { NbTopsFan++; } Код уже подпорчен :) но суть наверно видна.Спасибо!
Вот один из вариантов реализации. Он не оптимальный и не без "греха", потому рассматриваю его как учебный. Вот код:
#include <Arduino.h> /* Количество датчиков */ #define MAX_SENSORS 3 typedef void (*interruptFunc)(void); /* Кол-во обработчиков должно быть равно MAX_SENSORS */ void interruptFunc0(void); void interruptFunc1(void); void interruptFunc2(void); typedef struct SensorData { byte m_Pin; int m_InterruptNumber; unsigned long m_Counter; interruptFunc m_Func; }; /* Это только для Leonardo, для Uno всего два варианта */ SensorData g_Sensor[ MAX_SENSORS ] = { { 3, 0, 0, interruptFunc0 }, { 2, 1, 0, interruptFunc1 }, { 0, 2, 0, interruptFunc2 } }; /* Это класс, который будет делать общую для всех датчиков работу */ class WaterSensor { public: WaterSensor( byte p_Index ); ~WaterSensor(); unsigned long getRPM() const { /* Запрет прерываний, поскольку мы будем считывать состояние счетчика, который меняется в прерывании */ cli(); unsigned long l_Value = g_Sensor[ m_Index ].m_Counter; sei(); return l_Value; } /* Сброс счетчика */ void resetCounter() { cli(); g_Sensor[ m_Index ].m_Counter = 0; sei(); } private: byte m_Index; }; WaterSensor::WaterSensor( byte p_Index ) : m_Index( p_Index ) { g_Sensor[ m_Index ].m_Counter = 0; attachInterrupt( g_Sensor[ m_Index ].m_InterruptNumber, g_Sensor[ m_Index ].m_Func, RISING ); } WaterSensor::~WaterSensor() { detachInterrupt( g_Sensor[ m_Index ].m_InterruptNumber ); } WaterSensor g_SensorArray[ MAX_SENSORS ] = { WaterSensor( 0 ), WaterSensor( 1 ), WaterSensor( 2 ) }; void setup() { Serial.begin( 57600 ); } void loop() { for( byte i = 0; i < MAX_SENSORS; ++i ) { /* Считываем значение счетчика */ unsigned long l_Counter = g_SensorArray[ i ].getRPM(); /* Сбрасываем его */ g_SensorArray[ i ].resetCounter(); /* Выводим в Serial */ Serial.print( i ); Serial.print( ": " ); Serial.println( l_Counter ); } /* Отдохнем и наберем еще немного информации */ delay( 1000 ); } void interruptFunc0(void) { g_Sensor[ 0 ].m_Counter++; } void interruptFunc1(void) { g_Sensor[ 1 ].m_Counter++; } void interruptFunc2(void) { g_Sensor[ 2 ].m_Counter++; }Главное:
1. Храним данные об одном датчике в отдельной структуре.
2. Соответственно сколько датчиков, столько элементов в массиве.
3. Каждый класс цепляет к своему датчику внешний обработчик (указатель на который хранится там же в массиве).
4. В цикле опрашиваем счетчики каждого сенсора и выводим в Serial, другой вариант, считаем и пересчитываем как надо.
5. Делаем паузу в 1 секунду, чтобы счетчики успели набрать информацию. И переходим к п.4.
Что здесь реализовано криво:
1. В loop в цикле между считыванием данных счетчиков есть "большая" пауза для вывода в Serial, оптимальней считать все счетчики в другой моссив (сделать копию)
2. Выполнить нужные пересчеты
3. Вывести рассчитанные значения в Serial
Разумеется можно добавить в класс метод для пересчета данных по какой то общей формуле и использовать эту формулу для каждого счетчик в цикле, например:
#include <Arduino.h> /* Количество датчиков */ #define MAX_SENSORS 3 typedef void (*interruptFunc)(void); /* Кол-во обработчиков должно быть равно MAX_SENSORS */ void interruptFunc0(void); void interruptFunc1(void); void interruptFunc2(void); typedef struct SensorData { byte m_Pin; int m_InterruptNumber; unsigned long m_Counter; interruptFunc m_Func; }; /* Это только для Leonardo, для Uno всего два варианта */ SensorData g_Sensor[ MAX_SENSORS ] = { { 3, 0, 0, interruptFunc0 }, { 2, 1, 0, interruptFunc1 }, { 0, 2, 0, interruptFunc2 } }; /* Это класс, который будет делать общую для всех датчиков работу */ class WaterSensor { public: WaterSensor( byte p_Index ); ~WaterSensor(); unsigned long getRPM() const { /* Запрет прерываний, поскольку мы будем считывать состояние счетчика, который меняется в прерывании */ cli(); unsigned long l_Value = g_Sensor[ m_Index ].m_Counter; sei(); return l_Value; } /* Сброс счетчика */ void resetCounter() { cli(); g_Sensor[ m_Index ].m_Counter = 0; sei(); } static unsigned long solveWorldProblem( unsigned long p_Counter ) { return p_Counter * p_Counter / 4096; } private: byte m_Index; }; WaterSensor::WaterSensor( byte p_Index ) : m_Index( p_Index ) { g_Sensor[ m_Index ].m_Counter = 0; attachInterrupt( g_Sensor[ m_Index ].m_InterruptNumber, g_Sensor[ m_Index ].m_Func, RISING ); } WaterSensor::~WaterSensor() { detachInterrupt( g_Sensor[ m_Index ].m_InterruptNumber ); } WaterSensor g_SensorArray[ MAX_SENSORS ] = { WaterSensor( 0 ), WaterSensor( 1 ), WaterSensor( 2 ) }; void setup() { Serial.begin( 57600 ); } void loop() { for( byte i = 0; i < MAX_SENSORS; ++i ) { /* Считываем значение счетчика */ unsigned long l_Counter = g_SensorArray[ i ].getRPM(); /* Сбрасываем его */ g_SensorArray[ i ].resetCounter(); /* Выводим в Serial */ Serial.print( i ); Serial.print( ": " ); Serial.println( WaterSensor::solveWorldProblem( l_Counter ) ); } /* Отдохнем и наберем еще немного информации */ delay( 1000 ); } void interruptFunc0(void) { g_Sensor[ 0 ].m_Counter++; } void interruptFunc1(void) { g_Sensor[ 1 ].m_Counter++; } void interruptFunc2(void) { g_Sensor[ 2 ].m_Counter++; }Хорош на сегодня, вопросы есть или вообще ничего непонятно?
UPD: Код компилируется, но работает или нет - не знаю. И с 0 пином поаккуратней, я его тут использую, но может быть больно (лучше его не использовать).
UPD2: m_Counter надо объявить volatile, чтобы его компилятор не оптимизировал.
Спасибо, вроде понятно. Надо попробовать переложить в мои реалии :)
Кстати, про сруктуры как способ хранения данных датчиков.
Кроме датчиков протока, будут еще датчики тока и пару десятков температурных далласов. Я предположил что удобно хранить данные о датчиках в структорах, структуры в связанном списке и одной процедурой, перебирая список опрашивать датчики...
Т.е. задача в том, что бы не иметь 30 мелких функций , которые обрабатывают каждый отдельный датчик, а проходить список...
#include <LinkedList.h> #include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS 12 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress _deviceAddress; // временное место для адвера, нужно для перебора адресов в printAdress struct DS{int index;DeviceAddress deviceAddress;String desc;float result;float preres;float low;float high; boolean trend;}; struct PS{int index;String desc; float result;float low;float high;boolean trend;}; boolean isInited = false; LinkedList<DS> *dallas = new LinkedList<DS>(); void setup(void) { if(!isInited)initStruct(); Serial.print("Saze of list: "); // Serial.println(dallas_list.size()); test(); }//setup void loop(void) { Serial.println("ety"); delay(2000); }//loop void test(){ //for(int i=0; i!=dallas_list->size(); i++){ // DS temp = dallas_list->get(i); // _deviceAddress = temp.deviceAddress; // } } void initStruct(void){ DS dallas = {0, {0x10,0x3E,0x59,0x9A,0x02,0x08,0x00,0xA0},"Температура воздуха на улице",0,0,25,100,NULL}; //dallas_list.add(Ta_outdoor); /* DS Ta_indoor = {1, {0x28,0x35,0x72,0x80,0x04,0x00,0x00,0xB1},"Температура воздуха в доме",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tf_beforeComptessor = {2, {0x28,0x57,0x8E,0x7F,0x04,0x00,0x00,0x70},"Температура на всасе",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tf_after_Comptessor = {3, {0x10,0x3E,0x59,0x9A,0x02,0x08,0x00,0xA0},"Температура на разгрузке",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tf_beforeVaporator = {4, {0x28,0x35,0x72,0x80,0x04,0x00,0x00,0xB1},"Температура перед испарителем",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tf_afterPPTO = {5, {0x28,0x57,0x8E,0x7F,0x04,0x00,0x00,0x70},"Температура фреона перед ППТО",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tw_beforePPTO = {6, {0x10,0x3E,0x59,0x9A,0x02,0x08,0x00,0xA0},"Температура фреона после ППТО",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tw_afterPPTO = {7, {0x28,0x35,0x72,0x80,0x04,0x00,0x00,0xB1},"Температура воды перед ППТО",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS T_compreccor = {8, {0x28,0x57,0x8E,0x7F,0x04,0x00,0x00,0x70},"Температура воды перед ППТО",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tw_feedingMU = {9,{0x10,0x3E,0x59,0x9A,0x02,0x08,0x00,0xA0},"Температура подачи в ТП",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tw_returnMU = {10,{0x28,0x35,0x72,0x80,0x04,0x00,0x00,0xB1},"Температура обратки ТП",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS T_floor_heating = {11,{0x28,0x57,0x8E,0x7F,0x04,0x00,0x00,0x70},"Температура поверхности пола",0,9,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tw_DB_feed = {12,{0x10,0x3E,0x59,0x9A,0x02,0x08,0x00,0xA0},"Температура подачи ДК",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tw_DB_return = {13,{0x28,0x35,0x72,0x80,0x04,0x00,0x00,0xB1},"Температура обратки ДК",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tw_HCV = {14,{0x28,0x57,0x8E,0x7F,0x04,0x00,0x00,0x70},"Температура гидрострелки",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Tw_HCV_feed = {15,{0x10,0x3E,0x59,0x9A,0x02,0x08,0x00,0xA0},"Температура подачи СО",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS TH_HCV_return = {16,{0x28,0x35,0x72,0x80,0x04,0x00,0x00,0xB1},"Температура обратки СО",0,0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Ta_after_haeter = {17,{0x28,0x57,0x8E,0x7F,0x04,0x00,0x00,0x70},"Температура воздуха после предпрогрева",0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Ta_after_fancoil = {18,{0x10,0x3E,0x59,0x9A,0x02,0x08,0x00,0xA0},"Температура воздуха после фэнкоила",0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Ta_after_recuperator = {19,{0x28,0x35,0x72,0x80,0x04,0x00,0x00,0xB1},"Температура воздуха после рекуператора",0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Ta_rejection_outdoor = {20,{0x28,0x57,0x8E,0x7F,0x04,0x00,0x00,0x70},"Температура эвакуируваемого воздуха",0,25,100,NULL}; dallas_list->add(Ta_outdoor); DS Ta_accupation_outdoor = {21,{0x28,0x57,0x8E,0x7F,0x04,0x00,0x00,0x70},"Температура поступающего воздуха",0,25,100,NULL}; dallas_list->add(Ta_outdoor); PS HP_LP = {23,"Давдение на всасе",0,25,100,NULL}; PS HP_HP = {24,"Давление на разгрузке",0,25,100,NULL}; PS Cur_HP_compreccor = {25,"Ток компрессора",0,25,100,NULL}; //current heat pump compressor PS Cur_HP_fan = {26,"Ток вентилятора испарителя",0,25,100,NULL}; //current heat pump compressor PS Cur_air_heater = {27,"Ток предподогревателя воздуха",0,25,100,NULL}; PS Wf_HP_flow = {28,"Скорость протока воды через ППТО",0,25,100,NULL};// проток через ППТО PS Wf_HS_flow = {29,"Скорость протока воды в CO",0,25,100,NULL}; // проток через СО` */ isInited = true; Serial.println("done"); }Вот это почти работало :) на 2560 , на нано сдыхает на 3-4 структурах в списке. При этом при компиляции вроде места остается достатоно, т.е. половина на Нано.
Подскажите, плиз, как бы мне правильно работать со структурами, что бы организовать их хранение и обработку ? Массив структур тоже пробовал. Может подход изначально не верный ? Структуры и linkedlist не самоцель, может лучше как то по другому ?
Спасибо.
Навскидку, первое, что нужно помнить при большом количестве данных, что у нас очень мало ОЗУ и намного больше Flash памяти, потому, initStruct можно выкинуть совсем и инициализировать все эти структуры статически, с распложением во Flash, определив это, например, как массив:
// Это массив, который расположится во FLash // На счет PROGMEM могу наврать, редко пользуюсь, посмотрите доки // Здесь главное - принцип const DS PROGMEM dallas[] = { { 0, { 0x10,0x3E...},"Температура.." }, { 1, { 0x28,0x35...},"Температура.." }, .. { 215, { 0x18,0x33...}, "Hello, World" } };А также использовать поменьше классов (здесь они не всегда оправданы и нужны, но иногда можно) и динамического выделения памяти (её и так мало).
Постараться не создавать локальных (см. initStruct) переменных типа:
DS dallas = {0, {0x10,0x3E,0x59,0x9A,0x02,0x08,0x00,0xA0},"Температура воздуха на улице",0,0,25,100,NULL};потому что они скорей всего пойдут в стек (если компилятор не соптимизирует, не проверял), а памяти (в т.ч. стека) маловато.
Если более подробно обратиться к этой конструкции, то мы сначала создаем в стеке структуру, заполненную данными, потом копируем её в связанный список, т.е. в какой то момент получется две копии одного и того же. Если же Вы скажете, что add в связанный список не копирует данные, то при выходе из initStruct стек будет потерян и данные в связанном списке будут содержать мусор. Уфф, несколько сумбурно, надеюсь понятно.
Безусловно обращение к Flash может быть медленней, нежели к ОЗУ, но это не всегда проблема.
Вообще эта задача уже вышла за рамки темы ;)
В Cortex с флешем получше, там просто пишешь const и всё уже там, во Flash, а здесь приходится париться с PROGMEM, а потом хитро читать. Впрочем это не стоит обсуждения :)
Кстати, еще, увидел в комментариях, конструкция типа такой:
Опасна тем, что в temp будет создана КОПИЯ объекта, лучше использовать const DS &temp = ...; или типа того, т.е. использовать ссылку из списка, а не копию объекта.
Так что, либо учить матчасть, если пользоваться списками, указателями, динамически создаваемыми массивами, ссылками, либо данные хранить во Flash, тогда и памяти хватит.
Конечно люди пишут так, как пытаетесь Вы, такие проекты в сети есть, но оправдан ли такой подход на МК? (риторический). На больших компах - да, а здесь, лучше воздержаться от хитростей большого С++.
Может вечером еще посмотрю, работы много.
kisoft, спасибо! Большое спасибо!
Ща попробую. Мне нужно осознать как правильно работать с такими данными.
Завести отдельную тоему про структуры и списки ??
P.S.>
А также использовать поменьше классов (здесь они не всегда оправданы и нужны, но иногда можно) и динамического выделения памяти (её и так мало).
т.е. не пытать ся запихать все подряд фунции в классы в либах ?? :)
Про структуры создал отдельную тему
http://arduino.ru/forum/programmirovanie/khranenie-dannkh-datchikov-stru...
С либами не всё так просто. Использование классов - это, прежде всего, удобство использования. Потому что если это будет набор функций, будет сложнее искать и понять, для чего эти функции нужны. Как правило эти объекты не создаются десятками, а имеют всего один экземпляр. Хотя, безусловно, бывают исключения.
Я так понимаю, использование либы и создание экземпляра какого либо класса из нее отнимает больше памяти, нежели просто описанные функции в коде... Я и хотел все служебные функции, типа опроса датчиков (тут кстаи интересно , датчиков тока будет 3-4, датчиков давления 2, далласов 22-25, датчиков расхода 3), приема / отправки СМС, передачи данных через GPRS и т.п. вынести в либы, чтоб глаза не мазолили...
Может отказаться о использования DallasTemperature, и просто описать свой класс, мне нужно тока получить температуру по адресу и все. И будет 25 экземпляроов, с разными адресами и по разному поименованные :) ?
Я ответил в той теме, чтобы здесь не оффтопить.
В общем, свой вопрос я решил просто :) и не красиво.
В качестве либ использую .ino фалы и заголовки .h
Все работает, включая прерывания, и это логично....