Курс Arduino с нуля · Индикаторы и экраны
Урок 27. Датчик DHT11: температура и влажность
Подключаем цифровой датчик: он сам измеряет температуру и влажность и присылает плате готовые числа. Ставим первую библиотеку из каталога и учимся проверять, ответил ли датчик вообще.
Что понадобится
- Плата Uno из набора
- Кабель USB
- Макетная плата
- Датчик температуры и влажности DHT11
- Резистор 10 кОм
- 6 проводов «папа-папа»
Все детали есть в обучающем наборе, по которому идёт курс.
До сих пор наши датчики отдавали плате напряжение, а мы сами догадывались, что означают числа от 0 до 1023. Сегодня всё иначе: DHT11 измеряет сам и присылает готовые цифры — сколько градусов и сколько процентов влажности.
Заодно в этом уроке случится ещё одно первое: нам понадобится библиотека, которой нет в программе. Научимся её ставить — дальше это будет обычным делом.
Что это за деталь
Внутри корпуса спрятаны сразу два измерителя и маленькая микросхема. Один измеритель следит за температурой, второй — за влажностью воздуха, а микросхема превращает их показания в числа. Через решётку воздух попадает внутрь: закрывать её пальцем или клеить скотчем нельзя.
Что умеет датчик из набора:
- температура от 0 до +50 °C, ошибка до 2 градусов;
- влажность от 20 до 90 %, ошибка до 5 процентов;
- показания — целыми градусами и процентами, без десятых;
- отвечать успевает не чаще одного раза в 2 секунды.
Мороз и кипяток датчику не по силам: ниже нуля и выше пятидесяти он просто не работает. Для комнаты, теплицы или ящика с растениями этого хватает с запасом.
Чем он отличается от прежних датчиков
Фоторезистор, датчик Холла, потенциометр — все они были аналоговыми: деталь меняла напряжение, плата это напряжение измеряла командой analogRead и получала число 0…1023. Что значит «512», решали мы сами, и пороги приходилось подбирать опытом.
DHT11 — цифровой. Он сам делает измерение, сам переводит его в градусы и проценты и присылает плате готовый ответ. Никаких порогов подбирать не нужно: 23 — это двадцать три градуса, и всё.
Плата за это платит другим: с цифровым датчиком нужно договориться. Он не отвечает просто потому, что на него подали питание, — его нужно спросить, дождаться ответа и разобрать этот ответ. Всё это делает библиотека, но полезно знать, что там происходит.
Как датчик рассказывает о погоде
Провод данных всего один, а сказать нужно много. Поэтому плата и датчик говорят по очереди. Сначала плата на короткое время прижимает линию к минусу — это значит «измеряй». Потом отпускает и слушает.
Датчик отвечает серией импульсов: сорок штук, по одному на каждый бит. Хитрость в том, что отличаются они длиной: коротенькая полочка — ноль, длинная — единица. Из сорока бит складываются влажность, температура и контрольное число — по нему видно, дошёл ли ответ без искажений.
Весь разговор занимает около двадцати миллисекунд и целиком лежит на библиотеке. Нам останется одна команда «прочитать» и две готовые величины.
Зачем нужен резистор 10 кОм
Провод данных один, а говорящих двое. Чтобы они не сожгли друг друга, устроено так: и плата, и датчик умеют только прижимать линию к минусу. Поднять её наверх не может ни один из них.
Вот для этого и нужен резистор 10 кОм между линией данных и «плюсом». Он слабо, но постоянно подтягивает линию вверх: как только оба отпустили — на линии единица. Такой резистор называют подтягивающим, и мы его уже видели в уроке про кнопки. Только там он был спрятан внутри платы, а здесь нужен настоящий.
Без этого резистора схема иногда даже работает — линию слегка подтягивает сама плата. Но показания начинают пропадать без причины, а ошибку искать мучительно. Поставьте резистор сразу.
Собираем схему
Отключите USB и соберите по порядку.
- Вставьте датчик решёткой к себе в ряд
a, четыре вывода в столбики 5, 6, 7 и 8. Корпус ляжет на верхние шины — так и должно быть. - Питание макетки:
5Vплаты — на шину «+» нижней половины,GND— на шину «−». - Вывод 1 (столбик 5) — проводом на «+». Вывод 4 (столбик 8) — на «−». Столбик 7 не трогаем вообще.
- Резистор 10 кОм: одна ножка в столбик 6 сверху от канавки, вторая — в тот же столбик 6, но снизу. От нижней ножки провод идёт на шину «+».
- И последний провод: из столбика 6 сверху — на вывод 2 платы. Это линия данных.
Проверьте перед включением: решётка смотрит на вас; крайний левый вывод датчика идёт на «+», крайний правый — на «−» (перепутать их нельзя, от этого датчик может выйти из строя); третий вывод свободен; резистор соединяет столбик данных с «плюсом»; на макетке есть питание с платы.
Ставим библиотеку
Библиотеки Servo и LiquidCrystal из прошлых уроков были встроены в Trema IDE. С DHT11 так не выйдет — нужную библиотеку нужно поставить. Она называется iarduino_DHT, её сделал тот же магазин, что собрал ваш набор.
Проще всего дать программе разобраться самой: напишите первую строку скетча (она ниже) и нажмите «Проверить». Trema IDE увидит незнакомую строку и сама предложит установить библиотеку — окно так и называется, «Нужна библиотека». Соглашайтесь, установка занимает секунды.
Если окно не появилось, откройте слева раздел «Библиотеки», наберите в поиске iarduino_DHT и нажмите на карточке кнопку «Установить». Для установки нужен интернет — библиотека скачивается из каталога.
Библиотека ставится один раз и остаётся в программе навсегда: в следующих проектах с DHT11 её уже не придётся искать.
Шаг 1. Первые цифры
// Урок 27. Первые цифры: температура и влажность в мониторе порта.
#include <iarduino_DHT.h>
iarduino_DHT sensor(2); // датчик подключён к выводу 2
void setup() {
Serial.begin(9600);
delay(1000); // даём датчику проснуться после включения питания
}
void loop() {
sensor.read(); // спрашиваем датчик: измерь и передай
Serial.print("Температура: ");
Serial.print(sensor.tem, 1);
Serial.print(" C, влажность: ");
Serial.print(sensor.hum, 0);
Serial.println(" %");
delay(2000); // чаще раза в 2 секунды датчик спрашивать нельзя
}
Разберём новые строки.
#include <iarduino_DHT.h>— подключаем библиотеку, как раньше подключалиServo.iarduino_DHT sensor(2);— создаём «свой датчик» и говорим, к какому выводу он подключён. Имяsensorмы выбрали сами, оно может быть любым.sensor.read();— спрашиваем датчик. После этой строки вsensor.temлежит температура, а вsensor.hum— влажность.Serial.print(sensor.tem, 1)— печатаем число с одним знаком после точки. Цифра1в конце и есть «сколько знаков показать».
Откройте монитор порта. Через пару секунд там появятся строки:
Температура: 23.0 C, влажность: 41 %
Температура: 23.0 C, влажность: 41 %
Температура: 23.0 C, влажность: 42 %Подышите на датчик — влажность подскочит до восьмидесяти и будет медленно возвращаться. Накройте его ладонью — поползёт вверх температура. Датчик живой.
После точки всегда ноль — и это не ошибка. DHT11 измеряет целыми градусами, десятых он просто не знает. И ещё: температура почти всегда на градус-два выше, чем в комнате, — плата рядом греется, и датчик это чувствует.
Шаг 2. А если датчик не ответил?
Если в мониторе вместо чисел упрямые нули, значит датчик молчит: провод не в том столбике, забыт резистор или перепутаны выводы. Плохо то, что программа об этом даже не подозревает — она печатает что было.
Так вот: sensor.read() не только читает, но и возвращает ответ — получилось или нет. Проверим его.
// Урок 27. Сначала проверяем ответ датчика, потом печатаем.
#include <iarduino_DHT.h>
iarduino_DHT sensor(2);
void setup() {
Serial.begin(9600);
delay(1000);
}
void loop() {
if (sensor.read() == DHT_OK) {
Serial.print("Температура: ");
Serial.print(sensor.tem, 1);
Serial.print(" C, влажность: ");
Serial.print(sensor.hum, 0);
Serial.println(" %");
} else {
Serial.println("Датчик не ответил");
}
delay(2000);
}
DHT_OK — это готовое слово из библиотеки, означающее «всё хорошо». Теперь программа честно говорит, когда данных нет, а не выдаёт нули за показания. Проверьте: выньте провод данных из макетки — в мониторе побегут «Датчик не ответил».
Шаг 3. Четыре ответа и команда switch
«Не ответил» бывает по разным причинам, и библиотека их различает. Ответов всего четыре:
DHT_OK— данные пришли и сошлись;DHT_ERROR_NO_REPLY— датчик вообще не отозвался;DHT_ERROR_CHECKSUM— ответ пришёл, но искажённым;DHT_ERROR_DATA— ответ не похож на показания DHT.
Писать четыре if подряд некрасиво. Для случая «одно значение, много вариантов» в программах есть отдельная команда — switch.
// Урок 27. Разбираем ответ датчика: switch на все четыре случая.
#include <iarduino_DHT.h>
iarduino_DHT sensor(2);
void setup() {
Serial.begin(9600);
delay(1000);
}
void loop() {
switch (sensor.read()) {
case DHT_OK:
Serial.print("Температура: ");
Serial.print(sensor.tem, 1);
Serial.print(" C, влажность: ");
Serial.print(sensor.hum, 0);
Serial.println(" %");
break;
case DHT_ERROR_NO_REPLY:
Serial.println("Датчик молчит — проверьте провода и питание");
break;
case DHT_ERROR_CHECKSUM:
Serial.println("Ответ пришёл испорченным — помехи на линии");
break;
case DHT_ERROR_DATA:
Serial.println("Ответ не похож на показания DHT");
break;
default:
Serial.println("Что-то совсем непонятное");
break;
}
delay(2000);
}
Читается она просто:
switch (что проверяем)— берём значение один раз;case DHT_OK:— «если получилось вот это, делай следующее»;break;— «на этом всё, из switch выходим». Забыть его — частая ошибка: программа поедет выполнять и следующий случай тоже;default:— «на всё остальное». Полезен, даже если кажется лишним.
Теперь по монитору сразу видно, что не так. Оторвите провод данных — будет «датчик молчит». Возьмите провод подлиннее и потрясите — начнут попадаться «ответ пришёл испорченным».
Шаг 4. Смотрим на график
Помните вкладку «График» из урока про монитор порта? Вот теперь ей найдётся дело. Ей нужны просто числа, по одному в строке, — без подписей.
// Урок 27. Печатаем только число — для вкладки «График».
#include <iarduino_DHT.h>
iarduino_DHT sensor(2);
void setup() {
Serial.begin(9600);
delay(1000);
}
void loop() {
if (sensor.read() == DHT_OK) {
Serial.println(sensor.tem, 1); // одно число в строке, без подписей
}
delay(2000);
}
Откройте вкладку «График» и подышите на датчик: кривая пойдёт вверх ступеньками, а потом медленно вернётся. Ступеньки крупные, потому что датчик даёт целые градусы и отвечает раз в две секунды. Хотите смотреть на влажность — напечатайте вместо sensor.tem строку sensor.hum.
Шаг 5. Опрос по часам, без delay
Пока в программе стоит delay(2000), плата две секунды не делает ничего. Настоящему устройству это не подходит: оно должно успевать следить за кнопкой, мигать, считать время. Возьмём приём из урока про дребезг — часы millis().
// Урок 27. Опрос по часам: между замерами плата не стоит на месте.
#include <iarduino_DHT.h>
iarduino_DHT sensor(2);
const int LED = 13; // встроенный светодиод платы
unsigned long lastRead = 0; // когда последний раз спрашивали датчик
unsigned long lastBlink = 0; // когда последний раз переключали светодиод
bool ledOn = false;
void setup() {
Serial.begin(9600);
pinMode(LED, OUTPUT);
delay(1000);
}
void loop() {
unsigned long now = millis();
if (now - lastRead >= 2000) {
lastRead = now;
if (sensor.read() == DHT_OK) {
Serial.print("Температура: ");
Serial.print(sensor.tem, 1);
Serial.print(" C, влажность: ");
Serial.print(sensor.hum, 0);
Serial.println(" %");
} else {
Serial.println("Датчик не ответил");
}
}
if (now - lastBlink >= 250) {
lastBlink = now;
ledOn = !ledOn;
digitalWrite(LED, ledOn);
}
}
Датчик спрашивается раз в две секунды, а встроенный светодиод платы мигает четыре раза в секунду — и одно другому не мешает. Именно так и собирают устройства, где датчик — только одна из забот.
Спрашивать датчик чаще, чем раз в две секунды, бессмысленно: он не успевает сделать новое измерение и отвечает ошибкой. Число 2000 в программе — не прихоть, а требование датчика.
Шаг 6. Сигнал «стало жарко»
Сделаем из датчика простейший сторож: как только теплее 26 градусов — светодиод горит. Чтобы он не мигал на границе, поставим два разных порога — приём из урока про датчик света.
// Урок 27. Светодиод загорается, когда в комнате стало жарко.
#include <iarduino_DHT.h>
iarduino_DHT sensor(2);
const int LED = 13; // встроенный светодиод платы
const float TEM_ON = 26.0; // выше этого — зажигаем
const float TEM_OFF = 24.0; // ниже этого — гасим
bool warm = false; // сейчас жарко?
void setup() {
Serial.begin(9600);
pinMode(LED, OUTPUT);
delay(1000);
}
void loop() {
if (sensor.read() == DHT_OK) {
if (!warm && sensor.tem >= TEM_ON) {
warm = true;
}
if (warm && sensor.tem <= TEM_OFF) {
warm = false;
}
digitalWrite(LED, warm);
Serial.print(sensor.tem, 1);
if (warm) {
Serial.println(" C — жарко");
} else {
Serial.println(" C — нормально");
}
}
delay(2000);
}
Загорается на 26 градусах, гаснет только на 24. Между ними лампа не меняет решения, и дребезга на границе нет. Проверить легко: подержите датчик в ладони.
Здесь работает встроенный светодиод платы, поэтому паять и втыкать ничего не нужно. Хочется ярче — поставьте светодиод на вывод 10 через резистор 470 Ом, как в уроке 5, и замените в программе 13 на 10.
Не работает? Разбираемся
- Ошибка сборки «iarduino_DHT.h: No such file or directory» — библиотека не установлена. Вернитесь к разделу «Ставим библиотеку».
- Каждый раз «датчик молчит» — проверьте провод данных: он должен идти из столбика вывода 2 датчика на вывод 2 платы. Заодно проверьте резистор: без него молчание — обычное дело.
- В мониторе нули — это старая программа из шага 1, она печатает показания, не спросив, получились ли они. Возьмите вариант с проверкой.
- Показания появляются через раз — плохой контакт или слишком длинные провода. Пошевелите датчик в макетке: если ошибки идут волной, дело в контакте.
- Влажность упёрлась в 90 или в 20 — это границы датчика. Подышали слишком усердно: дайте ему минуту-две, показания вернутся сами.
- Температура выше, чем на настоящем термометре — так и будет. Датчик стоит рядом с греющейся платой, да и точность у него ±2 градуса.
- Датчик заметно горячий на ощупь — немедленно выньте USB: скорее всего питание попало не на те выводы. Пересчитайте их, держа датчик решёткой к себе.
Задания для тренировки
- РазминкаПечатайте только влажность и посмотрите на неё во вкладке «График». Подышите на датчик и дождитесь, пока кривая вернётся к обычным значениям — сколько это заняло?
- ПосложнееДобавьте в монитор строку «сухо», когда влажность ниже 30 %, и «сыро», когда выше 60 %. В остальных случаях пусть будет «нормально».
- Со звёздочкой ⭐Пусть программа помнит самую низкую и самую высокую температуру за всё время работы и печатает их рядом с текущей.
Разбор задания со звёздочкой
Хитрость одна: нельзя начинать с нулей. Если записать в «минимум» ноль, комнатные плюс двадцать три его никогда не побьют, и минимум навсегда останется нулём. Поэтому первый удачный замер задаёт сразу и минимум, и максимум — за этим следит отдельная переменная haveNumbers.
// Урок 27. Разбор задания: помним самое холодное и самое жаркое.
#include <iarduino_DHT.h>
iarduino_DHT sensor(2);
float lowest = 0;
float highest = 0;
bool haveNumbers = false; // был ли уже хоть один удачный замер
void setup() {
Serial.begin(9600);
delay(1000);
}
void loop() {
if (sensor.read() == DHT_OK) {
if (!haveNumbers) {
lowest = sensor.tem; // первый замер задаёт и минимум, и максимум
highest = sensor.tem;
haveNumbers = true;
}
if (sensor.tem < lowest) {
lowest = sensor.tem;
}
if (sensor.tem > highest) {
highest = sensor.tem;
}
Serial.print("Сейчас ");
Serial.print(sensor.tem, 1);
Serial.print(" C, минимум ");
Serial.print(lowest, 1);
Serial.print(" C, максимум ");
Serial.print(highest, 1);
Serial.println(" C");
}
delay(2000);
}
Тот же приём годится для любых «рекордов»: самая яркая вспышка, самое долгое нажатие, самая быстрая реакция.
Что мы узнали
- Датчики бывают аналоговые (отдают напряжение, значение угадываем сами) и цифровые (считают сами и присылают готовые числа).
- Цифровому датчику нужен разговор по правилам, и его ведёт библиотека. Библиотеку можно поставить в Trema IDE из каталога — программа предложит это сама.
- На линии данных нужен подтягивающий резистор: участники разговора умеют только прижимать линию к минусу.
- Чтение может не получиться, и хорошая программа это проверяет. Разбирать несколько вариантов ответа удобно командой
switch. - У любого датчика есть предел скорости: DHT11 отвечает раз в две секунды, и спрашивать его чаще бесполезно.
Теперь у нас есть экран, который умеет показывать текст, и датчик, который знает погоду в комнате. В следующем уроке соединим их вместе и соберём настоящую метеостанцию — с цифрами на экране и без компьютера.
Частые вопросы
Как подключить датчик DHT11 к Arduino?
Датчик ставят в макетную плату решёткой к себе. Первый вывод идёт на плюс, четвёртый — на минус, второй — на цифровой вывод платы, а третий не подключается. Между линией данных и плюсом обязательно ставят резистор 10 кОм.
Какая библиотека нужна для DHT11?
iarduino_DHT — её делает тот же магазин, что собрал набор. В Trema IDE она ставится из каталога библиотек: программа сама заметит незнакомую строку include и предложит установку.
Зачем датчику DHT11 резистор 10 кОм?
И плата, и датчик умеют только прижимать линию данных к минусу, а поднимать её обратно некому. Резистор подтягивает линию к плюсу, поэтому в покое на ней единица. Без него показания начинают пропадать.
Почему DHT11 показывает целые градусы, без десятых?
Такая у него точность: разрешение 1 градус и 1 процент, а ошибка до 2 градусов и 5 процентов. Дробная часть в показаниях всегда нулевая, и это нормально.
Как часто можно опрашивать DHT11?
Не чаще одного раза в 2 секунды. Если спрашивать быстрее, датчик не успевает сделать новое измерение и возвращает ошибку вместо показаний.
