Рейтинг@Mail.ru

Как подключить датчик температуры и влажности DHT11 к Arduino

автор:
6 comments Arduino
Print Friendly, PDF & Email

Датчик температуры и влажности DHT11 – популярный и дешёвый датчик, который можно использовать в довольно широком диапазоне температур и относительной влажности. Давайте посмотрим, как подключить его к Arduino и как считывать с него данные.

Нам понадобится:

1Технические характеристики датчика температуры и влажности DHT11

Итак, датчик DHT11 имеет следующие характеристики:

  • диапазон измеряемой относительной влажности – 20..90% с погрешностью до 5%,
  • диапазон измеряемых температур – 0..50°C с погрешностью до 2°C;
  • время реакции на изменения влажности – до 15 секунд, температуры – до 30 секунд;
  • минимальный период опроса – 1 секунда.
Габаритные размеры и внешний вид датчика температуры и влажности DHT11
Габаритные размеры и внешний вид датчика температуры и влажности DHT11

Как видно, датчик DHT11 не отличается особой точностью, да и диапазон температур не охватывает отрицательные значения, что вряд ли подойдёт для наружных измерений в холодное время года при нашем климате. Однако малая стоимость, малый размер и простота работы с ним частично перекрывают эти недостатки. На рисунке приведён внешний вид датчика и его размеры в миллиметрах.

2Схема подключения датчика температуры и влажности DHT11

Рассмотрим схему подключения датчика температуры и влажности DHT11 к микроконтроллеру, в частности, к Arduino.

Схема подключения датчика температуры и влажности DHT11
Схема подключения датчика температуры и влажности DHT11

Давайте посмотрим, что показано на рисунке.

Обозначение на рисункеОписаниеПримечание
MCU Микроконтроллер или одноплатный компьютерArduino / Raspberry Pi и др.
DHT11 Датчик температуры и влажностиВыводы 1Pin, 2Pin и 4Pin задействованы в схеме, один из выводов датчика – 3-ий пин 3Pin – ни к чему не подключается.
DATA Шина данныхЕсли длина соединительного кабеля от датчика к микроконтроллеру не превышает 20 метров, то эту шину рекомендуется подтянуть к питанию резистором 5,1 кОм; если больше 20 метров – то другой подходящий номинал (меньший).
VDD Питание датчикаДопустимы напряжения от ~3,0 до ~5,5 вольт постоянного тока; если используется питание ~3,3 В, то желательно использовать питающий провод не длиннее 20 см.

Соберём рассмотренную схему. Я также по традиции включу в цепь логический анализатор, чтобы можно было изучить временную диаграмму информационного обмена с датчиком.

Сенсор температуры и влажности DHT11 подключён к Arduino UNOСенсор температуры и влажности DHT11 подключён к Arduino UNO
Сенсор температуры и влажности DHT11 подключён к Arduino UNO

Сенсор DHT11 часто продаётся в виде готовой сборки с необходимой обвязкой – подтягивающими резистором и фильтрующим конденсатором (как на предыдущей фотографии). Для экспериментов с Arduino я рекомендую покупать именно такой.

3Считывание данных с сенсора DHT11 при помощи Arduino

Давайте пойдём таким путём: скачаем библиотеку для датчика DHT11 (также приложил её в конце статьи, т.к. у обновлённой библиотеки изменились вызываемые функции), установим её стандартным способом (распаковав в директорию \libraries\ среды разработки для Arduino).

Напишем вот такой простенький скетч. Он будет выводить в последовательный порт компьютера каждые 2 секунды сообщения об относительной влажности и температуре, считанные с датчика DHT11.

#include <dht11.h> // подключаем библиотеку
dht11 sensor; // инициализация экземпляра датчика
#define DHT11PIN 8 // вывод 8 будет шиной DATA

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

void loop() {
  int chk = sensor.read(DHT11PIN);

  Serial.print("h=");
  Serial.print(sensor.humidity);
  Serial.print("%\t");

  Serial.print("t=");
  Serial.print(sensor.temperature);
  Serial.println("C");
  
  delay(2000);
}

Загрузим этот скетч в Arduino. Подключимся к Arduino с помощью монитора COM-порта и увидим следующее:

Данные о температуре и влажности, полученные с датчика DHT11
Данные о температуре и влажности, полученные с датчика DHT11

Видно, что данные и о влажности, и о температуре считываются и выводятся в терминалку.

4Временная диаграмма информационного обмена датчика температуры и влажности DHT11 с микроконтроллером

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

Для связи с микроконтроллером датчик температуры и влажности DHT11 использует однопроводный последовательный пакетный интерфейс. Один информационный пакет длительностью около 4 мс содержит: 1 бит запроса от микроконтроллера, 1 бит ответа датчика и 40 битов данных от датчика (16 битов информации о влажности, 16 битов информации о температуре и 8 проверочных битов). Давайте подробнее рассмотрим временную диаграмму информационного обмена Arduino с датчиком DHT11.

Временная диаграмма информационного обмена датчика температуры и влажности DHT11 с микроконтроллеромВременная диаграмма информационного обмена датчика температуры и влажности DHT11 с микроконтроллером
Временная диаграмма информационного обмена сенсора DHT11 с микроконтроллером

Из рисунка видно, что есть два типа импульсов: короткие и длинные. Короткие в данном протоколе обмена обозначают нули, длинные импульсы – единицы.

Итак, первые два импульса – это запрос Arduino к DHT11 и, соответственно, ответ датчика. Далее идут 16 бит влажности. Причём они разделены на байты, старший и младший, старший слева. То есть на нашем рисунке данные о влажности такие: 0001000000000000 = 00000000_00010000 = 0x10 = 16% относительной влажности.

Данные о температуре, аналогично: 0001011100000000 = 00000000_00010111 = 0x17 = 23 градуса Цельсия.

Контрольная сумма – это всего-навсего арифметическое суммирование 4-х полученных байтов данных:
00000000 +
00010000 +
00000000 +
00010111 =
00100111 в двоичной системе или 0 + 16 + 0 + 23 = 39 в десятичной.

5Работа с датчиком DHT11 без библиотеки

Теперь мы знаем достаточно для того чтобы написать собственную программу для работы с сенсором температуры и влажности DHT11 без использования сторонних библиотек. Напишем скетч, который будет опрашивать раз в секунду датчик и выводить в последовательный порт компьютера принятый пакет и данные о температуре, влажности, а также проверочный байт. На 13-ую ножку Arduino выведем контрольный сигнал и, подключившись в ней логическим анализатором, проверим, что мы верно считываем информацию от датчика.

Скетч для работы с DHT11 и Arduino без сторонних библиотек (разворачивается)
#define DHT11pin 8 // для подключения шины DATA сенсора DHT11
#define LEDpin 13  // используем для контроля

const int NUM_READS = 500; // зависит от частоты кварца и подбирается экспериментально
long readsCounter = 0; // счётчик циклов чтения
int reads[NUM_READS]; // сырой массив считанных значений

void setup() {
  Serial.begin(9600);
  pinMode(DHT11pin, INPUT);
  pinMode(LEDpin, OUTPUT); 
}

void loop() {
  if (readsCounter < NUM_READS) {
    readSerialDHT11();
  }
  else {
    delay(1000); // задержка ПЕРЕД запросом
    processDht11Data(); // обрабатываем данные из прошлого цикла
    initLink(); // инициализируем новый цикл обмена
    resetVals();
  }
}

// Посылает импульс инициализации обмена с DHT11:
void initLink() {
  pinMode(DHT11pin, OUTPUT);
  digitalWrite(DHT11pin, LOW);
  delay(15);
  pinMode(DHT11pin, INPUT);
}

// Читает данные датчика DHT11 и записывает в массив:
void readSerialDHT11() {
    int sensorValue = digitalRead(DHT11pin);
    reads[readsCounter] = sensorValue;
    digitalWrite(LEDpin, sensorValue); // для проверки выводим на отдельную ножку
    readsCounter++;
}

// Обрабатывает массив данных за цикл с DHT11:
void processDht11Data() {
  byte dht11Data[41] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // обработанный массив (биты пакета)
  int zeroLen = 1; // минимальная длительность бита "0"
  int oneLen = 3 * zeroLen; // примерная длительность бита "1"
  int wrongData = 6 * zeroLen; // допуск по длительности для данных 
  int currentBitLen = 0; // длительность текущего бита
  int bitPosition = 0; // позиция бита в пакете
  
  for (int i=1; i<NUM_READS-1; i++) { // пропускаем первый импульс-подтверждение
    if ((reads[i] == 0) && (reads[i+1] == 1)) { // если пришёл передний фронт
      // Принимаем решение: предыдущий бит - это "0" или "1":
      if ((currentBitLen >= zeroLen) && (currentBitLen <= oneLen)) {
        dht11Data[bitPosition] = 0;
        bitPosition++;
      }
      else if ((currentBitLen < oneLen) && (currentBitLen <= wrongData)) {
        dht11Data[bitPosition] = 1;
        bitPosition++;
      }
      currentBitLen = 0;
    }
    else {
      if (reads[i] == HIGH) { // при сигнале HIGH
        currentBitLen += 1; // считаем длительность текущего бита
      }
    }
  }

  for (int i=0; i<41; i++) {
    Serial.print(dht11Data[i]);
    Serial.print(" ");
  }
  Serial.println();
  getHumidTemperatureParity(dht11Data);   
}

// Получает данные о влажности, температуре из пакета DHT11
void getHumidTemperatureParity(byte data[]) {
  word humidity = 0;
  byte hLow = 0; 
  byte hHi = 0;
  word temperature = 0;
  byte tLow = 0;
  byte tHi = 0;
  byte parity = 0;
  for (int i=1; i<9; i++){ //пропускаем первый импульс-подтверждение
    hLow = hLow | (data[i] << (8 - i));
  }  
  for (int i=9; i<17; i++){
    hHi = hHi | (data[i] << (16 - i));
  }
  for (int i=17; i<25; i++){
    tLow = tLow | (data[i] << (24 - i));
  }
  for (int i=25; i<33; i++){
    tHi = tHi | (data[i] << (32 - i));
  }
  for (int i=33; i<41; i++){
    parity = parity | (data[i] << (40 - i));
  }
  
  humidity = word(hHi, hLow);
  temperature = word(tHi, tLow);

  Serial.print("h=");
  Serial.print(humidity);
  Serial.print("%\t");
  
  Serial.print("t=");
  Serial.print(temperature);
  Serial.print("C\t");

  Serial.print("parity=");
  Serial.println(parity); 
}

// Сбрасывает переменные в исходное состояние:
void resetVals() {
  readsCounter = 0; 
}

Небольшая таблица даст дополнительные разъяснения к предлагаемому решению.

ФункцияНазначениеКомментарий
initLink()Посылает импульс инициализации обмена с DHT11.В режиме INPUT цифровые выводы Arduino находятся в состоянии "1". Мы переводим их в режим OUTPUT и на 15 мс опускаем в "0", что служит сигналом начала обмена для датчика DHT11.
readSerialDHT11()Читает данные датчика DHT11 и записывает в массив.Постоянно опрашиваем состояние линии DATA, записываем принятые данные в массив (до верхней границы массива), выводим для проверки на 13-ый пин Arduino принятые данные (это нужно было мне для отладки, в «чистовом» коде этот кусок можно убрать).
processDht11Data()Обрабатывает массив данных, принятых за один цикл (один пакет).По передним фронтам принятых импульсов фиксируем факт пришедшего нового бита и считаем в условных единицах его длительность. По длительности оцениваем – это бит-единица или бит-ноль (в некоторых заданных пределах). Составляем пакет из 41 бита.
getHumidTemperatureParity()Получает данные о влажности, температуре из пакета.Выделяем из 41 бита пакета данные о влажности, температуре и контрольную сумму.
resetVals()Сбрасывает переменные в исходное состояние.При расширении программы здесь могут появиться ещё переменные, требующие сброса.

Вот так будет выглядеть временная диаграмма. Здесь A – это сигнал в шине DATA датчика DHT11, B – считываемый сигнал.

Временная диаграмма информационного обмена DHT11 с Arduino и контрольный сигнал
Временная диаграмма информационного обмена DHT11 с Arduino (A) и считанные контрольные значения на выводе 13 (B)

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

Принятые и расшифрованные данные сенсора DHT11 в мониторе COM-порта
Принятые и расшифрованные данные сенсора DHT11 в мониторе COM-порта

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

Кстати, я уже упоминал несколько раз в других статьях о чудесном устройстве для любителей электроники и изучения разнообразных протоколов – Flipper Zero. Недавно у Флиппера появилось приложение для чтения показаний датчиков температуры, в том числе и DHT11:

Flipper Zero читает показания датчика температуры-влажности DHT11
Flipper Zero читает показания датчика температуры-влажности DHT11

Download attachments:

Last modified onВоскреснье, 11 Февраль 2024 19:37 Read 21780 times
Ключевые слова: :

Поблагодарить автора:

Поделиться

Print Friendly, PDF & Email

6 comments

  • Горчаков
    Горчаков Четверг, 04 Ноябрь 2021 04:19 Ссылка на комментарий

    программа не компилируется в строке for (int i=1; i= zeroLen) && (currentBitLen

  • aave1
    aave1 Четверг, 04 Ноябрь 2021 10:51 Ссылка на комментарий

    Дело в том, что там знак "меньше" или "больше", который редактор воспринял как html тег, и часть кода после него спрятал. Я забыл заменить его спецсимволом. Поправил, теперь всё будет компилироваться. Спасибо большое за замечание!

  • Горчаков
    Горчаков Четверг, 04 Ноябрь 2021 12:01 Ссылка на комментарий

    Отлично! Как быстро вы среагировали.Замечательная работа.Премного благодарен.

  • Горчаков
    Горчаков Четверг, 04 Ноябрь 2021 13:05 Ссылка на комментарий

    Огромное спасибо за быструю реакцию.Теперь программа транслируется,однако выдает одни нули. Не можете ли подсказать почему?Может скорость поменять?

  • Горчаков
    Горчаков Четверг, 04 Ноябрь 2021 13:11 Ссылка на комментарий

    Датчик совершенно точно исправен, так как с библиотекой он выдает разумные значения 25 и 22.Значит что-то с программой не так. Правда у меня не совсем ардуино, а китайский клон wavgat Uno R3,там вроде какой-то другой процессор стоит.Вы писали, что скорость нужно подбирать,а как?

  • Горчаков
    Горчаков Четверг, 04 Ноябрь 2021 13:17 Ссылка на комментарий

    Кстати, я проверил как считается контрольная сумма, так вот иногда в дробной части проскакивает единица и тогда будет ошибка. Видимо все-таки нужно складывать все четыре байта, чтобы получить сумму и сравнивать ее с контрольной-тогда ошибок будет меньше.

Leave a comment