Замирание всего кода из-за ds18b20

ergeykl
Offline
Зарегистрирован: 20.04.2017

Коллеги, добрый день!

Вероятно данный вопрос поднимался, но через поиск подобной темы я не нашел.

Уровень моих познаний в программировании это "Реле - вкл, подождать 2 сек, реле - выкл, подождать 2 сек" :)

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

Использую стандартные библиотеки OneWire и DallasTemperature. Я так понимаю что DallasTemperature использует задержку delay и из-за этого весь код останавливается в момент считывания температуры.

Сделал простенький код, как тестовый, и вместо плавной работы ШИМ по таймеру millis - 30 миллисекунд, происходит какое то импульсное "пускание" ШИМ сигнала.

#include <Wire.h>                   // Будим интерфейс I2C

#include <iarduino_MultiServo.h>    // Библиотека на ШИМ модуль PCA9685
iarduino_MultiServo PCA9685;        // Объявляем объект PCA9685, для работы с библиотекой


#include <OneWire.h>

#include <DallasTemperature.h>      // Библиотека датчиков ds18b20


////////////////////////////////////DS18B20//////////////////////////////////////////////////
const byte ONE_WIRE_BUS = 0;        // Пин D3 к которому подключены все датчики температуры
OneWire oneWire(ONE_WIRE_BUS);      // Вход датчиков ds18b20 на пине D3
DallasTemperature ds(&oneWire);
/////////////////////////////////////////////////////////////////////////////////////////////



int brightness = 0;      // уставливаем начально значение яркости
int fadeAmount = 128;    // шаг приращения/убывания яркости
/////////////////////////////////////////////////////////////////////////////////////////////
unsigned long timing;
/////////////////////////////////////////////////////////////////////////////////////////////


DeviceAddress Temp1 = {0x28, 0xFF, 0x06, 0x3D, 0x82, 0x16, 0x05, 0x55};   // Адрес датчика температуры Т1 (D3) (1 полоска) (28 FF 6 3D 82 16 5 55)
DeviceAddress Temp2 = {0x28, 0xFF, 0x4E, 0x70, 0x84, 0x16, 0x05, 0x2E};   // Адрес датчика температуры Т2 (D3) (2 полоски) (28 FF 4E 70 84 16 5 2E)

DeviceAddress Temp3 = {0x28, 0xFF, 0x8A, 0x99, 0x84, 0x16, 0x05, 0xC9};   // Адрес датчика температуры Т3 (D3) (3 полоски) (28 FF 8A 99 84 16 5 C9)
DeviceAddress Temp4 = {0x28, 0xFF, 0x72, 0xF0, 0x02, 0x17, 0x03, 0xF8};   // Адрес датчика температуры Т4 (D3) (4 полоски) (28 FF 72 F0 2 17 3 F8)

DeviceAddress Temp7 = {0x28, 0xFF, 0x2A, 0x07, 0xC1, 0x16, 0x04, 0x54};   // Адрес датчика температуры Тбак (D3) (5 полосок) (28 FF 2A 7 C1 16 4 54)
DeviceAddress Temp13 = {0x28, 0xEE, 0xF7, 0xC7, 0x1D, 0x16, 0x01, 0x2E};  // Адрес датчика температуры Т13 (D3) (6 полосок) (28 EE F7 C7 1D 16 01 2E)

float T1;                  // Датчик температуры Т1 (подача ЦО)
float T2;                  // Датчик температуры Т2 (обратка ЦО)
float T3;                  // Датчик температуры Т3 (подача ЦО ТП)
float T4;                  // Датчик температуры Т4 (обратка ЦО ТП)
float T7;                  // Датчик температуры Т7 (подача ГВС)
float T13;                 // Датчик температуры Т13 (обратка ГВС)


void setup() {

Wire.begin();                       

Serial.begin(115200);

/////////////////////////////////////////PCA9685///////////////////////////////////////
  PCA9685.begin(0x40, 1000);   // Инициируем работу с PCA9685. На частоте сигнала ШИМ - 1000 Гц (по умолчанию 50 Гц), можно указать от 1 до 1526 Гц
/////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////DS18B20//////////////////////////////////////////////////
  ds.begin();            //включаем DS18B20
/////////////////////////////////////////////////////////////////////////////////////////////


}

void loop() {

ds.requestTemperatures();       // Считываем показания температуры 

/////////////////////////////////////////////////////////////////////////////////////////////
T1 = ds.getTempC(Temp1);                       // Датчик температуры Т1 (подача ЦО)
T2 = ds.getTempC(Temp2);                       // Датчик температуры Т2 (обратка ЦО)
T3 = ds.getTempC(Temp3);                       // Датчик температуры Т3 (подача ЦО ТП)
T4 = ds.getTempC(Temp4);                       // Датчик температуры Т4 (обратка ЦО ТП)
T7 = ds.getTempC(Temp7);                       // Датчик температуры Т7 (подача ГВС)
T13 = ds.getTempC(Temp13);                     // Датчик температуры Т13 (обратка ГВС)
/////////////////////////////////////////////////////////////////////////////////////////////


  Serial.print("brightness = "); 
  Serial.println(brightness); 


 if ( millis() - timing > 30 ){
  timing = millis(); 

  PCA9685.analogWrite(15, brightness);   // Изменяем яркость подсветки дисплея 1602
 
  brightness = brightness + fadeAmount;
 
  if (brightness == 0 || brightness == 4096) {
    fadeAmount = -fadeAmount ;
  }   

 }


 

}

И главный вопрос :)

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

Заранее благодарю!

Logik
Offline
Зарегистрирован: 05.08.2014

ergeykl пишет:

Использую стандартные библиотеки OneWire и DallasTemperature. Я так понимаю что DallasTemperature использует задержку delay и из-за этого весь код останавливается в момент считывания температуры.

Да. Тема настолько баянистая, что начинать обяснять снова - моральное преступление ;) Только в поиск Вам.

Andrey12
Andrey12 аватар
Offline
Зарегистрирован: 26.12.2014

Logik пишет:

Да. Тема настолько баянистая, что начинать обяснять снова - моральное преступление ;) Только в поиск Вам.

Logik да чтож так сразу.

http://arduino.ru/forum/programmirovanie/pochistil-sketch-primera-raboty...

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

b707
Offline
Зарегистрирован: 26.05.2017

ergeykl пишет:

Коллеги, добрый день!

Вероятно данный вопрос поднимался, но через поиск подобной темы я не нашел.

То ли не умеете искать. то ли вообще не искали.

Ищите лучше, совсем недавно было обсуждение как раз главного вашего вопроса - "Как сделать так, чтобы задержка при измерении температуры не мешала скетчу"

 

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

ergeykl пишет:

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

Само по себе считывание требует времени, отсюда и Ваши затыки.

Сделать можно так. 

Считываем без блокировки. Для этого

1. заводим переменную для температуры

2 запускаем считывание,

3. не ждём пока считается, а продолжаем заниматься своими делами

4. когда считалось обновляем переменную.

5. продолжаем заниматься своими делами, а через 30 сек. снова исполняем п.2

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

Ваша библиотека (DallasTemperature) вполне позволяет работать по такому сценарию.

Logik
Offline
Зарегистрирован: 05.08.2014

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

ergeykl пишет:

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

Само по себе считывание требует времени, отсюда и Ваши затыки.

Опять с херней влазите. Читайте даташит, считывание как и запуск преобразования пролетают очень быстро, десятки микросекунд. А цикл измерения и преобразования по умолчанию 750мсек. Оно и тормозит, кривая либа просто ждет эти 750мс.

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

Вы уже один раз облажались, когда утверждали, что от этих 750 мс в этой библиотеке нельзя избавиться, забыли? Опять неймётся в лужу сесть? Отвалите уж ...

А на досуге, откройте таки даташит и изучите матчасть, прежде чем языком молоть:

на стр. 1 "Converts 12-bit temperature to digital word in 750 ms (max.)"
на стр. 19 "Temperature conversion takes up to 750 ms."
 
Logik
Offline
Зарегистрирован: 05.08.2014

Склероз с фантазией - жуткая смесь ))) Свал нах! незафлужуй тему.

ergeykl
Offline
Зарегистрирован: 20.04.2017

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

Logik
Offline
Зарегистрирован: 05.08.2014

ergeykl пишет:

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

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

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

ergeykl пишет:

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

Не за что. Если потребуется пример неблокирующего вызова, обращайтесь.

ergeykl
Offline
Зарегистрирован: 20.04.2017

ЕвгенийП, я прошу прощения, но пример мне бы не помешал :D

Посмотрел пример кода при использовании только лишь библиотеки OneWire, ничего не выходит. Контроллер у меня esp8266, а пример Почистил скетч примера работы с DS18B20 из библы OneWire.. | Аппаратная платформа Arduino предназначен, вроде как, для ардуино.

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

Ну, пример вот он. С этой же библиотекой. Не знаю, как на есп - запустите. попробуйте.

Там, главное, основные моменты понять, а писать можно как хотите.

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

#include <OneWire.h>
#include <DallasTemperature.h>

#define SENSOR_PIN 6

OneWire oneWire(SENSOR_PIN);
DallasTemperature sensors(&oneWire);
DeviceAddress deviceAddress;


void setup(void) {
  Serial.begin(115200);
  Serial << "Non blocking Dallas Temperature Demo\n";
  sensors.begin();
  sensors.getAddress(deviceAddress, 0);
  sensors.setWaitForConversion(false);
}

void loop(void) {
	static bool didNotSendYet = true;
	static unsigned long start;
	if (didNotSendYet) {
		 start = millis();
		sensors.requestTemperaturesByAddress(deviceAddress); 
		didNotSendYet = false;
	} else if (sensors.isConversionAvailable(deviceAddress)) {
		const float temp = sensors.getTempC(deviceAddress);
		const unsigned long duration = millis() - start;
		Serial << "Temperature: " << temp << " (" << duration << " ms)\n"; 
		delay(2000);
		didNotSendYet = true;
	}
}

Смотрите на строки 16-18. Это нужно сделать.

А потом смотрите как

1. запустить измерение - в строке 26
2. проверить не готов ли результат - в строке 28
3. получить готовый результат - в строке 29

b707
Offline
Зарегистрирован: 26.05.2017

ergeykl пишет:

 

Контроллер у меня esp8266, а пример предназначен, вроде как, для ардуино.

смотрите код из сообщения #11 той же ветки, он попроще. без прерываний - и должен одинаково работать и на ардуине, и на ЕСП

ergeykl
Offline
Зарегистрирован: 20.04.2017

Сообразил таким образом. Ещё раз большое спасибо всем за помощь!

#include <OneWire.h>

OneWire ds(0); // 10 pin к которому подключен датчик DS18b20

byte addr1[8] = {0x28, 0xFF, 0x06, 0x3D, 0x82, 0x16, 0x05, 0x55};   // Адрес датчика температуры Т1 (D3) (1 полоска) (28 FF 6 3D 82 16 5 55)
byte addr2[8] = {0x28, 0xFF, 0x4E, 0x70, 0x84, 0x16, 0x05, 0x2E};   // Адрес датчика температуры Т2 (D3) (2 полоски) (28 FF 4E 70 84 16 5 2E)

byte addr3[8] = {0x28, 0xFF, 0x8A, 0x99, 0x84, 0x16, 0x05, 0xC9};   // Адрес датчика температуры Т3 (D3) (3 полоски) (28 FF 8A 99 84 16 5 C9)
byte addr4[8] = {0x28, 0xFF, 0x72, 0xF0, 0x02, 0x17, 0x03, 0xF8};   // Адрес датчика температуры Т4 (D3) (4 полоски) (28 FF 72 F0 2 17 3 F8)

byte addr7[8] = {0x28, 0xFF, 0x2A, 0x07, 0xC1, 0x16, 0x04, 0x54};   // Адрес датчика температуры Тбак (D3) (5 полосок) (28 FF 2A 7 C1 16 4 54)
byte addr13[8] = {0x28, 0xEE, 0xF7, 0xC7, 0x1D, 0x16, 0x01, 0x2E};  // Адрес датчика температуры Т13 (D3) (6 полосок) (28 EE F7 C7 1D 16 01 2E)



float T1; // Переменная в которой будет храниться полученная температура
float T2; // Переменная в которой будет храниться полученная температура
float T3; // Переменная в которой будет храниться полученная температура
float T4; // Переменная в которой будет храниться полученная температура
float T7; // Переменная в которой будет храниться полученная температура
float T13; // Переменная в которой будет храниться полученная температура



byte flagDallRead;

unsigned long timing;


void setup() {

Serial.begin(115200);
  
  ds.reset(); // сброс шины
  //  ds.select(addr2); //выставить адрес
  //  ds.write(0x4E); // разрешение записать конфиг
  //  ds.write(0x7F); // Th контроль температуры макс 128грд
  //  ds.write(0xFF); //Tl контроль температуры мин -128грд
  ds.write(0x5F); // точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F;
  
}

void loop() {  
  dallRead(flagDallRead*1000);

  
 if ( millis() - timing > 5000 ){
  timing = millis(); 

  Serial.print("Temp1 = "); 
  Serial.println(T1);
  Serial.print("Temp2 = "); 
  Serial.println(T2);
  Serial.print("Temp3 = "); 
  Serial.println(T3);
  Serial.print("Temp4 = "); 
  Serial.println(T4);
  Serial.println(" ");
  
 }

 
}

void dallRead(unsigned long interval){
  static unsigned long prevTime = 0;
  if (millis() - prevTime > interval) { //Проверка заданного интервала
    static boolean flagDall = 0; //Признак операции
    prevTime = millis();
    flagDall =! flagDall; //Инверсия признака
    if (flagDall) {
      ds.reset();
      ds.write(0xCC);   //Обращение ко всем датчикам
      ds.write(0x44);   //Команда на конвертацию
      flagDallRead = 2; //Время возврата в секундах
    } else {
      int Temp1;
      int Temp2;
      int Temp3;
      int Temp4;
      int Temp7;
      int Temp13;
      ds.reset();
      ds.select(addr1);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp1 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T1 = (float)Temp1 / 16.0;

      ds.reset();
      ds.select(addr2);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp2 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T2 = (float)Temp2 / 16.0;
      
      ds.reset();
      ds.select(addr3);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp3 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T3 = (float)Temp3 / 16.0;

      ds.reset();
      ds.select(addr4);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp4 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T4 = (float)Temp4 / 16.0;
      
      flagDallRead = 3; //Время возврата в секундах
    }
  }
}

Вроде работает :)

bwn
Offline
Зарегистрирован: 25.08.2014

ergeykl пишет:

Сообразил таким образом. Ещё раз большое спасибо всем за помощь!

#include <OneWire.h>

OneWire ds(0); // 10 pin к которому подключен датчик DS18b20

byte addr1[8] = {0x28, 0xFF, 0x06, 0x3D, 0x82, 0x16, 0x05, 0x55};   // Адрес датчика температуры Т1 (D3) (1 полоска) (28 FF 6 3D 82 16 5 55)
byte addr2[8] = {0x28, 0xFF, 0x4E, 0x70, 0x84, 0x16, 0x05, 0x2E};   // Адрес датчика температуры Т2 (D3) (2 полоски) (28 FF 4E 70 84 16 5 2E)

byte addr3[8] = {0x28, 0xFF, 0x8A, 0x99, 0x84, 0x16, 0x05, 0xC9};   // Адрес датчика температуры Т3 (D3) (3 полоски) (28 FF 8A 99 84 16 5 C9)
byte addr4[8] = {0x28, 0xFF, 0x72, 0xF0, 0x02, 0x17, 0x03, 0xF8};   // Адрес датчика температуры Т4 (D3) (4 полоски) (28 FF 72 F0 2 17 3 F8)

byte addr7[8] = {0x28, 0xFF, 0x2A, 0x07, 0xC1, 0x16, 0x04, 0x54};   // Адрес датчика температуры Тбак (D3) (5 полосок) (28 FF 2A 7 C1 16 4 54)
byte addr13[8] = {0x28, 0xEE, 0xF7, 0xC7, 0x1D, 0x16, 0x01, 0x2E};  // Адрес датчика температуры Т13 (D3) (6 полосок) (28 EE F7 C7 1D 16 01 2E)



float T1; // Переменная в которой будет храниться полученная температура
float T2; // Переменная в которой будет храниться полученная температура
float T3; // Переменная в которой будет храниться полученная температура
float T4; // Переменная в которой будет храниться полученная температура
float T7; // Переменная в которой будет храниться полученная температура
float T13; // Переменная в которой будет храниться полученная температура



byte flagDallRead;

unsigned long timing;


void setup() {

Serial.begin(115200);
  
  ds.reset(); // сброс шины
  //  ds.select(addr2); //выставить адрес
  //  ds.write(0x4E); // разрешение записать конфиг
  //  ds.write(0x7F); // Th контроль температуры макс 128грд
  //  ds.write(0xFF); //Tl контроль температуры мин -128грд
  ds.write(0x5F); // точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F;
  
}

void loop() {  
  dallRead(flagDallRead*1000);

  
 if ( millis() - timing > 5000 ){
  timing = millis(); 

  Serial.print("Temp1 = "); 
  Serial.println(T1);
  Serial.print("Temp2 = "); 
  Serial.println(T2);
  Serial.print("Temp3 = "); 
  Serial.println(T3);
  Serial.print("Temp4 = "); 
  Serial.println(T4);
  Serial.println(" ");
  
 }

 
}

void dallRead(unsigned long interval){
  static unsigned long prevTime = 0;
  if (millis() - prevTime > interval) { //Проверка заданного интервала
    static boolean flagDall = 0; //Признак операции
    prevTime = millis();
    flagDall =! flagDall; //Инверсия признака
    if (flagDall) {
      ds.reset();
      ds.write(0xCC);   //Обращение ко всем датчикам
      ds.write(0x44);   //Команда на конвертацию
      flagDallRead = 2; //Время возврата в секундах
    } else {
      int Temp1;
      int Temp2;
      int Temp3;
      int Temp4;
      int Temp7;
      int Temp13;
      ds.reset();
      ds.select(addr1);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp1 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T1 = (float)Temp1 / 16.0;

      ds.reset();
      ds.select(addr2);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp2 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T2 = (float)Temp2 / 16.0;
      
      ds.reset();
      ds.select(addr3);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp3 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T3 = (float)Temp3 / 16.0;

      ds.reset();
      ds.select(addr4);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp4 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T4 = (float)Temp4 / 16.0;
      
      flagDallRead = 3; //Время возврата в секундах
    }
  }
}

Вроде работает :)

Как раз в оригинале той функции ваш случай, чтобы сто раз клавиши не стучать, все в массивах и с циклами. Не лень повторять сто раз было?)))))

Logik
Offline
Зарегистрирован: 05.08.2014

ergeykl пишет:

Вроде работает :)

Чего бы ему не работать. Только вот проверки контрольной суммы не видно. А шина эта часто ошибки кидает. А чтоб ей считать надо не по 2 байта температуры принимать, а все 9 ответа.

ergeykl
Offline
Зарегистрирован: 20.04.2017

Коллеги, если Вас не затруднит, проведите, пожалуйста, свою экспертизу по коду. Как, по Вашему мнению, всё должно работать действительно правильно, с учётом особенностей шины на которую повешены дачики?

Заранее благодарю!

sadman41
Онлайн
Зарегистрирован: 19.10.2016

А чего ее проводить? Смысла никакого нет.

Вам уже написали, что CRC вы не проверяете - будете периодически получать недостоверную температуру. Датчики на отрыв/замыкание не проверяете, отрицательные температуры не корректируете.

 

bwn
Offline
Зарегистрирован: 25.08.2014

ergeykl пишет:

Коллеги, если Вас не затруднит, проведите, пожалуйста, свою экспертизу по коду. Как, по Вашему мнению, всё должно работать действительно правильно, с учётом особенностей шины на которую повешены дачики?

Заранее благодарю!

Сперва скажите, где это будет работать, а потом уже решать, нужен ли весь этот тюнинг в "Московском зоопарке". Мне пока не понадобился. ИМХО.

Строки 34, 39 закомментируйте, уберите все в массивы и цикл. Если навороты потребуются их без проблем можно добавить.

ergeykl
Offline
Зарегистрирован: 20.04.2017

bwn, данная часть кода будет работать на благо комфортной температуры в загородном доме. Планируется, в будущем, сделать погодозависимый регулятор. В зависимости от температуры наружного воздуха будет производиться воздействия на котельный агрегат (какое воздействие  пока что не определился, пока что в планах ШИМ, но там сплошные костыли). Соответственно, в зависимости от показаний датчика температуры наружного воздуха и датчиков температуры в разных участках системы (Т2, Т4, Т13), будет производиться воздействие на котёл.

А что касается кода, не совсем понял. Вы имеете ввиду убрать все глобальные переменные в массивы и цикл?

#include <OneWire.h>

OneWire ds(0); // 0 pin к которому подключен датчик DS18b20

byte flagDallRead;

unsigned long timing;

byte addr1[8] = {0x28, 0xFF, 0x06, 0x3D, 0x82, 0x16, 0x05, 0x55};   // Адрес датчика температуры Т1 (D3) (1 полоска) (28 FF 6 3D 82 16 5 55)
byte addr2[8] = {0x28, 0xFF, 0x4E, 0x70, 0x84, 0x16, 0x05, 0x2E};   // Адрес датчика температуры Т2 (D3) (2 полоски) (28 FF 4E 70 84 16 5 2E)

byte addr3[8] = {0x28, 0xFF, 0x8A, 0x99, 0x84, 0x16, 0x05, 0xC9};   // Адрес датчика температуры Т3 (D3) (3 полоски) (28 FF 8A 99 84 16 5 C9)
byte addr4[8] = {0x28, 0xFF, 0x72, 0xF0, 0x02, 0x17, 0x03, 0xF8};   // Адрес датчика температуры Т4 (D3) (4 полоски) (28 FF 72 F0 2 17 3 F8)

//byte addr7[8] = {0x28, 0xFF, 0x2A, 0x07, 0xC1, 0x16, 0x04, 0x54};   // Адрес датчика температуры Тбак (D3) (5 полосок) (28 FF 2A 7 C1 16 4 54)
//byte addr13[8] = {0x28, 0xEE, 0xF7, 0xC7, 0x1D, 0x16, 0x01, 0x2E};  // Адрес датчика температуры Т13 (D3) (6 полосок) (28 EE F7 C7 1D 16 01 2E)

float T1; // Переменная в которой будет храниться полученная температура
float T2; // Переменная в которой будет храниться полученная температура
float T3; // Переменная в которой будет храниться полученная температура
float T4; // Переменная в которой будет храниться полученная температура
//float T7; // Переменная в которой будет храниться полученная температура
//float T13; // Переменная в которой будет храниться полученная температура

void setup() {

Serial.begin(115200);

  //  ds.reset(); // сброс шины
  //  ds.select(addr2); //выставить адрес
  //  ds.write(0x4E); // разрешение записать конфиг
  //  ds.write(0x7F); // Th контроль температуры макс 128грд
  //  ds.write(0xFF); // Tl контроль температуры мин -128грд
  //  ds.write(0x5F); // точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F;

}

void loop() {  

  dallRead(flagDallRead*1000);

 if ( millis() - timing > 5000 ){
  timing = millis(); 

  Serial.print("Temp1 = "); 
  Serial.println(T1);
  Serial.print("Temp2 = "); 
  Serial.println(T2);
  Serial.print("Temp3 = "); 
  Serial.println(T3);
  Serial.print("Temp4 = "); 
  Serial.println(T4);
  Serial.println(" ");

 }

}

void dallRead(unsigned long interval){
  
  static unsigned long prevTime = 0;
  if (millis() - prevTime > interval) { //Проверка заданного интервала
    static boolean flagDall = 0; //Признак операции
    prevTime = millis();
    flagDall =! flagDall; //Инверсия признака
    if (flagDall) {
      ds.reset();
      ds.write(0xCC);   //Обращение ко всем датчикам
      ds.write(0x44);   //Команда на конвертацию
      flagDallRead = 2; //Время возврата в секундах
    } else {
      int Temp1;
      int Temp2;
      int Temp3;
      int Temp4;
//      int Temp7;
//      int Temp13;
      ds.reset();
      ds.select(addr1);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp1 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T1 = (float)Temp1 / 16.0;

      ds.reset();
      ds.select(addr2);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp2 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T2 = (float)Temp2 / 16.0;
      
      ds.reset();
      ds.select(addr3);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp3 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T3 = (float)Temp3 / 16.0;

      ds.reset();
      ds.select(addr4);
      ds.write(0xBE);     //Считывание значения с датчика
      Temp4 = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      T4 = (float)Temp4 / 16.0;
      
      flagDallRead = 3; //Время возврата в секундах
    }
  }
}

 

b707
Offline
Зарегистрирован: 26.05.2017

Все однотипные переменные, относящиеся к датчикам - оформить как массивы. Тогда вместо 4х одинаковых кусков кода для каждого датчика можно будет выполнять один и тот же код в цикле. Общий размер программы уменьшится, конечно не в 4 раза, но в два точно.

Пример

float T[4];

void loop() {  

  dallRead(flagDallRead*1000);

 if ( millis() - timing > 5000 ){
  timing = millis(); 

  for byte k =0; k < 4; k++) {
  Serial.print("Temp"); 
  Serial.print(k);
  Serial.print(" = "); 
  Serial.println(T[k]);
  }
 }

}

 

bwn
Offline
Зарегистрирован: 25.08.2014

const byte addr[x][8] = {{0x......},{0x.........}....};
float[x]; - это глобально.
флоат не обязателен, тут сами решайте как удобнее.

А кусок с 72 строки заверните в фор, как у меня в функции сделано.
Система подогрева от электронагревателей в овощехранилище у меня четвертый год 365/24 работает без проверок, пока не сбоила. У дальнего датчика электролит (хотя линии короткие).
Делайте пока как есть, а понадобятся проверки, добавить всегда без проблем. ИМХО.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

У вас всего 5 датчиков.
Скорее всего они идут в разные стороны, а не вдоль какой-то линии.
Какой смысл подключать их на один пин?
Подключите на 5 разных.
Подпишите клеммник ху-ис-ху.
Отпадёт необходимость считывать и забивать в программе их адреса.
Замена датчиков производится способом их замены.
Без перепрошивки контроллера.
Вы же не макет делаете, а устройство для долгой и надеждой эксплуатации.
При проблеммах с проводами сразу видно где это.

ergeykl
Offline
Зарегистрирован: 20.04.2017

trembo, Вашу мысль понял. Можете разьяснить, если мы вешаем 6 датчиков на клеммник, потом, скажем, 4ый выходит из строя, и я его заменяю. То не собъётся ли номера датчиков? Я имею ввиду что до поломки, например, Т1 был Темп1 Т2 был Темп2 и т.д. а после замены станет Т1 это Темп4. И мне не совсем понятно как ссылаться, например, на значение Т1 в функции ЛУП если оно не прописано глобально, если ипользовать код который предложил b707 в #21 посте?

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Не вводятся там номера датчиков от слова совсем.
Работает с любым что воткнули.

bwn
Offline
Зарегистрирован: 25.08.2014

Если по коду из 21 поста, то Т объявлен глобально, а адресация T[0], T[1] и т.д. Почитайте про массивы.

ergeykl
Offline
Зарегистрирован: 20.04.2017

bwn пишет:

Если по коду из 21 поста, то Т объявлен глобально, а адресация T[0], T[1] и т.д. Почитайте про массивы.

bwn, спасибо Вам! Огромное, человеческое спасибо!

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Попробуйте мою давнюю заготовку.
Надеюсь  все будет понятно.

A1 и  A2  - пины датчиков

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS_WATER_PIN    A1  // water sensor pin
#define ONE_WIRE_BUS_OUTDOOR_PIN  A2  //outdoor air sensor pin
#define TEMPERATURE_PRECISION 9

OneWire oneWireWaterSensor(ONE_WIRE_BUS_WATER_PIN);
DallasTemperature waterSensor(&oneWireWaterSensor);

OneWire oneWireOutdoorSensor(ONE_WIRE_BUS_OUTDOOR_PIN);
DallasTemperature outdoorSensor(&oneWireOutdoorSensor);

float outdoorTemp ;         // Outdoor air temperature sensor value
float waterTemp ;         //water temperature sensor value
//==========================================================================
void setup() {
  Serial.begin(115200);
  waterSensor.begin();
  outdoorSensor.begin();
  waterSensor.setResolution(TEMPERATURE_PRECISION);
  outdoorSensor.setResolution(TEMPERATURE_PRECISION);

}
//=========================================================================
void GetWaterTemp () {
  waterSensor.requestTemperatures(); // Send the command to get temperatures
  waterTemp = waterSensor.getTempCByIndex(0);
  Serial.print("Water temperature = ");
  Serial.print(waterTemp, 1);
  Serial.print((char)223);
  Serial.println("C");
}
//==========================================================================
void GetOutdoorTemp () {
  outdoorSensor.requestTemperatures(); // Send the command to get temperatures
  outdoorTemp = outdoorSensor.getTempCByIndex(0);
  Serial.print("Outdoor  temperature = ");
  Serial.print(outdoorTemp, 1);
  Serial.print((char)223);
  Serial.println("C   ");
}
//===========================================================================
void loop() {
  GetWaterTemp ();
  GetOutdoorTemp ();
  delay(1000);
}



 

bwn
Offline
Зарегистрирован: 25.08.2014

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

bwn
Offline
Зарегистрирован: 25.08.2014

trembo пишет:

Попробуйте мою давнюю заготовку.
Надеюсь  все будет понятно.

A1 и  A2  - пины датчиков

У ТС с проблемы делаев топик начинался, а у Вас она вроде в полный рост?

ergeykl
Offline
Зарегистрирован: 20.04.2017

И то верно. В любом случае буду пробовать все предложенные методы. Ещё раз ВСЕМ огромное спасибо!

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

bwn пишет:

У ТС с проблемы делаев топик начинался, а у Вас она вроде в полный рост?

Это проба, я так и написал, работы с двумя датчиками
на разных пинах  и без ввода их адресов.
Что-то типа "ДЭМО"
Для понятия идеи.
Дэлэй для того чтобы  на мельтешило в сериал мониторе.

Logik
Offline
Зарегистрирован: 05.08.2014

Вобще легкая замена возможна и при топологии общей шины. Но надо реализовать поиск датчиков на шине. А адреса в EEPROM хранить. Если при очередном поиске появился новый адрес, а исчез один из старых - значить произошла замена, корректируем адрес в EEPROM. Общая шина позволяет легко добавить новые датчики в сеть, что особо актуально если нет четкого проекта решения и походу вдруг надо мерить еще чтото гдето.

Logik
Offline
Зарегистрирован: 05.08.2014

trembo пишет:

Это проба, я так и написал, работы с двумя датчиками

на разных пинах  и без ввода их адресов.

Чего его пробовать, работать без адреса совсем чутчуть проще чем с адресом. подали 0xcc - любой должен выполнить, а 0x55+8 байт адреса - только адресуемый. У ТС кстати тоже есть обращение без адреса - команда на конвертацию.

bwn
Offline
Зарегистрирован: 25.08.2014

Logik пишет:

Но надо реализовать поиск датчиков на шине. А адреса в EEPROM хранить. Если при очередном поиске появился новый адрес, а исчез один из старых - значить произошла замена, корректируем адрес в EEPROM. 

Это пока не для ТС задача.((((

Logik
Offline
Зарегистрирован: 05.08.2014

Не факт. Самому писать поиск тяжко, но готовую реализацию поиска можна выдрать из чужего кода, из либы например. Както ж ТС  адреса своих датчиков получил ;) К тому же разумно поиск делать разово при включении, а там можна и делеев не боятся. А остальное (читать писать EEPROM и сравнивать адреса) примитивщина. Если это не уметь (или не научится) - нехрен братся за озвученый проект.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

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

Logik
Offline
Зарегистрирован: 05.08.2014

Можна менять любое кол-во, но по одному. Замена датчиков очень редкий случай в процессе эксплуатации и зацикливатся на нем не стоит. Бегать и ребутить не надо, надо выключить, заменить датчик и включить. Ни одного лишнего действия. Рескан шины в процессе работы - излишество сложное, безсмысленое и из-за этого вредное. 

sadman41
Онлайн
Зарегистрирован: 19.10.2016

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

Logik
Offline
Зарегистрирован: 05.08.2014

///С чего это оно сложное, бессмысленное и вредное? 

Сложной - алгоритм сложный и реализуется блокирующим кодом, а значить в процессе работы будут те самые замирания. И шина в это время не может быть задействована по прямому назначению. Вам известна неблокирующая быстрая реализация  - показывайте! Безсмысленым - замена датчиков процесс очень редкий при корректном построении сети.  Например у меня за 5 лет ниразу не требовался. Все 100% живы- здоровы, единственная проблема - исчезает контакт если провод разорвать;) Зачем писать и  исполнять код  не дающий результата. А вредное - из-за вышеизложеного: отнимает ресурсы у разраба и контролера и не дает результата, т.к. проблема очень редкая.

Какое нафиг "неопределенного поведения", "датчики будут договариваться", "двойное резервирование не всегда является гарантией" и "исполнение инструкций людьми "? В не туда попали, здесь не сказки и не аэрокосмические системы. 

ПС. Тема начинает отдавать шизофренией, одному CRC излишне другому двойное резервирование недостаточно, для одного поиск датчиков на шине - слишком сложно, другому реалтаймом он необходимо. Вы там, пацаны, междусобой както договоритесь;) А я пока пожру пойду.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Не стоит забывать тот факт, что разработчик понимает, почему нужно менять по одному датчику, каждый раз выключая и включая блок управления. У копировщика кода такого понимания нет и замена сразу двух датчиков будет для него крайне оптимальной операцией. Законы Мерфи написаны как раз для таких случаев. Почитайте.

Впрочем, я чую, что тут начинается бессмысленный срач в попытке доказать, что "я пять лет МКАД перебегал и ничего страшного", посему предпочту в нем не участвовать, а сходить в кино. 

Неблокирующий (на время проведения конверсии) код вам уже, как я помню, ЕвгенийП демонстрировал. Не вижу смысла повторяться.

ssss
Offline
Зарегистрирован: 01.07.2016

Logik пишет:

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

На STM TIM+DMA !!!

Быстрая и практически не блокирующая.

Цитата:

Безсмысленым - замена датчиков процесс очень редкий при корректном построении сети. 

Для этого достаточно отдать ещё один пин, к которому и тыкать новые датчики для опознавания системой, если уж совсем лень все датчики разделять изначально.

Logik
Offline
Зарегистрирован: 05.08.2014

//Неблокирующий (на время проведения конверсии) код вам уже, как я помню, ЕвгенийП демонстрировал. Не вижу смысла повторяться.

Свинорыл пока только свою ограниченость продемонстрировал попутав время преобразования (750мсек) и время считывания (60мксек на бит) ))) А Вы только что попутали код "проведения конверсии" и код поиска датчика. И стояло из-за этого в тему влазить? Лучше бы сразу в кино.

ПС. Последние "Звездные войны" не стоят того чтоб в кино перется.

Logik
Offline
Зарегистрирован: 05.08.2014

Дадада!! Только эсесовца тут не хватало ))))

Пропала тема.

Напоследок напишу, может ТС заинтересует, что в крайних своих поделках зачастую разделяю скетч на два. Один конфигурирует, настраивает, проверяет и создает все что можна и нужно, в т.ч. и список датчиков в EEPROM. В нем же и отлаживается переферия, библиотеки и т.д. Второй - основной рабочий с разумным минимумом настроек. Замена датчиков разумеется в первом. Т.к. предусматривать возмость прошивки даже в готовом устройстве всеравно нужно, то такой подход радует.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

У женской логики что - обострение сегодня? Эко разбушевался, так и льётся изо всех щелёнок чсв :) :) :)

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

sadman41, прекращайте спорить с полуграмотным википедиком. Это бесполезно - он всегда и во всём прав! Когда я его вчера ткнул носом в даташит, так он просто послал меня нах и опять же оказался победителем на белом коне! Ну, поймите, человек прав всегда! Что Вы пытаетесь ему доказать? Это ж как с голубем в шахматы играть!

bwn
Offline
Зарегистрирован: 25.08.2014

Logic, где я сказал, что CRC излишне? Я сказал, что за три и четыре года эксплуатации двух девайсов нужды в этой фиче не возникло. Последует ТС моему личному опыту (заметьте, не совету)  или нет, решать ему, что то навязывать или кого то убеждать не собираюсь, это жизненный принцип. Здесь вроде взрослые дядьки собрались, которые могут сами решить вопрос о критичности и последствиях возникшей ошибки. ИМХО.

Logik
Offline
Зарегистрирован: 05.08.2014

От такой разговор по существу)))

Только цитаты.

Logik пишет:

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

ergeykl пишет:

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

Само по себе считывание требует времени, отсюда и Ваши затыки.

Опять с херней влазите. Читайте даташит, считывание как и запуск преобразования пролетают очень быстро, десятки микросекунд. А цикл измерения и преобразования по умолчанию 750мсек. Оно и тормозит, кривая либа просто ждет эти 750мс.

All read time slots must be a minimum of 60μs

Temperature conversion!!!!!!! takes up to 750 ms!!!!!!!

Не? не различаеш?

Ну и ладно ТС уже различил и скетч зделал.

ПС. Послал - чего вернулись? Идитет дальше, там заждались ;)

 
Logik
Offline
Зарегистрирован: 05.08.2014

bwn пишет:

Logic, где я сказал, что CRC излишне? 
 
 

bwn пишет:

Сперва скажите, где это будет работать, а потом уже решать, нужен ли весь этот тюнинг в "Московском зоопарке". Мне пока не понадобился. 

Надобность проверок CRC вобщето не обсуждается. Их всегда проверяют, она для того и создана и посчитана.  Просто тяжело обяснять одному человеку почему CRC надо проверять, а другому рассказывать почему датчики у нормальных людей редко выходят из строя и заменяются. Это две крайности в представлении о системе, Вы считаете что никогда не сбойнет, а sadman41 постоянный поиск заменяемого датчика да двойное резервирование и гарячую замену считает нужным. Плюс учесть что эксплуатирует идиот безграмотный. Это кто? ТС наверное? ;)  

 Я пытаюсь ТС удержать от этих крайностей в рамках разумного подхода. Тож по софту: одному реализовать поиск датчика - запредельно сложно кажется, другой его реалтайм предлагает (правда тут же путает поиск и опрос :), а я представляю последствия и опять же неопытному ТС советую делать, но без фанатизма.

bwn
Offline
Зарегистрирован: 25.08.2014

Logik пишет:

Это две крайности в представлении о системе, Вы считаете что никогда не сбойнет, а sadman41 постоянный поиск заменяемого датчика да двойное резервирование и гарячую замену считает нужным. Плюс учесть что эксплуатирует идиот безграмотный. Это кто? ТС наверное? ;)  

 Я пытаюсь ТС удержать от этих крайностей в рамках разумного подхода. Тож по софту: одному реализовать поиск датчика - запредельно сложно кажется, другой его реалтайм предлагает (правда тут же путает поиск и опрос :), а я представляю последствия и опять же неопытному ТС советую делать, но без фанатизма.

Я не считаю, что никогда на сбойнет, просто последствия разового сбоя минимальны и смысл его отслеживания теряется. Если что то делаю в другие руки (это очень редко), там да и контроль и алярм и новогодняя елка, а может и принудительное отключение. Запись, сверка, принадлежность датчика были, во второй версии просто выкинул за ненадобностью, если отвалится, я это и так увижу и полезу с паяльником, а там и перезалить быстрее, чем их зажигалкой по очереди греть. Опять таки, личные выводы и предпочтения. Для серийной продукции такие методы не подходят.