Занялся я тут еще небольшим проектом, для которого надо было изучить работу датчика влажности температуры 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) } }
как раз счас тоже занимаюсь влажностью,делаю автоматику сушилки,юзаю sht10,с ним проблем то нет ,он по и2с рулится,у меня другая сложность ,мне его нужно привязать к контроллеру овен,по modbus rtu .сижу голову ломаю!
А нельзя замутить двусторонний конвертер i2c <> modbus ?
PS. Но с modbus я никогда не работал, написал что первое в голову пришло.
я уже сижу на этом модбасе,делаю без контроля четности,вроде должно работать ,но чет пока не работает
а ты кстати где DHT11 приобретал,ни в однгом инет-магазе его нет ,кроме е-бай?
На алиэкспрессе 🙂 Я из Беларуси, а тут с покупкой электроники вообще туго.
вроде как он под мои нужды тоже бы подошел,у меня закасчиком заявленая макс,температура в сушилке 100град, тока мне подойдет DHT22,он по даташиту я посмотрел до 120 град. у него диапазон,я так на всякий случай интересуюсь для след проекта,пока делал эту камеру ,уже есть заинтересованные на следующую!
самое главное он дешевле намного!
ага, DHT22 5 баксов в Китае стоит. Размеры правда вроде побольше чем у sht
sarge,а протокол кан не пытался поднимать?
Не, не было нужды еще в нем.
То что работает отлично. Пришел и мне такой. Прошу у вас весь код а то что-то не могу родить того чего не достает в программе. Откуда например Humflag, и что это
К сожалению исходников проекта полностью у меня не осталось, но то чего вам не достает вы можете выдрать из главного исходника отсюда – http://diymicro.ru/wp-content/uploads/2013/11/HumTempControl.zip
Копайте в сторону прерываний INTE, там больше добавлять нечего.
А Humflag просто статусная переменная, используется для выхода из цикла получения данных от датчика влажности.
Большое спасибо! Очень оперативно. Первые два датчика взял с Dealextrime оказались не рабочие все нули выдавали. Теперь попытка номер два. Логический анализатор в PICkit2 уже показал рабочий семпл с датчика.
Удачных попыток, можете сразу заказывать dht22 если на базе этого какой-то проект планируется, я сейчас жалею, что сразу не взял их.
Мне в ванную. Задумка такая чтоб вентилятор включался при увеличении скорости нарастания влажности. То есть влажность относительная в разное время года разная бывает, а тут душем пользоваться начинаешь, прибор должен делать периодические замеры, если к примеру через 15 секунд влажность увеличилась более (20 единиц к примеру) записать в еепром текущую влажность и включить вентилятор. А затем снова делать замеры и сравнивать со значением из еепром. Как только она сравняется или снизится до значения записанного в память, выключить вентилятор.
Правда у DHT11 сам датчик плохой, он с каким-то органическим напылением. Из за этого при ооочень большом значении влажности он как бы клинит и ещё долго остается в максимуме пока не просохнет…
Хорошая идея с относительными замерами.
Только вот практика показывает, что у него здоровенная инерционность – в ванной куча пара, а он на пару процентов показывает что влажность изменилась, ну и обратно таже история как вы описали.
А как на счет HCH-1000, он правда голый без обвязки. Может его подвязать как задающую емкость для генератора на 555 таймере, а на выходе уже мерить ширину импульса. Что скажете
Скажу, что попахивает дополнительными сложностями на одно место.
С генератором конечно прикольно, но повторяемость паршивая будет, если не использовать 1 процентные резаки для RC цепочки, да и у самих датчков есть разброс.
Мерять емкость по зарядной кривой с компаратором – та же история.
А если для единичного образца и он работает лучше дхт, то может и ок, я с ним не работал и не могу сказать лучше он или хуже.
В общем получилось 😉 Вот только не понятно, почему при захвате байтов у вас отсчитывается по 9 прерываний. Но у меня почему то заработало при значениях больше 2 и меньше 13. С температурой и контрольной суммой аналогично
Потому что мы определяем длительность байта по возрастающему фронту, разрисуйте пакет байт и посчитайте сколько нужно обработать возрастающих фронтов для того, чтобы засечь 8 байт.
Вторую часть вопроса что-то совсем не понял.