Масив датчиков OneWire

orcsin
Offline
Зарегистрирован: 12.06.2015

Всем здрасти!

Подскажите пожалуйста можно ли как то объявить датчики в OneWire не в виде объектов, а в виде масива объектов?

То есть обычно так:

OneWire sensorTemperature1(1);
OneWire sensorTemperature2(2);
OneWire sensorTemperature3(3);

А хотелось бы что то типа масива, что бы можно было крутить цикл опроса датчиков или написать общую функцию. В библиотеке ДаласТемператур есть подобное, но он не работает:

int oneWirePins[]={3,7};//OneWire DS18x20 temperature sensors on these wires
const int oneWirePinsCount=sizeof(oneWirePins)/sizeof(int);

OneWire ds18x20[oneWirePinsCount];
DallasTemperature sensor[oneWirePinsCount];

....

DeviceAddress deviceAddress;
  for (int i=0; i<oneWirePinsCount; i++) {;
    ds18x20[i].setPin(oneWirePins[i]);
    sensor[i].setOneWire(&ds18x20[i]);
    sensor[i].begin();
    if (sensor[i].getAddress(deviceAddress, 0)) sensor[i].setResolution(deviceAddress, 12);
  }

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Простите, но, боюсь, я не понял проблемы. Что мешает просто "по рабоче-крестьянски" объявить массив? Примерно так:

OneWire sensors[3] = { OneWire(1), OneWire(2), OneWire(3) }; // датчики на пинах 1, 2 и 3

В чём засада-то?

vde69
Offline
Зарегистрирован: 10.01.2016

ЕвгенийП пишет:

Простите, но, боюсь, я не понял проблемы. Что мешает просто "по рабоче-крестьянски" объявить массив? Примерно так:

OneWire sensors[3] = { OneWire(1), OneWire(2), OneWire(3) }; // датчики на пинах 1, 2 и 3

В чём засада-то?

это не то, что нужно ему...

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

кстати вопрос: можно делать массив состоящий из структур? если без указателей и приведения типов... простой способ работает?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vde69 пишет:

это не то, что нужно ему...

есму нужен массив адресов и по каждому адресу тогда можно обращатся к элементу... 

Вполне возможно, я же говорю, что я не понял проблемы. Просто в примере он явно хотел массив OneWire'ов, вот я и показал как это описать.

vde69 пишет:

можно делать массив состоящий из структур? если без указателей и приведения типов... простой способ работает?

Ну, я же описал массив экземпляров класса в этом же топике? А структура - она тоже класс. Так что делайте, кто Вам не даёт. Никаких проблем.

 

orcsin
Offline
Зарегистрирован: 12.06.2015

Спасибо за ответы, но тут ещё дальше вопросы, в принципе я попробую всё таки написать класс для датчиков, но в образовательных целях инетересно...

#include <Wire.h>
#include <OneWire.h>

#define pinDigitalTemperatureWater1 16
#define pinDigitalTemperatureWater2 17

OneWire sensorTemperature[2] = {OneWire(pinDigitalTemperatureWater1), OneWire(pinDigitalTemperatureWater2)};

byte addresSensorTemperature1[2][8]; // Так как датчиков несколько приходится создавать 2х мерный масив. В примере адресс одного датчика это одномерный масив и выглядит так : byte addr[8]; ds.select(addr);

void setup(){
    Serial.begin(9600);
    sensorTemperature[0].search(addresSensorTemperature1[0]);
    sensorTemperature[1].search(addresSensorTemperature1[1]);
}

...........

sensorTemperature[j].reset();                    // сбрасываем шину OneWire;
 sensorTemperature[j].select(addresSensorTemperature1[j]);            // И вот это он уже не понимает, мы указываем одномерный масив, а по факту он 2х мерный

Как быть в этой ситуации?

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну и что? Адрес сам по себе это одномерный массив. Ваш двумерный массив - это массив одномерных массивов (т.е. адресов). Ещё раз, Ваш вумерный массив на самом деле "одномерный массив одномерных массивов". Поэтому когда Вам нужен адрес, Вы берёте элемент одномерного "массива массивов". Этот элемент есть одномерный массив - адрес.

orcsin
Offline
Зарегистрирован: 12.06.2015

ЕвгенийП, а можете написать вашу мысль в коде? Исправить эту строку как надо.

sensorTemperature[j].select(addresSensorTemperature1[j]);

Если писать так, то он думает что я даю ему всего лишь ячейку масива под номером j.

 

orcsin
Offline
Зарегистрирован: 12.06.2015

Стоп! У меня адрес byte, а в примерах нашёл ещё типа такого:

DeviceAddress Thermometer1; Вот это тоже легко можно в масив загнать.

DeviceAddress встроен в язык, или он часть OneWire или DalasTemperature?

vde69
Offline
Зарегистрирован: 10.01.2016

orcsin пишет:

Стоп! У меня адрес byte, а в примерах нашёл ещё типа такого:

DeviceAddress Thermometer1; Вот это тоже легко можно в масив загнать.

DeviceAddress встроен в язык, или он часть OneWire или DalasTemperature?

 

я тебе это и предложил в третем посту :)

этот адрес - массив из 8 байт если меня склероз не подводит

vde69
Offline
Зарегистрирован: 10.01.2016

я сейчас с мониторчиком доразберусь и займусь именно тем чего ты хочешь...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

orcsin пишет:

DeviceAddress встроен в язык, или он часть OneWire или DalasTemperature?

Определён в OneWire как массив из 8 байтов.

orcsin
Offline
Зарегистрирован: 12.06.2015

Или у меня не тот OneWire или его там нет, но нашёл в библиотеке Даласа - typedef uint8_t DeviceAddress[8];

А просто так выдаёт ошибку

DeviceAddress Thermometer1;

sketch_jun01a:10: error: 'DeviceAddress' does not name a type

 DeviceAddress Thermometer1;

 ^

exit status 1
'DeviceAddress' does not name a type

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, значит я ошибся - в далласе.

А ошибки не будет, если включить #include <DallasTemperature.h>

orcsin
Offline
Зарегистрирован: 12.06.2015

Не помогает, что то её не нравится #include <DallasTemperature.h>, взял просто добавил себе typedef uint8_t DeviceAddress[8];

По сути начало ругаться после этой строки: sensorTemperature[count].select(addresSensorTemperature[count]);

ВОт что у меня сейчас и не работает:

#include <Wire.h>
#include <OneWire.h>

#define pinDigitalTemperatureWater1 16
#define pinDigitalTemperatureWater2 17

typedef uint8_t DeviceAddress[8];

OneWire sensorTemperature[2] = {OneWire(pinDigitalTemperatureWater1), OneWire(pinDigitalTemperatureWater2)};
DeviceAddress addresSensorTemperature[2];

void setup(){
	Serial.begin(9600);
	
	sensorTemperature[0].search(addresSensorTemperature[0]);
	sensorTemperature[1].search(addresSensorTemperature[1]);
}
 
void loop(){
	CalculateTemperature();
}

long millisNow;
bool ask_sensor[2] = {false, false};
long timeWhenAskSensor[2];
float temperatureNow[2];


void CalculateTemperature(){	//OK
	
	int HighByte, LowByte;
	byte dataTemperature[2];
		
	for (int count = 0; count < 2; count++) {
		sensorTemperature[count].reset();					// сбрасываем шину OneWire;
		sensorTemperature[count].select(addresSensorTemperature[count]);			// выбираем датчик температуры аквариума по адресу;
		sensorTemperature[count].write(0x44);			// запускаем конвертацию температуры температуры аквариума;
		
		delay(1000);
		
		sensorTemperature[count].reset();
		sensorTemperature[count].select(addresSensorTemperature[count]);
		sensorTemperature[count].write(0xBE); 				// считываем ОЗУ датчика температуры аквариума
		for (byte i = 0; i < 2; i++) {					// Читаем 2 bytes;
			dataTemperature[i] = sensorTemperature[count].read();
		}
		LowByte = dataTemperature[0];
		HighByte = dataTemperature[1];
		temperatureNow[count] = (float)((HighByte << 8) + LowByte)/16.0;
				
		Serial.println(count);
		Serial.println(temperatureNow[count]);
				
	}
}

И дурная привычка у IDE на разные ошибки выдавать только:

collect2.exe: error: ld returned 5 exit status

exit status 1
Ошибка компиляции для платы Arduino Nano.

 

Даже если стоит ПОДРОБНО.

orcsin
Offline
Зарегистрирован: 12.06.2015

Ещё вопросик, оказывается и сообщал датчику, что у меня паразитное питание (sensorTemperature[count].write(0x44, 1);
), а по факту у меня норм питание и датчики висит на 3 проводах.

Показания выдавал правдивые, это нормально?

orcsin
Offline
Зарегистрирован: 12.06.2015

С ошибкой "collect2.exe: error: ld returned 5 exit status" мой косяк, вылечилось полной переустановкой и уделением библиотек.

orcsin
Offline
Зарегистрирован: 12.06.2015

Подскажите пожалуйста, переписываю библиотеку Даласа под себя и просто набираюсь опыта, имею вот что:

typedef uint8_t DeviceAddress[8];

byte temperaturePins[] = {15,16};
byte oneWirePinsCount = 2;

OneWire TemperatureOneWire[4] = {
	OneWire(temperaturePins[0]), OneWire(temperaturePins[0]),
	OneWire(temperaturePins[1]), OneWire(temperaturePins[1])};
DeviceAddress addresSensorTemperature[4] = {
	{0x28, 0x9E, 0x95, 0xB5, 0x04, 0x00, 0x00, 0x51 },
	{0x28, 0x9E, 0x95, 0xB5, 0x04, 0x00, 0x00, 0x51 },
	{0x28, 0x9E, 0x95, 0xB5, 0x04, 0x00, 0x00, 0x51 },
	{0x28, 0x9E, 0x95, 0xB5, 0x04, 0x00, 0x00, 0x51 }
};

DS18B20Lib sensorsTemperature(&TemperatureOneWire);

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

Arduino: 1.6.9 (Windows 7), Плата:"Arduino/Genuino Uno"

DS18B20_test:24: error: no matching function for call to 'DS18B20Lib::DS18B20Lib(OneWire (*)[4])'

 DS18B20Lib sensorsTemperature(&TemperatureOneWire);

                                                  ^

E:\doc\arduino\DS18B20Lib\DS18B20_test\DS18B20_test.ino:24:50: note: candidates are:

In file included from E:\doc\arduino\DS18B20Lib\DS18B20_test\DS18B20_test.ino:3:0:

C:\Users\User\Documents\Arduino\libraries\DS18B20Lib/DS18B20Lib.h:25:5: note: DS18B20Lib::DS18B20Lib(OneWire*)

     DS18B20Lib(OneWire*);

     ^

C:\Users\User\Documents\Arduino\libraries\DS18B20Lib/DS18B20Lib.h:25:5: note:   no known conversion for argument 1 from 'OneWire (*)[4]' to 'OneWire*'

C:\Users\User\Documents\Arduino\libraries\DS18B20Lib/DS18B20Lib.h:24:2: note: DS18B20Lib::DS18B20Lib()

  DS18B20Lib();

  ^

C:\Users\User\Documents\Arduino\libraries\DS18B20Lib/DS18B20Lib.h:24:2: note:   candidate expects 0 arguments, 1 provided

C:\Users\User\Documents\Arduino\libraries\DS18B20Lib/DS18B20Lib.h:22:7: note: constexpr DS18B20Lib::DS18B20Lib(const DS18B20Lib&)

 class DS18B20Lib {

       ^

C:\UsersUser\Documents\Arduino\libraries\DS18B20Lib/DS18B20Lib.h:22:7: note:   no known conversion for argument 1 from 'OneWire (*)[4]' to 'const DS18B20Lib&'

C:\Users\User\Documents\Arduino\libraries\DS18B20Lib/DS18B20Lib.h:22:7: note: constexpr DS18B20Lib::DS18B20Lib(DS18B20Lib&&)

C:\Users\User\Documents\Arduino\libraries\DS18B20Lib/DS18B20Lib.h:22:7: note:   no known conversion for argument 1 from 'OneWire (*)[4]' to 'DS18B20Lib&&'

E:\doc\arduino\DS18B20Lib\DS18B20_test\DS18B20_test.ino: In function 'void setup()':




exit status 1
no matching function for call to 'DS18B20Lib::DS18B20Lib(OneWire (*)[4])'


В принципе либа Даласа не работает по это же причине, конструктор не может принять масив объектов.

Подскажите как поправить.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, я же показывал Вам в посте №1 выше как объявить массив объектов и вызвать конструкторы. Там были объекты типа OneWire, ну а сейчас Вам нужны объекты типа DeviceAddress. Ну точно также как там объявите массив и вызывайте конструкторы в инициализаторе.

georgo
Offline
Зарегистрирован: 06.09.2016

Понимаю что пост был более года назад, всеравно напишу свой вопрос здесь, потому что иду  к своей цели своей тропинкой, в свободное от работы семьи время : 0)

ковыряю сейчас библиотеку OneWire , мне нужно обратится к конкретному датчику DS18B20 по его адресу,

 вставляю в  myWire.select(addrArray) адрес датчика показывает температуру - 127.

http://www.pjrc.com/teensy/td_libs_OneWire.html -тут пишут myWire.select(addrArray) это команда выбора устройства по адресу

адрес в 0х пишу

 в скобках массив адресов написано но массив по синтаксису в квкадратных скобках

подскажите как правильно обратится

 
 
 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

georgo пишет:

подскажите как правильно

Правильно посмотреть в текст библиотеки. Открываем и смотрим

//
// Do a ROM select
//
void OneWire::select(const uint8_t rom[8])
{
    uint8_t i;

    write(0x55);           // Choose ROM

    for (i = 0; i < 8; i++) write(rom[i]);
}

 

т.е., функция принимает один параметр - массив из восьми байтов.

georgo
Offline
Зарегистрирован: 06.09.2016

Цитата:
т.е., функция принимает один параметр - массив из восьми байтов.

точно, один ваер ведь последовательный интерфейс, и поэтому байты через цикл вводятся, спасибо дошло

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

08  write(0x55);           // Choose ROM

подскажите, плиз

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так она же ВНЕ цикла и исполняется 1 раз. Цикл находится в строке 10.

georgo
Offline
Зарегистрирован: 06.09.2016

спасибо

orcsin
Offline
Зарегистрирован: 12.06.2015
OneWire sensors[3] = { OneWire(1), OneWire(2), OneWire(3) };

Это я осилил и успешно применяю. Но стал другой вопрос, как инициализировать двухмерный массив, типа такого...

OneWire sensors[3] [2] = ??? ;

уже нашёл ответ:

int[,] array2D2 = { {1, 2, 3}, {4, 5, 6} };

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

в сто пицотый раз про датчики температуры даллас. С ними часто бывают глюки,  особенно если пользователь малоопытный.  Будь то delay (750) в библиотеке даллас, который с ростом опыта начинает раздражать, или будь то некорректные -127 или 85 градусов показывает. Предлагаю на обозрение взаимодействие с датчиками следующим образом (см скетч).  Из всех способов, которые я пробовал, так меньше всего глюков. Потому что проверяется контрольная сумма данных от датчика, и если она некорректна, данные этого конкретного измерения не учитываются. Задержки в виде delay при измерениях отсутствуют. 

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

Может кому будет полезно, ну и критика тоже приветствуется. 

#define Dallas_pin 3      // пин датчиков DS18B20

#include <OneWire.h>      // библиотека для устройств даллас 1-wire 
OneWire ds(Dallas_pin);   // датчики DS18B20 на такойто пин
#include <avr/pgmspace.h> // библиотека прогмем (для хранения названий температур во флеш, а не в ОЗУ)

uint32_t prev_dallas = 0;    // для таймера периодического обновления температур
uint32_t current_millis = 0; // снимок системного времени

uint16_t update_period = 5000; // интервал опроса датчиков (*2, т.е. в данном случае раз в 10сек)

// ниже перечисление нужных нам температур (в конце это размер массива температур)
enum TempC {
Vyhlop, 
Engine, 
Ulica, 
Salon, 

size_arrayTemp  
           }; 

// ниже это строки-названия температур (хранится будут в прогмем, т.е. во флеш, а не ОЗУ)
const char Vyhlop_Str[] PROGMEM = "Vyhlop "; 
const char Engine_Str[] PROGMEM = "Engine ";   
const char Ulica_Str[]  PROGMEM = "Ulica ";   
const char Salon_Str[]  PROGMEM = "Salon ";   

// ниже располагаем строки прогмем в массиве в том же порядке, что и enum температур чуть выше.
const char* const string_table[] PROGMEM = {
Vyhlop_Str, 
Engine_Str, 
Ulica_Str, 
Salon_Str 
};

#define  BUF_LENGTH 40
char buf[BUF_LENGTH]; // буфер для работы прогмем, если нужны строки более 40 символов каждая, тогда ставим бОльшее значение

// ниже массив температур. Указано соответствие адресов датчиков различным температурам, порядок расположения температур (строк) не важен 
// в массиве сначала адрес датчика, затем какой температуре он соответствует, затем сама переменная температуры (изначально =20*С)
byte DS18B20 [size_arrayTemp][10] = {
{0x28, 0xFF, 0xD3, 0xE2, 0xC1, 0x17, 0x04, 0x0D, Engine,  20}, 
{0x28, 0xFF, 0x3F, 0xB7, 0xC1, 0x17, 0x05, 0xF1, Salon,   20},
{0x28, 0xFF, 0xF8, 0xBC, 0xC1, 0x17, 0x04, 0x48, Ulica,   20},  
{0x28, 0xFF, 0xB2, 0xB5, 0xC1, 0x17, 0x05, 0xD1, Vyhlop,  20} 
};


uint32_t prev = 0; // для таймера  - периодический пример работы с температурами

void setup() {
  Serial.begin (9600);

 }

void loop() {
current_millis = millis();


if (current_millis - prev>5000) {

// ниже пример использования сразу всех температур массива в цикле фор
  for (byte i = 0; i<size_arrayTemp; i++) {Serial.print (NameTemper(DS18B20[i][8])); Serial.print ((int8_t)DS18B20[i][9]); Serial.println (F("*C"));}
  Serial.println();

// а также примеры как работать с одной определённой температурой из массива 

   Serial.print (NameTemper(Engine)); Serial.println(Temper(Engine));
  
if (Temper(Ulica)==0) {Serial.print (NameTemper(Ulica)); Serial.println(Temper(Ulica));}
  Serial.println();  
  prev = current_millis;  
                                }

dallas_update (); // вызов функции обновления температур 
}



// ниже функция обновления температур 

void dallas_update (){

if (current_millis-prev_dallas>update_period){
static bool n=0;        // флаг работы: запрос температуры или её чтение
n=!n;
if (n) {ds.reset();     // сброс шины
        ds.write(0xCC); // обращение ко всем датчикам
        ds.write(0x44); // начать преобразование (без паразитного питания)  
       }
else   {
  for (byte i=0; i<size_arrayTemp; i++){  //цикл обновления всех температур массива
    int Temper_ = -124; byte buff[9];
    ds.reset();
    ds.select(DS18B20[i]);
    ds.write(0xBE);                             // чтение регистров датчиков
    for (byte j=0; j<9; j++) buff[j]=ds.read(); // читаем все 9 байт от датчика
    ds.reset();
    if (OneWire::crc8(buff, 8) == buff[8]){     // если контрольная сумма совпадает 
          Temper_ = buff[0]|(buff[1]<<8);       // то читаем температуру из первых двух байт (остальные были нужны только для проверки CRC)
          Temper_ = Temper_ / 16;
          if (Temper_<150 && Temper_>-55) DS18B20[i][9] = Temper_;
}}}

prev_dallas=current_millis;
}}

// ниже функция поиска нужной температуры в массиве, если не найдено: возвращает значение -99 градусов. 
int8_t Temper (const byte &addressTemp)  {for(byte j=0; j<size_arrayTemp; j++){if(DS18B20[j][8]==addressTemp) return(int8_t)DS18B20[j][9];}return-99;}

// ниже функция возвращает из прогмем название температуры в виде строки 
char *NameTemper (const byte &Str_nomer) {strcpy_P(buf, (char*)pgm_read_word(&(string_table[Str_nomer])));return buf; }