DS18B20 (нужна помощь)

bob-130
Offline
Зарегистрирован: 09.08.2017

Помогите, есть 2 датчика DS18B20 все работает, но нет минусового значения никак не получается

#include <OneWire.h>


OneWire  ds(2);                // Завесим датчики на pin 2 (и обязательно подтянем к плюсу 4.7K резистором)
byte i;                        // Любимый счетчик
byte data[8];                  // Сюда попадают данные из датчиков
byte addr[8];                  // Здесь хранятся адреса датчиков
float celsius;
                                // Всякая хрень для работы с температурой
int signBit, tc_100, whole, fract;


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

void loop(void) {
                                // Функция последовательно ищет адреса устройств
    if (!ds.search(addr)) {    // и запоминает их в addr. Если очередного устройства не найдено
    ds.reset_search();          // поиск сбрасывается и все начинается сначала
    delay(250);
    return;
    }
    ds.reset();                  // Сбрасываем линию
    ds.select(addr);              // Выбираем найденный адрес
    ds.write(0x44, 1);            // Пишем 0x44 - команда на расчет температуры и 1 - если паразитное питание, если обычное (соединение три провода) то 0.

    delay(1000);                  // Для преобразования при паразитном питании надо 750ms, берем с запасом. Если питание обычное - достаточно 100

    ds.reset();                  // Опять сброс и выбор адреса - так положено по инструкции.
    ds.select(addr);
    ds.write(0xBE);              // Команда датчику, чтобы он начал отдавать данные.

    Serial.print("  Data = ");
    Serial.print(" ");
    for ( i = 0; i < 9; i++) {    // Читаем 8 байт. А зачем нам все 8? Достаточно первых двух!
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
    }

    int16_t raw = (data[1] << 8) | data[0]; // int кодировка сотоит из двух байт, причем каждая единичка значит 0.0625 градуса

    celsius = (float)raw / 16.0;            // Превращаем int во float и делим на 16, что равно умножению на 0.0625, потому что
    Serial.print("First Temperature = ");  // 1 делить на 16 равно 0.0625.
    Serial.print(celsius);

    signBit = raw & 0x8000;                  // Проверяем самый левый бит: 0x8000= 0b10000000 00000000
    if (signBit)                            // Если там единица - число отрицательное и его надо преобразовать
    {                                        // Стандартное преобразование отрицательного числа, которое в микроконтроллере в дополнительной кодировке
        raw = (raw ^ 0xffff) + 1;              // Путем исключающего ИЛИ плюс единица http://www.inf1.info/additionalcode
    }
    tc_100 = (6 * raw) + raw / 4;            // Это хитрая запись умножения на 6.25 - поиграйте с дробями на бумажке: (25raw)/4
                                            // Вообще то, нужно было умножать на 0.0625, но число наше - int, и тогда мы потеряем
                                            // все данные. Поэтому умножили еще на 100.
    whole = tc_100 / 100;                      // Делим на сто, и получаем целое число (помним, что int отбросит дробь)
    fract = tc_100 % 100;                    // Остаток от деления на 100 будет дробной частью.
    Serial.print("Second Temperature = ");  // И напечатаем все это для сравнения.
    if(signBit) {
        Serial.print("-");
    }
    Serial.print(whole);
    Serial.print(".");
    if(fract < 10) {
        Serial.print("0");
    }
    Serial.println(fract);
}

 

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

Или берите даташит, читайте как они (отрицательные температуры) хранятся и обрабатывайте, или возьмите готовую библиотеку DallasTemperature - там всё уже сделано, причём более грамотно - проверяется контрольная сумма, обрабатываются ошибки и т.п..

bob-130
Offline
Зарегистрирован: 09.08.2017

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

Или берите даташит, читайте как они (отрицательные температуры) хранятся и обрабатывайте, или возьмите готовую библиотеку DallasTemperature - там всё уже сделано, причём более грамотно - проверяется контрольная сумма, обрабатываются ошибки и т.п..

сам не силен может подскажешь на 2 датчика код, вообще вывод надисплей OLED LCD 128x64 0.96 I2C но хватит и монитор порта там как нить сам доделал бы

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

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

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

Всё просто:

  int loByte = data[0];
  int hiByte = data[1];

  int8_t tempValue;
  uint8_t tempFract;

  int temp = (hiByte << 8) + loByte;
  
  bool isNegative = (temp & 0x8000);
  
  if(isNegative)
    temp = (temp ^ 0xFFFF) + 1;

  // DS18B20 ONLY !!!
  int tc_100 = (6 * temp) + temp/4;

  tempValue = tc_100/100;
  if(isNegative)
    tempValue = -tempValue;
    
  tempFract = tc_100 % 100;

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Я думаю если в 10 строке SignBit сделать беззнаковый тип - все заработает, сталкивался уже с такой проблемой

Отсюда можно нужный кусок взять - 100 % минус показывает
http://arduino.ru/forum/programmirovanie/attiny13a-101-primenenie?page=2...