Можно ли работать со Struct как с массивом?

Draghkon
Offline
Зарегистрирован: 17.09.2013

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

текущие значения датчиков храняться в структуре Current (13 элементов),

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

Чтобы не расписывать снова для каждого датчика идея была перебирать все элементы структуры в цикле - подобно массиву. Возможно ли это?

Представляю себе это примерно так:

typedef struct Data {
	float temp1 [3]{0,2,0};
	float hum1 [3]{0,2,0};//0-значение влажности, 2 - интервал проверки в секундах, 0- время последнего обновления.
	float temp2 [2]{0,3,0};
	float temp3 [2]{0,3,0};
	float temp4 [2]{0,2,0};
	float hum2 [2]{0,2,0};
	int hum3 [2]{0,3,0};
	boolean lampSens [3]{0,600,0};
	int Hight [1]{1200,1250};//это не датчики, эти данные нужно передавать только если они изменились. 1200 - текущее, 1250-предыдущее.
	int fanPwr[1]{150,255];
	int compPwr [2]{0,30,0};
	boolean filterSt [1] {1,1};
	boolean doorSt [2]{0,2,0};
}Current;

 void dataRead()
 {
for (int i=0 i>=12 i++){
int j=Current[i].lenght //пробуем перебрать структуру и узнаем длину массива элемента
if (j==2){ //если массив из 3х элементов
double t=millis(); //прошло времени
if (t-Current[i][2]>=Current[i][1]){ //если пора обновлять
dataCheck(Current[i]); //обновляем значение этого элемента.. вот только мы же не знаем тип данных?!
Сurrent[i][2]=millis(); //,обнуляем счетчик
}
else if (j==1){ //если массив из двух
if(Current[i][0]!=Current[i][1]){ //если данные отличаются
Serial.println(Current[i][0]); //отправляем данные
Current[i][1]=Current[i][0]; //обновляем
}
}
}
}
 
 }

 

Вобщем в таком виде код не работает, но думаю мысль моя понятна.. 

Еще смущают конечно типы.. Millis нужно записывать в Double, а элемент структуры может быть определен как boulean или int и как тогда быть?

 

 

kaaKAA777
Offline
Зарегистрирован: 30.01.2014

Мысль понятна но такой подход ошибочен в принципе. Структура создатеся для того, чтобы логически объеденить несколько элементов в один, но это не массив!

Что вам мешает создать массив массивов если на то пошло? Просто и удовлетворить ваши потребности.

Draghkon
Offline
Зарегистрирован: 17.09.2013

ТОже подумал об этом, но сталкиваюсь с проблемой: массив массивов может быть только однотипным насколько я понимаю.

т.е. 



float tempAir[2];
int compPwr[2];
boolean filter [1];
param[]={tempAir,compPwr,filter};

так сделать не получится, потому что какой тип массиву param не задавай - жалуется что нельзя преобразовать Float, int и boolean в этот тип.. Структура как раз позволяет объединять разнотипные данные.

А так Стракт можно было бы объявить и после и прописать в него значения уже определенных массивов.

 

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

Массив структур.

struct Data
{
...
  uint8_t value;
...
};

Data array[3] =
{
  // Здесь инициализируются данные, если нужно
  { данные первого датчика},
  { данные второго датчика},
  { данные третьего датчика},
};
...

  for( i =0; i < 3; ++i )
  {
    Data &arr = array[i];
    Serial.print( i );
    Serial.print( "Value = " );
    Serial.println( arr.value );
  }

...

 

kaaKAA777
Offline
Зарегистрирован: 30.01.2014

Поддержу предыдущий пост.

Draghkon
Offline
Зарегистрирован: 17.09.2013

Спасибо,

Компилится, но не работает.

Я так понимаю, что в struct я записываю все те элементы которые были в моем примере, с их типами. А зачем включать вот это: uint8_t value; ? что это дает?

Data array[3] - мы создаем массив структур.. может я ошибаюсь, но в таком случае каждый элемент массива будет представлять экземпляр структуры, а потом в этой конструкции мы задаем значения,я так понимаю те значения которые я задавал как массив для каждого элемента структуры. Вроде получается уже трехмерный массив, но компилятор не ругается.. Вобщем эта часть ускользает от понимания.

Data &arr = array[i]; - Здесь я так понимаю происходит создание ссылки на созданный ранее массив.

Честно сказать не понимаю что мы должны получить в итоге... Скомпилированный код не выдает вообще ничего, ни один из Serial.println не выводится в терминал.

kaaKAA777
Offline
Зарегистрирован: 30.01.2014


struct Data
	{
	  uint8_t value1_1;	
	  uint8_t value1_2;
	  uint8_t value1_3;
	};
	 
	Data array[3] =
	{
	  // Здесь инициализируются данные, если нужно
	  {1,2,3 },
	  {4,5,6},
	  {7,8,9}
	};

int main()
{
        for (int i=0; i<3; ++i )
	{
	    Data &arr = array[i];
	    Serial.println("Array element = " + i );
	    Serial.println( "Value_1 = " + arr.value1_1); 
	    Serial.println( "Value_2 = " + arr.value1_2); 
	    Serial.println( "Value_3 = " + arr.value1_3); 
	};
}

 

Draghkon
Offline
Зарегистрирован: 17.09.2013

kaaKAA777

... видимо я что-то не догоняю. Точно как есть вставляю ваш код -  он компилится без ошибок замечательно, но в Сериал порт не выводит вообще ничего! должен же эти цыфры выводить 1-9, а ничего не выводит.

Больше того, если в коде присутствует указанный вами кусок, Seral.println вообще ничего не выводит(даже произвольный текст), даже если функция  main не вызывается... 

kaaKAA777
Offline
Зарегистрирован: 30.01.2014

Возможно проблеммы с конкатенцией символов. Попробуйте убрать все стоковые константы.

{
        for (int i=0; i<3; ++i )
	{
	    Data &arr = array[i];
	    Serial.println(i);
	    Serial.println(arr.value1_1); 
	    Serial.println(arr.value1_2); 
	    Serial.println(arr.value1_3); 
	};
}

Просто я теоретик, контроллера у меня пока нет и в натуре проверить код немогу.

Draghkon
Offline
Зарегистрирован: 17.09.2013

Решил проблему. Все дело оказалось по всей видимоcти в имени функции int main() , изменил её на void main1() все заработало.

Но смысла относительно задачи я что-то не увидел. Мы создаем несколько экземпляров структуры в массиве (3 шт), дальше определяем значения для каждого элемента экземпляра структуры. 

Но чтобы вызвать эти значения, по прежнему нужно обращаться к элементу по имени, т.е. arr.value 

А в данном случае нужен лишь 1 экземпляр структуры, и задача перебрать все элементы, подобно тому, как это делает foreach в php. Потому что ладно если их 5 штук, а если 45?

С другой стороны заменить структуру массивом мы не можем, потому что нужно использовать разные типы данных.

 

Draghkon
Offline
Зарегистрирован: 17.09.2013

Кажется нащупал решение.. Спасибо за наводку - попробовал подумать над этим с другой стороны, в итоге пришел к тому, что мне нужен Массив массивов структур.

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


struct Data //структура параметров датчиков
	{
	  float value;	
	  double time;
	  int interval;
	};

	Data tempAir[1] = //экземпляр структуры для каждого датчика
	{
	  // Здесь инициализируются данные, если нужно
	  {1.233,222222,33},
	  
	};
	Data &tempair=tempAir[0]; //делаем так, чтобы к массиву можно было обращаться как к структуре
	Data humAir[1]=
	{
	  // Здесь инициализируются данные, если нужно
	  {69.22,333333,44},
	  
	};
	Data &humair=humAir[0];
	
 Data *Array[2]={tempAir, humAir}; //объединяем все датчики в 1 массив
	

void setup()
{
Serial.begin(9600);
main1(); //вызов функции перебора
float q; //пробуем присвоить начение переменной
q=tempair.value;
Serial.println(q);
int in=1020; //пробуем изменить значение структуры
humair.interval=in;
Serial.println(humair.interval);

}
void loop()
{


}

void main1()
{

        for (int i=0; i<2;  ++i )
	{
	
	
	
	    Data &arr = *Array[i]; //перебо всех значений всех датчиков
	    Serial.println(i);
	    Serial.println(arr.value); 
	    Serial.println(arr.time); 
	    Serial.println(arr.interval); 
	    
	};
	
}

Выводит:

0
1.23
222222.00
33
1
69.22
333333.00
44
1.23
1020

kaaKAA777
Offline
Зарегистрирован: 30.01.2014

Вы по сути повторили мой код, только усложнили его.

Draghkon
Offline
Зарегистрирован: 17.09.2013

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

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

struct Data
	{
	  float value;	
	  double time;
	  int interval;
	};
	
	Data Array[2]=
	{
	  // Здесь инициализируются данные, если нужно
	  {1.233,222222,33},
	  {69.22,333333,44},
	   
	};
	Data &tempAir=Array[0];
	Data &humAir=Array[1];

Результат тот же.

Единственное - для меня пока остаются непонятными механизмы того как это работает.. я имею ввиду операторы & и * . поэтому использую их почти наугад.

на почту вам написал, мэйлагентом не пользуюсь.

kaaKAA777
Offline
Зарегистрирован: 30.01.2014

Ну теперь другое дело, посмотрите в скайп.

Sandr
Offline
Зарегистрирован: 14.01.2015

Подниму тему. 

Есть структура в файле srCh.h, и в основном скетче необходимо перебрать все каналы и прописать каждому каналу значения maxV и minV снятые с соответсвующих аналоговых входов

Для этого перебираю массив и передаю структуру в функцию readState

  for ( int i=0; i < chCount; i++ )
      chArray[i].state = readState( chArray[i] ); 

Но значения сохраняются в пределах функции readState и глубже

Не сохраняясь в основном массиве каналов "chArray"

Вопрос - как записать данные в основной массив при такой структуре функций?

-----------------------------

Вот подробный код srCh.h

// Структура кодов
typedef struct {
  const char* cName; // Имя канала, не используется в коде
  int enable; // отключение канала при обнаружении ошибки
  const int pIn;  // Порт чтения статуса устройства
  const int pOut; // Порт управления устройством
  int state;  // Результаты измерений pIn
  int maxV; // Максимальное измеренное значение диапазона
  int minV; // Минимальное измеренное значение диапазона
} srCh;

srCh chArray[2] = //экземпляр структуры для каждого датчика
{
  // Здесь инициализируются данные, если нужно
  {"ch1", 1, A0, 2, 0, 0, 1023},
  {"ch2", 1, A1, 3, 0, 0, 1023},
};

srCh &ch1=chArray[0]; //делаем так, чтобы к массиву можно было обращаться как к структуре
srCh &ch2=chArray[1]; //делаем так, чтобы к массиву можно было обращаться как к структуре

Вот подробный код скетча

void setup() 
{
  // подсчет количества прописанных каналов 
  chCount = sizeof(chArray)/sizeof(*chArray);
  
  for ( int i=0; i < chCount; i++ )
  { // перебор всех каналов и установка портов вывода
    pinMode (chArray[i].pOut, OUTPUT);
  }

  for ( int i=0; i < chCount; i++ )
  { // self test всех каналов

     if ( chArray[i].enable == 1 )
     {// чтение состояния канала, если он не отключен в srCh.h
        chArray[i].enable = selfTest( chArray[i] ); 
     }

  }

}

int selfTest(  srCh ch )
{ // self test канала

    // прогон канала до крайнего значения
    digitalWrite ( ch.pOut, HIGH) ;
    delay ( fT ); // задержка с запасом на прогон всего канала
    digitalWrite ( ch.pOut, LOW) ;
    delay(200);
    
    // замер первого значения
    int s1 = readState ( ch );

    digitalWrite ( ch.pOut, HIGH) ;
    delay ( fT );
    digitalWrite ( ch.pOut, LOW) ;
    delay(200);
    // замер второго значения
    int s2 = readState ( ch );

    // вычисление диапазона измерений
    int d = s1 - s2 ;
    d = abs(d);
    if ( d >= mR) //  mR  значение рабочего диапазона
    { // если измеренный диапазон равен или больше рабочих значений 
      // запишем значения 
      ch.maxV = max(s1, s2); 
      ch.minV = min(s1, s2);

      return 1;  // вернуть TRUE
    }
    
    return 0; // при ошибке вернуть FALSE
}

int readState( srCh ch )
{ // Чтение состояния канала
    int  sens = analogRead(ch.pIn);  // прочитать значение на входе
	  sens = map(sens, 0, 1023, 1023, 0); // перевернуть значение

    
    // вычислим разницу между измерениями
    int diff = ch.state - sens ;
    diff = abs(diff);
    
    if ( diff > thrsh ) // thrsh - диапазон погрешности
    {
      ch.state = sens; 
    }
    return ch.state;
}

 

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

В функции selftest и readstate передаются копии структур, а не указатели, поэтому все, что заносится внутри функций идёт лесом.

Sandr
Offline
Зарегистрирован: 14.01.2015

Собственно вопрос - передавать указатель положения в массиве

// чтение состояния канала, если он не отключен в srCh.h
selfTest( i );

// замер второго значения
int s2 = readState ( i );

или есть другой способ?

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

Передавать указатель на структуру

Sandr
Offline
Зарегистрирован: 14.01.2015

а можно в виде примера ?

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