Эксперимент #24. Датчик влажности DHT11

Занялся я тут еще небольшим проектом, для которого надо было изучить работу датчика влажности температуры DHT11. В качестве главного проца для проекта выбран хорошо знакомый микроконтроллер pic16f628a. Начинаем как обычно – с чтения даташита.

Типовые характеристики:

Мягко говоря – не очень, надо было брать DHT22.

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

Советуют юзать подтягивающий резак 5 кОм если кабель длиной до 20 метров. Если же кабель длинее, то четких инструкций нет. Вот как должно выглядеть начало передачи: Мк проваливает линию данных в 0 на время хотя бы 18 мс, затем отпускает в 1 и переводит линию в состояние входа – дальше работает датчик. Заодно покажем как выглядит 0: И логическая единица: Как видно из изображений, они отличаются лишь длительностью высокого уровня. Пора немножко попрактиковаться


#include

#define _XTAL_FREQ 12000000
#define State TRISB0
#define HumPin RB0

__CONFIG(WDTDIS & UNPROTECT & LVPDIS & HS);

unsigned char DHTbyte[5];

void main() {

State = 1;
CMCON = 0x07;

PEIE = 1;
INTEDG = 0;                 \\Работаем по спадающему фронту
HumPin = 1;                 \\Подтягиваем линию к питанию

for (;;)
{
if (!RB1)
  {
    __delay_ms(100); \\Антидребезг
    State = 1;
    State = 0;
    HumPin = 0;             \\Проваливаем линию
    __delay_ms(20);         \\Ждем около 20мс
    State = 1;
    HumPin = 1;             \\Подтягиваем к питанию
    __delay_us(40);         \\Ждем 40мкс
    State = 1;

  }//if
}//while(1)

}//main

Кстати если кто-то внимательно читает мои коды, то заметит, что частота кварца увеличена до 12 МГц вместо моих обычных 4. Дело в том, что для адекватной работы кода нужно более быстрое тактирование, хватило бы и 8 МГц, но такого кварца под рукой у меня не было. Результат работы: Здесь видны провалы от мк (самые первые),  затем следующая комбинация 0 -> 1, с длиной импульсов 80 мкс. Напоследок, после последнего бита данных датчик проваливает линию на 50 мкс. Еще немного информации к размышлению, пакет данных состоит из 5 байт, каждый байт начинается со старшего бита: 1 байт влажности – пустой байт – 1 байт температуры – пустой байт – байт с контрольной суммой. Пустые байты здесь я так подозреваю из-за одной и той же реализации протокола в dht11 и dht22, в последнем датчике вместо пустых там передаются десятые доли влажности и температуры ( да и диапазоны измерений у последнего пошире и пореальнее ). Ну в принципе все важная инфа уже озвучена, теперь решаем как будем декодировать 1 и 0. Нам нужно декодировать временные промежутки, я для себя делал примерно так: По каждому возрастающему фронту снимаем значение таймера и запускаем таймер заново: если время больше 80 мкс то это 1, если меньше 0. Вроде все просто и прозрачно. Правда тут меня тоже ждала небольшая засада – расчет с реальностью сходится не желал. Я настроил таймер на проход в 1.33 мкс и отладка показала, что 0 соответствует 48 прогонам = 63.84 мкс, а никак не 78 мкс. Ну ничего не поделаешь мы работаем с реальным девайсом, так что и вбиваем реальные цифры. Ну вот собственно и код функции:


void GetRHandTemp()
{
   INTE = 0;                //Вырубаем прерывания по RB0
   DHTbyte[0] = 0;          //Байт для влажности
   DHTbyte[1] = 0;          //Байт для температуры
   DHTbyte[2] = 0;          //Байт для контрольной суммы
   Humflag = 0;
   IsrCount = 0;            //Со старта обнуляем количество прерываний
   State = 1;               //Проваливаем линию на 20 мс
   State = 0;
   HumPin = 0;
   __delay_ms(20);
   State = 1;
   HumPin = 1;
   __delay_us(40);
   State = 1;
   INTEDG = 0;              //Прерывания по спадающему фронту
   INTE = 1;

while (!Humflag)
{

  if (InteFlag)
     {
      INTE = 0;
      if (IsrCount==2) INTEDG = 1;         //После двух срабатываний меняем направление на противоположное
      if ((IsrCount > 2) && (IsrCount < 12)) //Байт влажности
         {
          DHTbyte[0]<<=1;
          if (tempTmr0>50) DHTbyte[0] |= 0b00000001;
          InitTimer0();
         }

      if ((IsrCount > 18) && (IsrCount < 28))      //Байт температуры
         {
          DHTbyte[1]<<=1;
          if (tempTmr0>50) DHTbyte[1] |= 0b00000001;
          InitTimer0();
         }

      if ((IsrCount > 34) && (IsrCount < 44))     //Контрольная сумма
         {
          DHTbyte[2]<<=1;
          if (tempTmr0>50) DHTbyte[2] |= 0b00000001;
          InitTimer0();
         }

 InteFlag = 0;
 INTE = 1;
 }//if (InteFlag)

 if (IsrCount>=43)                 //Все нужные фронты пойманы
 {
   Humflag = 1;                    //Условие выхода из цикла
   INTE = 0;
   lcd_clear();
   lcd_goto(0x00);
   lcd_puts("RH");
   lcd_goto(0x06);
   lcd_puts("Temp");
   display_digit(DHTbyte[0],0x40);  //выводим влажность на экран
   display_digit(DHTbyte[1],0x46);  //выводим температуры
   lcd_goto(0x48);
   lcd_putch(0b11011111); //градус
   lcd_putch(0b01000011); //С
   lcd_goto(0x0E);
   if (DHTbyte[2] == (DHTbyte[0]+DHTbyte[1]))
      lcd_puts("ok");                //если контрольная сумма совпала
    else
       lcd_puts("er");               //если не совпала
} //if (IsrCount>=43)
 }
}

Тестим:

Работает!

Эксперимент #24. Датчик влажности DHT11: 20 комментариев

  1. как раз счас тоже занимаюсь влажностью,делаю автоматику сушилки,юзаю sht10,с ним проблем то нет ,он по и2с рулится,у меня другая сложность ,мне его нужно привязать к контроллеру овен,по modbus rtu .сижу голову ломаю!

    • А нельзя замутить двусторонний конвертер i2c <> modbus ?
      PS. Но с modbus я никогда не работал, написал что первое в голову пришло.

  2. я уже сижу на этом модбасе,делаю без контроля четности,вроде должно работать ,но чет пока не работает

  3. вроде как он под мои нужды тоже бы подошел,у меня закасчиком заявленая макс,температура в сушилке 100град, тока мне подойдет DHT22,он по даташиту я посмотрел до 120 град. у него диапазон,я так на всякий случай интересуюсь для след проекта,пока делал эту камеру ,уже есть заинтересованные на следующую!

  4. То что работает отлично. Пришел и мне такой. Прошу у вас весь код а то что-то не могу родить того чего не достает в программе. Откуда например Humflag, и что это

    • К сожалению исходников проекта полностью у меня не осталось, но то чего вам не достает вы можете выдрать из главного исходника отсюда – http://diymicro.ru/wp-content/uploads/2013/11/HumTempControl.zip

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

      • Большое спасибо! Очень оперативно. Первые два датчика взял с Dealextrime оказались не рабочие все нули выдавали. Теперь попытка номер два. Логический анализатор в PICkit2 уже показал рабочий семпл с датчика.

        • Удачных попыток, можете сразу заказывать dht22 если на базе этого какой-то проект планируется, я сейчас жалею, что сразу не взял их.

          • Мне в ванную. Задумка такая чтоб вентилятор включался при увеличении скорости нарастания влажности. То есть влажность относительная в разное время года разная бывает, а тут душем пользоваться начинаешь, прибор должен делать периодические замеры, если к примеру через 15 секунд влажность увеличилась более (20 единиц к примеру) записать в еепром текущую влажность и включить вентилятор. А затем снова делать замеры и сравнивать со значением из еепром. Как только она сравняется или снизится до значения записанного в память, выключить вентилятор.
            Правда у DHT11 сам датчик плохой, он с каким-то органическим напылением. Из за этого при ооочень большом значении влажности он как бы клинит и ещё долго остается в максимуме пока не просохнет…

            • Хорошая идея с относительными замерами.
              Только вот практика показывает, что у него здоровенная инерционность – в ванной куча пара, а он на пару процентов показывает что влажность изменилась, ну и обратно таже история как вы описали.

              • А как на счет HCH-1000, он правда голый без обвязки. Может его подвязать как задающую емкость для генератора на 555 таймере, а на выходе уже мерить ширину импульса. Что скажете

                • Скажу, что попахивает дополнительными сложностями на одно место.
                  С генератором конечно прикольно, но повторяемость паршивая будет, если не использовать 1 процентные резаки для RC цепочки, да и у самих датчков есть разброс.
                  Мерять емкость по зарядной кривой с компаратором – та же история.
                  А если для единичного образца и он работает лучше дхт, то может и ок, я с ним не работал и не могу сказать лучше он или хуже.

  5. В общем получилось 😉 Вот только не понятно, почему при захвате байтов у вас отсчитывается по 9 прерываний. Но у меня почему то заработало при значениях больше 2 и меньше 13. С температурой и контрольной суммой аналогично

    • Потому что мы определяем длительность байта по возрастающему фронту, разрисуйте пакет байт и посчитайте сколько нужно обработать возрастающих фронтов для того, чтобы засечь 8 байт.
      Вторую часть вопроса что-то совсем не понял.

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.