DS18B20 && Arduino

Тема в разделе "Arduino & Shields", создана пользователем Salk, 1 мар 2015.

  1. temp1 = DS18B20(addr1); - то есть эта строка это "чтение" функции которая называется DS18B20?
    float DS18B20(byte *adres) - а здесь указатель byte что бы контроллер преобразовал адрес из массива в байты и записал их в adres?
    оператор * - как я понял это "косвенное обращение"?
     
  2. Megakoteyka

    Megakoteyka Оракул Модератор

    Только не чтение, а вызов. Функция - это подпрограмма.
    Да, функция принимает адрес первого элемента массива с адресом датчика и считывает из массива нужное количество байт.
     
  3. Спасибо большое) разобрался)
     
  4. Всем привет, гуру подскажите что я делаю не так?
    Суть - необходимо отслеживать неполадки с DS18B20 (обрыв питания или обрыв шины данных)
    Вот что написал:
    Код (PHP):

    byte error85[9] =  {0x50, 0x05, 0x4B, 0x46, 0x7F, 0xFF, 0x0C, 0x10, 0x1C}; // эти данные в массиве data при обрыве положительного питания (при этом значении T=85)
    //==================================================================================
    //                             Считывание температуры
    //==================================================================================
    float DS18B20(byte *adres){
      ds.reset();
      ds.select(adres);
      ds.write(0x44,0); // start conversion, with parasite power on at the end
      ds.reset();
      ds.select(adres);
      ds.write(0xBE); // Read Scratchpad
      for (byte i = 0; i < 9; i++) { // we need 9 bytes
      data[i] = ds.read ();
    // ***********ОШИБКИ с датчиков DS18b20******************* если обрыв линии или питания
                          if (data[i]==error85[i] || data[i]==0xFF)
                            {e++;} //сравниваем одинаковые байты
                          else
                            {e=0; }                                          
                          }
                          if (e>8) {podtv++; e=0;} // если все байты в массиве совпали, увеличиваем счетчик ошибок
                          if (podtv>5) error=1;  //если счетчик ошибое перевалил за 5 - выводим ошибку
                                                             
    //************ПРОДОЛЖИМ вычисление температуры************                  
      raw = (data[1] << 8) | data[0];//=======Пересчитываем в температуру
      float celsius = (float)raw / 16.0;
      return celsius;
    }

     
    переменная error как была 0 так и остается(
     
  5. сам спросил - сам ответил) в общем запись, где байт записан в HEX: data==0xFF - не работает.
    Хотя когда сравниваю массив data с массивом error85 (где, кстати, байты записаны в HEX формате) - все работает.
    Исправил на data==0 - все заработало
     
  6. User MTU

    User MTU Нуб

    Здравствуйте.

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

    Но есть одно неудобство - температура отображается с шагом 0.5 градуса. Да, япомню про точность18В20 как раз в 0.5 градуса, однако подскажите, как сменить отображение на 0.1 градуса?
     
  7. AL___2008

    AL___2008 Нуб

    Думаю, зависит от настройки разрешения, в библиотеке даллас есть пример. У меня сейчас показывают 3 датчика с сотыми градуса
     
  8. AL___2008

    AL___2008 Нуб

    Большое спасибо
     
  9. Salk

    Salk Гик

    Да, верно, в библиотеке Dallas это сделать довольно очевидно
    Код (C++):
    //Инициализируем термодатчик и установим разрешающую способность 12 бит (обычно она установлена по умолчанию, так что последнюю строчку можно опустить)
    void setup()
    {
      sensors.begin();
      sensors.getAddress(tempDeviceAddress, 0);
      sensors.setResolution(12); // 12 бит
    }
    Только ради этого снова переходить на "тормознутую" библиотеку, решать каждому :)
    Сам не игрался с этим, точность меня вполне устраивала 0.5*С, но полагаю, что в функции
    Код (C++):
    float DS18B20(byte *adres){
      ds.reset();
      ds.select(adres);
      ds.write(0x44,0); // start conversion, with parasite power on at the end
      ds.reset();
      ds.select(adres);
      ds.write(0xBE); // Read Scratchpad
      for (byte i = 0; i < 9; i++) { // we need 9 bytes - разрешение датчика
      data[i] = ds.read ();
    можно изменить строчку
    Код (C++):
    for (byte i = 0; i < 9; i++)  // разрешение датчика
    на
    Код (C++):
    for (byte i = 0; i < 12; i++) // т.е. повысить разрешение с 9 до 12 бит
    Будет здорово, если проверите и отпишитесь о результате :)
     
  10. AL___2008

    AL___2008 Нуб

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

    tarakan Нуб

    А отрицательную температуру он показывать будет?
     
  12. AL___2008

    AL___2008 Нуб

    да
     
  13. Jaric

    Jaric Нуб

    Подскажите как узнать адрес датчика? в проекте важно чтобы ардуина не переставила датчики местами после отключения питания.
     
  14. Oiler

    Oiler Нуб

    Добрый день!
    Сделал свой вариант
    этого кода. Но использую 8-ми разрядный ЛЕД на MAX7219, поэтому немного переделал код под себя:

    Код (C++):
    #include <OneWire.h>
    #include <LedControl.h>

    LedControl lc=LedControl(11,10,9,2);
    OneWire ds (8);

    byte data[12];
    byte addr1[8] = {0x28, 0xFF, 0x8A, 0xF8, 0xA3, 0x15, 0x03, 0xB0};
    unsigned int raw;
    float temp1;
    int T1; // переменная текущей температуры
    int ones, tens, hundreds, thousand;

    void setup()
    {
      Serial.begin(9600);
      lc.clearDisplay(0);// clear screen
      lc.shutdown(0,false);// turn off power saving, enables display
      lc.setIntensity(0,5);// sets brightness (0~15 possible values)
      lc.setScanLimit(0, 4);
    }

    void loop()
    {
      temp1 = DS18B20(addr1);
      Serial.println(temp1);
      T1 = temp1*100;
      thousand = T1/1000;
      hundreds = (T1-thousand*1000)/100;
      tens = (T1-(thousand*1000+hundreds*100))/10;
      ones = T1-(thousand*1000+hundreds*100+tens*10);

      lc.setDigit(0,0,ones,false);
      lc.setDigit(0,1,tens,false);
      lc.setDigit(0,2,hundreds,true);
      lc.setDigit(0,3,thousand,false);
      delay(5000);
    }

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

      for (byte i = 0; i < 9; i++) // можно увеличить точность измерения до 0.0625 *С (от 9 до 12 бит)
      { // we need 9 bytes
        data[i] = ds.read ();
      }
      raw =  (data[1] << 8) | data[0];//=======Пересчитываем в температуру
      float celsius =  (float)raw / 16.0;
      return celsius;
    }
    При этом ЛЕД ведёт себя поразному: может несколько циклов показывать правильную температуру, потом срывается и разные разряды показывают всякую хрень, точки могут сами включаться/выключаться, потом загораются все сегменты и до перезагрузки ничего не меняется. А могут все сегменты погаснуть но через несколько циклов опять работают кое-как. При этом вывод температуры в сериал идёт нормально.
    По отдельности DS18B20 и ЛЕД работают нормально: датчик работает и по 1варе и по далассу, ЛЕД нормально отображает тестовые скетчи.
    Что тут можно ещё поправить?


    Короче говоря, решил отвлечься и запихнуть Уно в стандартный прозрачный корпус. Собрал, запустил и о чудо! Работает. Толи наводки какие были, толи неправильно собирал до этого (хотя сто раз всё проверял), толи просто ей хотелось жить в своём собственном доме.
    Спасибо за рабочий пример.
     
    Последнее редактирование: 28 фев 2016
  15. avtoremgarage

    avtoremgarage Нуб

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

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

    Прошу помощи рабобраться что не так, два вечера уже убил на поиск температуры, освоение прерываний както проще далось. Скет прилагаю.
    Код (C++):
    #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;
    }}
     
  16. sanky

    sanky Нуб

    Отказался от Даллас, как у ТС, температура реле стало щелкать без задержек, но жутко тормозит считывание с IR. Надо долго тиснуть пока сработает, что не так???
    Плиз.

    Код (C++):
    #include <LiquidCrystal.h> //подключаем библиотеку работы с ЖКИ
    #include <OneWire.h> //подключаем библиотеку работы с 1-wire
    #include <IRremote.h>
    #include <Wire.h>

    OneWire ds(8);
    LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
    int buz=6;
    int RECEIVE_PIN = 7;
    int VALVE_PIN=9;
    int y;
    float x;
    float Temp1;
    byte addr1[8] = {
      0x28, 0xFF, 0x34, 0x61, 0x61, 0x15, 0x01, 0x8F };
      byte data[12];
    unsigned int raw;

    IRrecv irrecv(RECEIVE_PIN);
    decode_results results;

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

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

    void setup() {
    y=0;
    x=40;
    pinMode(buz, OUTPUT);
    pinMode(VALVE_PIN, OUTPUT);
    pinMode(A0, INPUT);
    irrecv.enableIRIn();
      lcd.begin(16, 2);
      lcd.clear();
    Wire.begin();

    }

    void loop() {
    Temp1 = DS18B20(addr1);
    if (irrecv.decode(&results)) {
              switch (results.value) {
                case 0xFF9867:   x+=10; break;
                case 0xFF6897:   x-=10; break;
                case 0xFF18E7:   x+=1;  break;
                case 0xFF30CF:   x-=1;  break;
                case 0xFF38C7:   x+=0.1;break;
                case 0xFF10EF:   x-=0.1;break;
                case 0xFF4AB5:   x+=0.01;break;
                case 0xFF42BD:   x-=0.01;break;
                case 0xFF629D:  y+=1;  break;
                case 0xFFA857:  y-=1;  break;
            }          
            irrecv.resume();
        }
      lcd.setCursor(0, 0);   // устанавливаем курсор во вторую строку (нумерация с 0) в 0 столбец
      lcd.print("T1=");    // выводим "Т=" на экран
      lcd.print(Temp1);     // в следующей позиции будет печататься температура
     
      lcd.setCursor(10, 0);
      lcd.print("*");
      lcd.print(x);
      lcd.setCursor(10, 1);
      lcd.print("y");
      lcd.print(y);
     
      if (Temp1>x){
      digitalWrite(buz, HIGH);}
        else digitalWrite(buz, LOW);
     
    /*  switch (y)
      {
        case 0: digitalWrite(VALVE_PIN, LOW); break;
        case 1: {digitalWrite(VALVE_PIN, HIGH); delay(10); digitalWrite(VALVE_PIN, LOW); delay(50);} break;
        case 2: {digitalWrite(VALVE_PIN, HIGH); delay(20); digitalWrite(VALVE_PIN, LOW); delay(50);} break;
        case 3: {digitalWrite(VALVE_PIN, HIGH); delay(30); digitalWrite(VALVE_PIN, LOW); delay(50);} break;
        case 4: {digitalWrite(VALVE_PIN, HIGH); delay(35); digitalWrite(VALVE_PIN, LOW); delay(50);} break;
        case 5: {digitalWrite(VALVE_PIN, HIGH); delay(50); digitalWrite(VALVE_PIN, LOW); delay(50);} break;
        case 6: {digitalWrite(VALVE_PIN, HIGH);} break;
     
       
      }*/

    }
     
     
  17. ИгорьК

    ИгорьК Гуру

    Я просто балдею от этого кусочка кода. Он бродит от одного ардуинщика к другому уже лет сто и никто не задаётся вопросом зачем он нужен и для чего жрёт память массив, куда читаются данные.
     
  18. avtoremgarage

    avtoremgarage Нуб

    Проясните пожалуйста, что не так и как более правильно.
     
  19. ИгорьК

    ИгорьК Гуру

    1. Замените
    Код (C++):
    for (byte i = 0; i < 9; i++) // можно увеличить точность измерения до 0.0625 *С (от 9 до 12 бит)
      { // we need 9 bytes
        data[i] = ds.read ();
      }
    На
    Код (C++):
    data[0] = ds.read ();
    data[1] = ds.read ();
    Так будет быстрее.
    2. Надо понимать, что DS18b20 на вычисление температуры требуется некоторое время. При паразитном питании ок 700 мс., при обычном - тоже сколько-то надо. Дергать его чаще чем раз в секунду не стоит, хотя и не запрещено. В любом случае, если датчик не осуществил вычисление температуры и занесение результатов в регистры - шина 1wire останавливает выполнение кода для ожидания.
     
    Securbond нравится это.
  20. sanky

    sanky Нуб

    Игорь, спасибо.
    И вместе с тем почему перестает воспринимать Ir?. Если закрментировать
    // Temp1 = DS18B20(addr1); то все становится нормально. Тормозит в функции.
    Спасибо