Добавить в избранное

DS18B20 с Arduino: точный цифровой термометр по 1-Wire

Чтение ≈ 4 мин

Цифровой датчик температуры DS18B20: шина 1-Wire, подтяжка 4.7 кОм, библиотеки OneWire и DallasTemperature, несколько датчиков на одном проводе, разрешение 9–12 бит и водонепроницаемые версии.

Почему DS18B20 — лучший термометр для Arduino

DS18B20 — цифровой датчик температуры: в отличие от аналоговых (термисторов, LM35) он сам измеряет и отдаёт готовое число по шине 1-Wire. Точность ±0.5 °C в диапазоне −10…+85 °C, разрешение до 0.0625 °C (12 бит), диапазон −55…+125 °C. Есть в металлическом герметичном корпусе — можно мерить воду и почву.

Главная фича — 1-Wire: несколько датчиков на одном проводе, каждый с уникальным 64-битным адресом. Десяток термометров по дому — и один пин Arduino.

Подключение

Три вывода: VCC (3–5.5 В), GND, DQ (данные). Обязательна подтяжка DQ к VCC резистором 4.7 кОм — без неё шина не работает:

Arduino 5V ── VCC ──┬──[4.7 кОм]──┬── DQ ── Arduino D2
                    │             │
                   GND            DQ других датчиков на том же проводе

Датчики цепляются параллельно — один резистор на всю шину, не на каждый.

Библиотеки и первый код

Ставим OneWire (Jim Studt/Paul Stoffregen) и DallasTemperature (Miles Burton):

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

OneWire oneWire(2);                  // шина на пине 2
DallasTemperature sensors(&oneWire);

void setup() {
    Serial.begin(9600);
    sensors.begin();
    Serial.print("найдено датчиков: ");
    Serial.println(sensors.getDeviceCount());
}

void loop() {
    sensors.requestTemperatures();                  // команда всей шине
    float t = sensors.getTempCByIndex(0);           // по индексу — первый найденный
    if (t != DEVICE_DISCONNECTED_C) {
        Serial.print("T: "); Serial.println(t);
    }
    delay(1000);
}

requestTemperatures запускает измерение у всех датчиков на шине сразу — они измеряют параллельно ~750 мс на 12 бит.

Несколько датчиков по адресам

Каждый DS18B20 имеет прошитый адрес — обращение по индексу работает, но порядок не гарантирован после перезагрузки. Правильно — по адресу:

DeviceAddress addr1 = {0x28, 0xFF, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};

float t = sensors.getTempC(addr1);   // конкретный датчик

Адреса узнают скетчем-сканером из примеров OneWire или:

DeviceAddress addr;
for (int i = 0; i < sensors.getDeviceCount(); ++i) {
    sensors.getAddress(addr, i);
    // распечатать addr в hex и записать для скетча
}

Разрешение и точность

По умолчанию 12 бит (0.0625 °C). Можно снизить ради скорости:

sensors.setResolution(9);   // 9 бит = 0.5 °C, измерение ~94 мс
// 10 бит — 0.25 °C / ~188 мс
// 11 бит — 0.125 °C / ~375 мс
// 12 бит — 0.0625 °C / ~750 мс

При опросе важно: requestTemperatures стартует измерение, а getTempC читает готовое. Между ними должно пройти время на измерение — иначе старое значение или DEVICE_DISCONNECTED.

Паразитное питание и режимы

DS18B20 умеет работать по двум проводам — паразитное питание от линии данных (VCC на GND). Не рекомендую: меньше ток на измерение, нестабильность при длинных линиях. Подключайте тремя проводами — надёжнее.

setWaitForConversion(false) позволяет не блокировать loop на время измерения:

sensors.setWaitForConversion(false);
sensors.requestTemperatures();
// через 800 мс (по millis) читаем
if (millis() - convStart >= 800) {
    float t = sensors.getTempCByIndex(0);
}

Практический проект: мультизонный термометр

OneWire oneWire(2);
DallasTemperature sensors(&oneWire);

DeviceAddress inside  = {0x28, 0xAA, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
DeviceAddress outside = {0x28, 0xBB, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22};

void loop() {
    sensors.requestTemperatures();
    delay(800);
    Serial.print("дома: "); Serial.println(sensors.getTempC(inside));
    Serial.print("улица: "); Serial.println(sensors.getTempC(outside));
    delay(5000);
}

Типичные проблемы

  • getDeviceCount() = 0: нет резистора 4.7 кОм или он не туда; DQ на другом пине; датчик мёртвый/перепутаны выводы (смотрите маркировку — у waterproof-версий цвета проводов).
  • 85 °C всегда: датчик в режиме "сброса" — возвращает стартовое значение; не хватило времени на конверсию.
  • −127 °C: DEVICE_DISCONNECTED — потерян контакт или нет подтяжки.
  • Пляшут значения на длинной линии: провод >10 м — уменьшите резистор до 2.2 кОм, экранируйте, добавьте конденсатор.
  • Перепутаны адреса: распечатайте адреса сканером и задайте явно.

Итог

DS18B20 — готовый точный термометр на одном проводе: резистор 4.7 кОм, OneWire + DallasTemperature, опрос по адресу для нескольких датчиков. Три грабли: подтяжка обязательна, дайте 750 мс на измерение, −127 значит «нет связи». Дальше — теплица, аквариум, котёл, метеостанция.

Полный пример: несколько датчиков

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

OneWire oneWire(4);
DallasTemperature sensors(&oneWire);

void setup() {
    Serial.begin(9600);
    sensors.begin();
    Serial.printf("найдено датчиков: %d\n", sensors.getDeviceCount());
}

void loop() {
    sensors.requestTemperatures();          // опросить все
    for (int i = 0; i < sensors.getDeviceCount(); ++i) {
        float t = sensors.getTempCByIndex(i);
        Serial.printf("датчик %d: %.2f°C\n", i, t);
    }
    delay(1000);
}

Одна шина — много датчиков: библиотека сама различает их по уникальным 64-битным адресам.

По адресу: надёжнее, чем по индексу

getTempCByIndex возвращает датчики в порядке обнаружения — при замене порядок может измениться. Стабильнее запрашивать по конкретному ROM-адресу:

DeviceAddress addr1 = {0x28, 0xFF, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
float t = sensors.getTempC(addr1);

Адреса узнаёте сканером — библиотека печатает их при старте.

Водонепроницаемый корпус

DS18B20 в герметичном гильзе — стандарт для улицы, аквариума, котла. Три провода: красный VCC, чёрный GND, жёлтый DATA. Подтяжка 4.7 кОм между DATA и VCC.

Паразитное питание

DS18B20 умеет работать от двух проводов — DATA и GND, «воруя» питание с линии данных. Для этого VCC датчика сажается на GND. Экономит провод, но медленнее и менее надёжно — для обычных задач используйте трёхпроводную схему.

Диапазон и точность

  • −55…+125°C, точность ±0.5°C в диапазоне −10…+85.
  • Разрешение настраивается 9–12 бит (0.5–0.0625°C шаг) — больше бит = медленнее конверсия (750 мс на 12 бит).
  • setResolution(12) для максимальной точности, setWaitForConversion(false) для неблокирующего чтения.

Частые проблемы

  • getTempC возвращает -127: датчик не отвечает — проверьте провода, подтяжку, адрес.
  • Показания скачут: плохой контакт, длинный провод без витой пары.
  • Несколько датчиков мешают: суммарная подтяжка важна — один резистор на всю шину.
  • Медленный опрос: requestTemperatures ждёт конверсии 750 мс на 12 бит — setWaitForConversion(false) и опрос по таймеру.

Проекты

  • Уличный термометр в гильзе.
  • Контроль температуры котла/бойлера.
  • Земляной термометр в теплице.
  • Металлическая гильза для точного измерения жидкостей.
Поделиться
Понравился материал?

Комментарии

Добавить комментарий