Два DS1820, не корректные показания, помогите разобраться.

AvtoRemGarage
Offline
Зарегистрирован: 26.02.2016

Добрый день, я тут новичок, да и вообще только начал изучение ардуино.

Пытаюсь вытянуть температуру с двух датчиков DS1820, по некоторым библиотекам определяется как DS18S20, что в общем то одно и тоже.

Суть проблеммы, подключил датчики к Нано, тремя проводами, с сопративлением, скетчем из Даллосовской библиотеки(мультипл) проверяю адреса датчиков, всё показывает, и адреса и корректную температуру, затем делаю другой скетч, по примерам из тем, показания отправляю на LCD и в сериалпорт. Показания идут с обоих датчиков, но не корректные, занижены в десятки раз, и даже не понятно на сколько именно.



Пробылвал смотреть показания с отключенным датчиком, на даллосовской библиотеке начинает показывать -127 градусов, это я так понимаю всё правильно. А на моём скетче показывает 4095,94 при отключенном датчике.



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

#include <OneWire.h>
#include <Wire.h>                // I2C
#include <LiquidCrystal_I2C.h>   // LCD

OneWire ds (10);
byte data[12];
byte addr1[8] = {0x10, 0x40, 0xDF, 0xD7, 0x01, 0x08, 0x00, 0xE5};   // ID индивидуально для каждого датчика
byte addr2[8] =  {0x10, 0x3F, 0xD3, 0xD7, 0x01, 0x08, 0x00, 0x78};
unsigned int raw;
float temp1, temp2;



LiquidCrystal_I2C lcd(0x27, 16, 2);



void setup()
{
  Wire.begin();
  lcd.init();
  lcd.backlight(); // вкл. подсветку LCD (noBack-выкл)
  lcd.clear();
  Serial.begin(9600);
}

void loop()
{
  temp1 = DS18B20(addr1);
  temp2 = DS18B20(addr2);

 
  Serial.println(temp1);
  Serial.println(temp2);

  lcd.setCursor(6, 0);
  
  lcd.print(temp1); // отображение температуры
  
  lcd.setCursor(6, 1);
  
  lcd.print(temp2); // отображение температуры
  
}

//==================================================================================
//                            Считывание температуры
//==================================================================================
float DS18B20(byte *adres){
{
  ds.reset();
  ds.select(adres);
  ds.write(0x44); // start conversion, with parasite power on at the end
  ds.reset();
  ds.select(adres);
  ds.write(0xBE); // Read Scratchpad

  for (byte s = 0; s < 9; s++) // можно увеличить точность измерения до 0.0625 *С (от 9 до 12 бит)
  
  data[s] = ds.read ();
  
  raw =  (data[1] << 8) | data[0];//=======Пересчитываем в температуру
  float celsius =  (float)raw / 16.0;
  return celsius;
}}

 

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

А задержку на конвертацию, дядя будет ставить?

AvtoRemGarage
Offline
Зарегистрирован: 26.02.2016
#include <OneWire.h>
#include <Wire.h>                // I2C
#include <LiquidCrystal_I2C.h>   // LCD

OneWire ds (10);
byte data[12];
byte addr1[8] = {0x10, 0x40, 0xDF, 0xD7, 0x01, 0x08, 0x00, 0xE5};   // ID индивидуально для каждого датчика
byte addr2[8] =  {0x10, 0x3F, 0xD3, 0xD7, 0x01, 0x08, 0x00, 0x78};
unsigned int raw;
float temp1, temp2;



LiquidCrystal_I2C lcd(0x27, 16, 2);



void setup()
{
  Wire.begin();
  lcd.init();
  lcd.backlight(); // вкл. подсветку LCD (noBack-выкл)
  lcd.clear();
  Serial.begin(9600);
}

void loop()
{
  temp1 = DS18B20(addr1);
  temp2 = DS18B20(addr2);

 
  Serial.println(temp1);
  Serial.println(temp2);

  lcd.setCursor(6, 0);
  
  lcd.print(temp1); // отображение температуры
  
  lcd.setCursor(6, 1);
  
  lcd.print(temp2); // отображение температуры
  
}

//==================================================================================
//                            Считывание температуры
//==================================================================================
float DS18B20(byte *adres){
{
  ds.reset();
  ds.select(adres);
  ds.write(0x44); // start conversion, with parasite power on at the end
  delay(1000);
  ds.reset();
  ds.select(adres);
  ds.write(0xBE); // Read Scratchpad

  for (byte s = 0; s < 9; s++) // можно увеличить точность измерения до 0.0625 *С (от 9 до 12 бит)
  
  data[s] = ds.read ();
  
  raw =  (data[1] << 8) | data[0];//=======Пересчитываем в температуру
  float celsius =  (float)raw / 16.0;
  return celsius;
}}

Не помогает и задержка, или не туда добавляю задержку?

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

Попробуйте 33  строку вставить после 64.

P/S Ессно temp1 заменить на celsius.

alex_r61
Offline
Зарегистрирован: 20.06.2012

Вы говорите про 18S20, а скетч приводите для 18B20. У этих датчиков разное разрешение и пересчет показаний будет по разному.

AvtoRemGarage
Offline
Зарегистрирован: 26.02.2016

Ближе к истине, не нашел другомго пересчета, не поможете.

Скетч облегчил. 

#include <OneWire.h>

OneWire ds (10);
byte data[12];
byte addr1[8] = {0x10, 0x40, 0xDF, 0xD7, 0x01, 0x08, 0x00, 0xE5};   // ID индивидуально для каждого датчика
byte addr2[8] =  {0x10, 0x3F, 0xD3, 0xD7, 0x01, 0x08, 0x00, 0x78};
unsigned int raw;
float temp1, temp2;

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

void loop()

{
  temp1 = DS1820(addr1);
  temp2 = DS1820(addr2);
  
  Serial.println(temp1);
  Serial.println(temp2);
  
}

//==================================================================================
//                            Считывание температуры
//==================================================================================

float DS1820(byte *adres)

{ ds.reset();
  ds.select(adres);
  ds.write(0x44,0); 
 
  ds.reset();
  ds.select(adres);
  ds.write(0xBE); 


  for (byte i = 0; i < 9; i++) 
  data[i] = ds.read ();
  
  
  raw =  (data[1] << 8) | data[0];
  float celsius =  (float)raw / 16.0;
  
  return celsius;
  
}

 

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

Согласен с alex_r61, S-ки в руки не попадали, не обратил внимания. Открывайте пример из OneWire - DS18x20 Temperature.
Он в

  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];

 

AvtoRemGarage
Offline
Зарегистрирован: 26.02.2016

Вот като так получилось, вроде корректно показывает температуру , и без паузы после запроса. ничего конечно не понял в этих строчках 44-45-46, особенно не понятно что такое data[0] и  [6], и что такое int16_t.

Есть какие нибудь замечания по преобразованию?

#include <OneWire.h>

OneWire ds (10);
byte data[12];
byte addr1[8] = {0x10, 0x40, 0xDF, 0xD7, 0x01, 0x08, 0x00, 0xE5};   // ID индивидуально для каждого датчика
byte addr2[8] =  {0x10, 0x3F, 0xD3, 0xD7, 0x01, 0x08, 0x00, 0x78};
unsigned int raw;
float temp1, temp2;

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

void loop()

{
  temp1 = DS1820(addr1);
  temp2 = DS1820(addr2);
  
  Serial.println(temp1);
  Serial.println(temp2);
  
}

//==================================================================================
//                            Считывание температуры
//==================================================================================

float DS1820(byte *adres)

{ ds.reset();
  ds.select(adres);
  ds.write(0x44,0); 
 
  ds.reset();
  ds.select(adres);
  ds.write(0xBE); 


  for (byte i = 0; i < 9; i++) 
  data[i] = ds.read ();

  int16_t raw = (data[1] << 8) | data[0];
  raw = raw << 3;
  raw = (raw & 0xFFF0) + 12 - data[6];

  float celsius =  (float)raw / 16.0;
  
  return celsius;
  
}

 

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

data[0]-data[8]  это 8 байт полученных от датчика. Что значит каждый, читать в даташите.
Если преобразовывает корректно, значит все верно. В битовых операциях не силен, не объясню.
Считывание без задержки, в данном случае без разницы. Если интервал опроса значительный, будете получать результат от предыдущей конвертации.

AvtoRemGarage
Offline
Зарегистрирован: 26.02.2016

Всем спасибо за помощь.

В итоге получил температуру с двух датчиков DS1820( или DS18S20). С корректными показаниями в сериалпорт, без пауз, иначе можно было использовать Даллосовскую библиотеку, чего не хотелось.

Может кому пригодиться.


// Снятие температуры с двух дачтиков DS1820/DS18S20

#include <OneWire.h>

OneWire ds (10);   // порт 10, на котором висят датчики
byte data[12];
byte addr1[8] = {0x10, 0x40, 0xDF, 0xD7, 0x01, 0x08, 0x00, 0xE5};   // ID индивидуально для каждого датчика
byte addr2[8] =  {0x10, 0x3F, 0xD3, 0xD7, 0x01, 0x08, 0x00, 0x78};  // ID индивидуально для каждого датчика
unsigned int raw;
float temp1, temp2;

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

void loop()

{
  temp1 = DS1820(addr1);
  temp2 = DS1820(addr2);
  
  Serial.println(temp1);        // вывод температуры1 в сериалпорт
  Serial.println(temp2);        // вывод температуры2 в сериалпорт
  
}

//==================================================================================
//                            Считывание температуры
//==================================================================================

float DS1820(byte *adres)

{ ds.reset();
  ds.select(adres);
  ds.write(0x44,0);        
                           //здесь добавить паузу если показания кривые,рекомендовано 750мсек, но у меня без паузы работат корректно.
  ds.reset();
  ds.select(adres);
  ds.write(0xBE); 


  for (byte i = 0; i < 9; i++) 
  data[i] = ds.read ();

  int16_t raw = (data[1] << 8) | data[0];       // преобразование температуры только для DS1820 и DS18S20
  raw = raw << 3;                               // преобразование температуры только для DS1820 и DS18S20
  raw = (raw & 0xFFF0) + 12 - data[6];          // преобразование температуры только для DS1820 и DS18S20

  float celsius =  (float)raw / 16.0;           // пересчет температуры в цельсии
  
  return celsius;
 
}

 

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

46 строка для всех датчиков. А для S-ки еще 46-47.

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

//***Функция считывания температуры c Далласов*****
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 = 1; //Время возврата в секундах
  }
  else {
    byte i;
     int temp;
    for (i = 0; i < 3; i++){ //Перебор количества датчиков
     ds.reset();
     ds.select(addr[i]);
     ds.write(0xBE); //Считывание значения с датчика
     temp = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
     Temp[i] = (float)temp / 16.0; 
     flagDallRead = 2; //Время возврата в секундах
     }
   }
  }
}
//-------

В данном случае на 3 датчика. Адреса храняться в массиве addr[], температуру читаем в массив Temp[].
Присваивая значения второму flagDallRead, можем менять требуемый интервал.
Вызов dallRead( flagDallRead*1000 );
Для вас надо добавить считывание 6 байтов от датчиков и пересчет. Для DS18B20 достаточно двух, как у меня.
Идея украдена здесь.

okta
Offline
Зарегистрирован: 10.01.2015

что-то последний пример (про миллис) я вообще не понял. Вернее идея понятна, но реализация... не будет оно работать так.

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

okta пишет:

что-то последний пример (про миллис) я вообще не понял. Вернее идея понятна, но реализация... не будет оно работать так.

А что в нем не так?

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

bwn пишет:

okta пишет:

... не будет оно работать так.

А что в нем не так?

Вот уважаю таких людей, из них потом депутаты классные получаются. Сказал веское мнение и в кусты. А обоснование сами придумаете.((((

okta
Offline
Зарегистрирован: 10.01.2015

Честно говоря, ожидал что вы объясните как оно работает :)

Что мне не понравилось:

1. при каждом вызове обнуляется prevTime, соответственно, интервал будет отсчитываться некорректно (по факту, он скорее всего всегда будет больше заданного интервала, т.к. расчетный будет временем от включения МК)

2. тоже самое с flagDall, соответственно, при каждом вызове будем отправлять комманду всем датчикам на конвертацию

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

1. prevTime - static, обнуляется только при первичной инициализации, далее работает 6 строка.
2. flagDall аналогично и потом инвертируется при каждом проходе. Соответственно true - конвертация, false - считывание.

okta
Offline
Зарегистрирован: 10.01.2015

ах ну да, этиж недоглобальные переменные. Сорри, вылетело, сам их не использую - очень код читать потом неудобно (но это глубоко ИМХО).

PS не надо сразу резко реагировать и депутатами обзываться - зашел глянул, отписался. Как в следующий раз зашел, так ответил :)

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

Так зашли, плюнули, причин не объяснили и удалились.)))) Абыдно, да.

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

хочу  получать температуру для девайса 18B20 , переписал пример 1-wire

 в принципе оно считывает, но кусок програмы после этого кода не работает.. :(

задача была - получить значение celsium - и оперировать в программе этим значением дальше.

так можно делать? какие ошибки я допустил? 

самому разобраться будет сложновато.

 

 

#include <OneWire.h>
OneWire  ds(3);  // on pin 10 (a 4.7K resistor is necessary)

void setup(void) {
  Serial.begin(9600);
byte i;heit;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius;
}

void getTEMP() {

  
  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  
 
  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
  
  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.
  
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();

  }


  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  Serial.print("  Temperature = ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  float TEMP = celsius;
}

 

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

Посмотрите здесь.

Там есть и с wdt и с millis.