Вызов attachInterrupt из объекта класса.

CityCat
CityCat аватар
Offline
Зарегистрирован: 13.06.2013

Переписываю библиотеку (переделываю 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;

Может не туда полез - в общем, запутался окончательно. Отказываться от такой конструкции не хотелось бы, потому как на два прерывания можно повесить два датчика (два объекта класса), однако, в обработчике прерывания хотелось бы оперировать именно с переменными данного объекта.
Надеюсь, хоть немного понятно объяснил.

Посему вопрос. Как заставить данную конструкцию работать и возможно ли это в принципе?

Прошу помидорами не кидать, а разъяснить по существу.

Спасибо.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

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();
}

Понятно, что можно завести переменную (например, указатель на активный объект) и отслеживать, какой именно объект сейчас перехватывает прерывания, но это гемор еще тот, а если Вам нужно одновременно, тогда этот метод не подойдет.

 

CityCat
CityCat аватар
Offline
Зарегистрирован: 13.06.2013

А можно "живой" пример?

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Учите мат.часть, изучайте примеры. Тем более компилятор Вам всё сказал корректно, а я Вам объяснил, почему он это сказал. А если вообще ничего непонятно, то может и браться не стоит?

 

CityCat
CityCat аватар
Offline
Зарегистрирован: 13.06.2013

Спасибо за напутствие. Разобрался.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Пример обработчика в виде статического метода класса, возможно кому то будет интересно. Это только скелет и код не рабочий, но компилируется.

#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()
{
}

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

Т.е. я правильно понял,  что использовать attachInterrupt в экземпляре класа не получиться ?

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Использовать можно, только особого смысла в этом нет. Если в двух словах опишите задачу, попробую пояснить конкретней

AlexMann
Offline
Зарегистрирован: 13.05.2014

Спасибо.

в частности , используется примерно такой код 






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++;
}  


 Код уже подпорчен :) но суть наверно видна.

Спасибо!

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Вот один из вариантов реализации. Он не оптимальный и не без "греха", потому рассматриваю его как учебный. Вот код:

#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, чтобы его компилятор не оптимизировал.

AlexMann
Offline
Зарегистрирован: 13.05.2014

Спасибо, вроде понятно. Надо попробовать переложить в мои реалии :) 

Кстати, про сруктуры как способ хранения данных датчиков.

Кроме датчиков протока, будут еще датчики тока и пару десятков температурных далласов. Я предположил что удобно хранить данные о датчиках в структорах, структуры в связанном списке и одной процедурой, перебирая список опрашивать датчики...

Т.е. задача в том, что бы не иметь 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 не самоцель, может лучше как то по другому ?

Спасибо.

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Навскидку, первое, что нужно помнить при большом количестве данных, что у нас очень мало ОЗУ и намного больше 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, а потом хитро читать. Впрочем это не стоит обсуждения :)
 

Кстати, еще, увидел в комментариях, конструкция типа такой:

DS temp  = dallas_list->get(i);

Опасна тем, что в temp будет создана КОПИЯ объекта, лучше использовать const DS &temp = ...; или типа того, т.е. использовать ссылку из списка, а не копию объекта.

Так что, либо учить матчасть, если пользоваться списками, указателями, динамически создаваемыми массивами, ссылками, либо данные хранить во Flash, тогда и памяти хватит.

Конечно люди пишут так, как пытаетесь Вы, такие проекты в сети есть, но оправдан ли такой подход на МК? (риторический). На больших компах - да, а здесь, лучше воздержаться от хитростей большого С++.

Может вечером еще посмотрю, работы много.

AlexMann
Offline
Зарегистрирован: 13.05.2014

 

kisoft, спасибо! Большое спасибо!

Ща попробую.  Мне нужно осознать как правильно работать с такими данными. 

Завести отдельную тоему про структуры и списки ??

P.S.>

kisoft пишет:

А также использовать поменьше классов (здесь они не всегда оправданы и нужны, но иногда можно) и динамического выделения памяти (её и так мало).

т.е. не пытать ся запихать все подряд фунции в классы в либах ?? :)

 

Про структуры создал отдельную тему

http://arduino.ru/forum/programmirovanie/khranenie-dannkh-datchikov-stru...

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

С либами не всё так просто. Использование классов - это, прежде всего, удобство использования. Потому что если это будет набор функций, будет сложнее искать и понять, для чего эти функции нужны. Как правило эти объекты не создаются десятками, а имеют всего один экземпляр. Хотя, безусловно, бывают исключения.

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

Я так понимаю, использование либы и создание экземпляра какого либо класса из нее отнимает больше памяти, нежели просто описанные функции в коде... Я и хотел все служебные функции, типа опроса датчиков (тут кстаи интересно , датчиков тока будет 3-4, датчиков давления 2, далласов 22-25, датчиков расхода 3),  приема / отправки СМС, передачи данных через GPRS и т.п. вынести в либы, чтоб глаза не мазолили... 

Может отказаться о использования DallasTemperature, и просто описать свой класс, мне нужно тока получить температуру по адресу и все. И будет 25 экземпляроов, с разными адресами и по разному поименованные :) ? 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Я ответил в той теме, чтобы здесь не оффтопить.

AlexMann
Offline
Зарегистрирован: 13.05.2014

В общем, свой вопрос я решил просто :) и не красиво.

В качестве либ использую .ino фалы и заголовки .h

Все работает, включая прерывания, и это логично....