Skip to contentSkip to main navigation Skip to footer

Arduino и термометр DS18B20

Описание


DS18B20 – высокоточный цифровой датчик температуры. Основные характеристики:

  • Диапазон: -55.. 125 °C
  • Точность: 0.5 °C
  • Разрешение: 9.. 12 бит (0.48.. 0.06 °C)
  • Питание: 3-5.5V
  • Период выдачи результата:
    • 750 мс при точности 12 бит
    • 94 мс при точности 9 бит
  • Интерфейс связи: 1-Wire (OneWire)
  • Корпус: TO-92, SOIC-8 или герметичное исполнение

В наборе идёт датчик в герметичном исполнении со стандартным гнездом (шаг 2.54 мм) для подключения

Подключение


Датчик имеет следующие назначения пинов:

 

Датчик подключается к любому цифровому пину Arduino, но пин должен быть подтянут к питанию резистором 4.7 кОм. На один пин можно подключить несколько датчиков DS18B20.

В рамках набора GyverKIT резистор на 4.7 кОм можно заменить двумя резисторами на 10 кОм (есть в комплекте), подключенными параллельно:

Библиотеки


Для этого датчика есть несколько библиотек:

  • “Официальная” библиотека DallasTemperature.h, для работы которой также понадобится библиотека OneWire.h.
  • Наша библиотека microDS18B20

В примерах на этом сайте мы будем использовать microDS18B20, так как она в несколько раз легче и проще в использовании, чем официальная. Библиотека идёт в архиве к набору GyverKIT, а свежую версию всегда можно установить/обновить из встроенного менеджера библиотек Arduino по названию microDS18B20. Краткая документация находится по ссылке выше, базовые примеры есть в самой библиотеке.

Работа с microDS18B20

Без адресации


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

MicroDS18B20<пин1> sensor1;
MicroDS18B20<пин2> sensor2;
// ... и так далее

С адресацией


В этом режиме можно подключить сколько угодно датчиков на один пин МК, но для работы с ними понадобится занести в программу уникальные адреса датчиков. В момент чтения адреса к пину должен быть подключен только один датчик! Пример – address_read. Для дальнейшей работы адреса хранятся в массивах на стороне программы и передаются датчикам при инициализации, пин указывается один и тот же:

uint8_t addr1[] = {0x28, 0xFF, 0xCD, 0x59, 0x51, 0x17, 0x4, 0xFE};
uint8_t addr2[] = {0x28, 0xFF, 0x36, 0x94, 0x65, 0x15, 0x2, 0x80};

MicroDS18B20<пин, addr1> sensor1;
MicroDS18B20<пин, addr2> sensor2;
// ... и так далее

Также адрес можно сменить во время работы программы, см. документацию.

Чтение температуры


Чтение температуры делится на два этапа – запрос и получение данных. Запрос делается функцией requestTemp(). После получения запроса датчик начинает измерение температуры, которое длится от 90 до 750 мс в зависимости от настроенной точности (по умолчанию точность максимальная, преобразование длится 750 мс). Если прочитать температуру до окончания преобразования – датчик вернёт результат предыдущего измерения, поэтому в примерах используется задержка или опрос по таймеру на 1 секунду. Получить температуру можно при помощи getTemp() [float] или getTempInt() [int]. Если принятые данные повреждены или датчик отсутствует на линии – функция вернёт предыдущее успешно прочитанное значение температуры.

Примечание: при повторных вызовах getTemp() не запрашивает с датчика новую температуру (долгое выполнение функции), вместо этого она просто возвращает предыдущий результат до тех пор, пока не будет сделан новый запрос requestTemp().

В версии библиотеки 3.5 появилась возможность отдельно запросить температуру и определить корректность полученных данных, чтобы только после этого их прочитать и применить в программе – функция readTemp(). Также это позволяет определить состояние подключения и всё ли в порядке с датчиком. Для чтения температуры рекомендуется использовать конструкцию вида:

if (sensor.readTemp()) value = sensor.getTemp();
// else отработка ошибки

где readTemp() запрашивает данные с датчика и возвращает true, если они прочитаны корректно. После этого можно забрать текущую температуру из getTemp(), которая уже не запрашивает температуру с датчика, а отдаёт прочитанный в readTemp() результат.

Примеры


Без адресации

Библиотека позволяет работать по схеме “один датчик – один пин”, в которой адрес датчика получать не нужно. Достаточно подключить и использовать:

// один датчик лучше читать без адресации, это сильно экономит память
#include <microDS18B20.h>
MicroDS18B20<2> sensor;

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

void loop() {
  // запрос температуры  
  sensor.requestTemp();
  
  // вместо delay используй таймер на millis(), пример async_read
  delay(1000);
  
  // проверяем успешность чтения и выводим
  if (sensor.readTemp()) Serial.println(sensor.getTemp());
  else Serial.println("error");
}
Без адресации асинхронный опрос
#include <microDS18B20.h>
MicroDS18B20<2> sensor;  // датчик на D2

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

void loop() {
  // конструкция программного таймера на 800 мс
  static uint32_t tmr;
  if (millis() - tmr >= 800) {
    tmr = millis();

    // читаем прошлое значение
    if (sensor.readTemp()) Serial.println(sensor.getTemp());
    else Serial.println("error");

    // запрашиваем новое измерение
    sensor.requestTemp();
  }
}
Чтение адреса

Каждый датчик имеет свой уникальный адрес. Его можно прочитать следующим образом:Данный код выводит в порт адрес текущего подключенного датчика.

#include <microDS18B20.h>

MicroDS18B20 <2> sensor;  // Создаем термометр без адреса на пине D2
uint8_t address[8];       // Создаем массив для адреса

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

void loop() {
  // читаем адрес термометра в указанный массив
  if (sensor.readAddress(address)) {  // если успешно, выводим
    Serial.print('{');
    for (uint8_t i = 0; i < 8; i++) {
      Serial.print("0x");
      Serial.print(address[i], HEX);  // Выводим адрес
      if (i < 7) Serial.print(", ");
    }
    Serial.println('}');

  } else Serial.println("Not connected");
  delay(1000);
}
Опрос датчиков с адресацией

Зная адреса датчиков, можно подключить несколько штук на один пин и обращаться к ним в коде следующим образом:

#include <microDS18B20.h>
#define DS_PIN 2 // пин для термометров

// Уникальные адреса датчиков - считать можно в примере address_read
uint8_t s1_addr[] = {0x28, 0xFF, 0xCD, 0x59, 0x51, 0x17, 0x4, 0xFE};
uint8_t s2_addr[] = {0x28, 0xFF, 0x36, 0x94, 0x65, 0x15, 0x2, 0x80};

MicroDS18B20<DS_PIN, s1_addr> sensor1;  // Создаем термометр с адресацией
MicroDS18B20<DS_PIN, s2_addr> sensor2;  // Создаем термометр с адресацией

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

void loop() {
  // асинхронное чтение нескольких датчиков смотри в примере async_read_many
  sensor1.requestTemp();      // Запрашиваем преобразование температуры
  sensor2.requestTemp();

  delay(1000);           // ожидаем результат 
  
  Serial.print("t1: ");
  if (sensor1.readTemp()) Serial.println(sensor1.getTemp());
  else Serial.println("error");

  Serial.print("t2: ");
  if (sensor2.readTemp()) Serial.println(sensor2.getTemp());
  else Serial.println("error");
}
Удобный опрос массива датчиков
// количество датчиков для удобства
#define DS_SENSOR_AMOUNT 5

// создаём двухмерный массив с адресами
uint8_t addr[][8] = {
  {0x28, 0xFF, 0x78, 0x5B, 0x50, 0x17, 0x4, 0xCF},
  {0x28, 0xFF, 0x99, 0x80, 0x50, 0x17, 0x4, 0x4D},
  {0x28, 0xFF, 0x53, 0xE5, 0x50, 0x17, 0x4, 0xC3},
  {0x28, 0xFF, 0x42, 0x5A, 0x51, 0x17, 0x4, 0xD2},
  {0x28, 0xFF, 0xCD, 0x59, 0x51, 0x17, 0x4, 0xFE},
};

#include <microDS18B20.h>
// указываем DS_ADDR_MODE для подключения блока адресации
// и создаём массив датчиков на пине D2
MicroDS18B20<2, DS_ADDR_MODE> sensor[DS_SENSOR_AMOUNT];

void setup() {
  Serial.begin(9600);
  // устанавливаем адреса
  for (int i = 0; i < DS_SENSOR_AMOUNT; i++) {
    sensor[i].setAddress(addr[i]);
  }
}

void loop() {
  // конструкция программного таймера на 1c
  static uint32_t tmr;
  if (millis() - tmr >= 1000) {
    tmr = millis();

    // выводим показания в порт
    for (int i = 0; i < DS_SENSOR_AMOUNT; i++) {
      Serial.print(sensor[i].getTemp());
      Serial.print(',');
    }
    Serial.println();

    // запрашиваем новые
    for (int i = 0; i < DS_SENSOR_AMOUNT; i++) {
      sensor[i].requestTemp();
    }
  }
}

Видео


Домашнее задание


  • Изучить остальные возможности библиотеки
  • Измерить температуру тела, сравнить со ртутным термометром

 

Связанные уроки

Полезный пример?

Похожие примеры
Подписаться
Уведомить о
32 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии