Читаем показания DHT без библиотеки.
- Войдите на сайт для отправки комментариев
Втр, 14/07/2015 - 07:41
При опросе двух датчиков DHT21 с помощью библиотек заметил, что скетч "тормозится". Чтение одного DHT занимает до 250 мс. По даташиту опрос датчика должен уложиться примерно в 5 мс.
Как происходит общение МК с DHT21-DHT22. Для начинающих:)
Датчик молчит-на линии высокий уровень. МК прижимает линию к земле минимум на 800 мкс. Далее отпускает линию и подтягивающий резистор тянет её вверх. Заметьте, не МК тянет вверх!! МК переводит пин на ввод, а не устанавливает "1" на пине. В даташитах по этому поводу очень "скользко" . Здесь работает схемное "И": высокий уровень на линии если: И МК не тянет вниз ("1"), И DHT не тянет вниз ("1"). Низкий уровень на линии если: МК тянет вниз или DHT тянет вниз.
От импульса отрицательной полярности DHT "просыпается" и через 20-40 мкс (даже до 200 мкс) притягивает линию к земле на 80 мкс. Затем отпускает на 80 мкс. Снова прижимает на 50 мкс и отпускает.
Начинается первый импульс положительной полярности, несущий информацию "0" или "1". Длительность в 26 мкс соответствует "0", а 70 мкс - "1". Всё что нужно это прочитать 40 таких положительных импульсов различной длительности.
Скетч прилагаю.
// Mega uint8_t data[5]; const byte DHT1_pin = 22; const byte DHT2_pin = 24; const unsigned int interval = 1000; void setup(){ Serial.begin(9600); } void loop(){ int hum1 = 0, temp1 = 0; int hum2 = 0, temp2 = 0; static unsigned long prevMillis = 0; if(millis() - prevMillis > interval){ prevMillis += 1000; if(readingDHT(DHT1_pin)){ //если контрольная сумма верна hum1 = (data[0] << 8) | data[1];//считаем Н и Т первого датчика temp1 = ((data[2] & 0x7F) << 8) | data[3]; if(data[2] & 0x80) temp1 *= -1; }else{ //ошибка DHT1 } if(readingDHT(DHT2_pin)){ hum2 = (data[0] << 8) | data[1]; temp2 = ((data[2] & 0x7F) << 8) | data[3]; if(data[2] & 0x80) temp2 *= -1; }else{ //ошибка DHT2 } Serial.print("hum1 = "); Serial.print(hum1 /10); Serial.print('.'); Serial.println(hum1 %10); Serial.print("tem1 = ");Serial.print(temp1 /10); Serial.print('.'); Serial.println(temp1 %10); Serial.print("hum2 = ");Serial.print(hum2 /10); Serial.print('.'); Serial.println(hum2 %10); Serial.print("tem2 = ");Serial.print(temp2 /10); Serial.print('.'); Serial.println(temp2 %10); Serial.println(); } } //=============================================== boolean readingDHT(byte pin) { boolean state = HIGH; //состояние линии byte counter = 0, j = 0; const byte count = 5; for(byte i=0; i<5; i++){ data[i] = 0; } pinMode(pin, OUTPUT); digitalWrite(pin, LOW); delay(1); //более 800mks нужно чтобы рабудить датчик DHT21-22 //delay(18); //для DHT11 //cli(); //отключить прерывания если нужно pinMode(pin, INPUT); //начинаем слушать датчик for(byte i = 0; i < 83; i++){//читаем 83 сост линии counter = 0; while (digitalRead(pin) == state) {//state==1 первый проход counter++; delayMicroseconds(4);//if 4 mkc count==3-7 if (counter > 20) break; }//end while state = !state;//digitalRead(_pin); if (counter > 20) break; if ((i > 3) && !(i & 1)) {//i%2 записать каждый бит в байты хранения data[j >> 3] <<= 1; //читаем с 5(i=4) состояния(1,0,1,0,?,0,?,0,...?) if (counter > count) data[j>>3] |= 1;//counter>3-10 дальше ошибки j++; } }//end for //sei(); //включить прерывания uint8_t sum = data[0] + data[1] + data[2] + data[3]; if(sum == data[4]) return 1; else return 0; }
Да, по даташиту DHT21-22 нужно опрашивать не чаще раза в 2сек.
Поэтому в строке 5 нужно interval=2000; а в 16 - prevMillis +=2000; или понятней - prevMillis +=interval;
Но и при опросе каждую сек показания датчиков не повторяются при изменении температуры и влажности.
Я читаю данные с DHT22 при помощи функции pulseIn, все выглядит гораздо лучше, понятнее и никакой магии. Если нужно - могу свою переделанную библиотеку оно Adafruit дать, вытащите оттуда функцию.
SunX, выкладывайте свою библиотеку, раз уж лучше и понятней. Это замечательно, когда много примеров хороших и разных...
А про какую магию говорите?
Вот: https://github.com/SunAngel/DHT-sensor-library
Я вот про эту counter-магию:
Оно все работает и наверное даже правильно, но зато совершенно непонятно, почему все так.
PS: Примеры в моей измененной библиотеке естественно не работают, так как их я не переписывал. Так же в этой либе возвращаются температура и влажность умноженные на 10, что бы не использовать float и для других нужных мне вещей, но, думаю, Вы с этим спокойно справитесь.
Очень знакомая библиотека)) Если её ещё подправить, будет лучше, меньше тормозить. Все отличия в pulseIn и заключаются.
Про "магию" раскажу как время будет.
Ну не удивлюсь, если Adafruit ее в свою очередь где-то еще потырили %) Ну или кто-то потырил у них.
Как эта counter-магия работает я вполне понимаю, просто не понимаю, зачем так извращаться =).
Я вот про эту counter-магию:
Оно все работает и наверное даже правильно, но зато совершенно непонятно, почему все так.
В цикле while задержка складывается из delayMicrosecond(4) ==4mks (даже чуть больше) и чтение пина digitalRead(pin) == около 4-6 мкс, которые в сумме дают около 9мкс. За 6 проходов while получаем задержку около 50мкс. В это время положительный импульс 26мкс, соответствующий "0" уже закончился, а 70мкс импульс "1" ещё не закончился.
С pulseIn функция readingDHT(DHT_pin) выглядит попроще.
Коммент в строке 18 читать как: сдвигаем влево на 1, а в младший бит пишется "0"
Попробовал оба варианта кода — со старой функцией readingDHT, с упрощённым вариантом с pulseIn. В обоих случаях hum1 и temp1 (у меня один датчик) равны нулю. Пробовал использовать также библиотеку (скетч), с ней всё работает корректно. Самое странное, что даже если добавить в этот код посылку сообщения об ошибке, оно никогда не будет послано — код считает, что всё в порядке. Помогите!
Если зарядить в блюпиле таймер
то можно получить аппаратно, без задержек вывод с датчика и его обработать.
Про этом получение данных не зависит от типа 11 или 22. Различается только обработка. Одна проблема - нога входа таймера фиксирована РА7.
У меня появилась мысль, что, возможно, у Петра в скетче есть ошибка контрольной суммы, которая проявляется тем, что humidity и temperature равны нулю.
Мысль то откуда? Что выводить то если КС не сошлась? Некоторые выводят NaN.
Давно это было... С тех пор и не использую эти датчики. Может прерывания мешают? Пробовали запрещать перед опросом датчика?
Пробовал, не помогло...
Библиотека для CVAVR, но в принципе несложно перевести в Arduino
Интересно, что оно вот здесь возвращает? И почему так?
43
temp = (data[0]<<8)+(data[2]);
//data[0]-humidity, data[2]-temperature
return temp;
если temp обьявлен как int
Интересно, что оно вот здесь возвращает? И почему так?
43
temp = (data[0]<<8)+(data[2]);
//data[0]-humidity, data[2]-temperature
Если ардуина оригинальная, то она сама разберется, а если китайская - то...
Давно работал, забыл уже. Это для DHT11, он дает только целую часть процента влажности , а дробная равно 0.
Процесс коммуникации
Формат данных DHT11/DHT22
Когда датчик влажности и температуры отправляет данные, он сначала отправляет MSb (Most Significant Bit) — старший значащий бит. Данные от датчика передаются в виде посылки, состоящих из 40 бит данных — это 5 байт из которых первых два влажность, следующие 2 температура и байт четности. Байт четности равен сумме предыдущих байт. 1 и 2 байт содержат соответственно целую и дробную часть информации о влажности, 3 и 4 байт содержат целую и дробную часть информации о температуре. Для датчика DHT11 2-й и 4-й байты всегда ноль. Значение этих байтов заключается в следующем:
Joog - как обычно...
К чему эти цитаты, вы сами головой думать умеете?
Вас спрашивают, что получится, если сложить влажность и температуру ? :)
Joog - как обычно...
К чему эти цитаты, вы сами головой думать умеете?
Вас спрашивают, что получится, если сложить влажность и температуру ? :)
Кому нужно разобраться, приведённого выше достаточно. Но вы из той породы кому надо на "пальцах" всё показывать и ещё и несколько раз.
unsigned char temp=0, hum=0;
int ca=0;
ca = read_dht_hum(); //читаем влажность и температуру c DHT11 из подпрограммы
hum = ((ca >>8) & 0xFF); // Разрезаем на байты старший байт влажность
temp = (ca & 0xFF); // Разрезаем на байты младший байт температура
Можете просто из подпрограммы забрать
char
data[5];
если работаете с DHT22 и вам надо цифры после запятойТам не сложение температуры с влажностью, там возвращается двухбайтовая величина, в старшем байте которой находится однобайтная влажность, а в младшем - однобайтная температура. Непонятно только, почему переменная описана как знаковая величина.
Непонятно только, почему переменная описана как знаковая величина.
чтобы полной грудью ощутить разницу битового сдвига между знаковым и беззнаковым инт
Да ладно бы они в старшую часть температуру пхали, она тоже знаковая, потом её только выкусить и использовать, так нет жеж, там беззнаковая влажность.
Я также пробовал использовать эту библиотеку, и обсуждаю сейчас проблему с её разработчиком. Ни одна библиотека, которая читает DHT22 функцией, не работает.
Starter381 загрузите мой скетч, и посмотрите ошибки от датчика где происходят? Обязательно проверьте резистор от вывода Data к +5в, должен быть 10 килоом. Чем он меньше тем больше ошибок чтения. Data DHT на 5 пин Arduino/
Зачем клеить, а затем резать влажность и температуру, если она никуда не выводится?
"goto
ReLoad"
вообще за гранью моего понимания.Думаю, это Северныйветер в другой реинкарнации
со знаковыми и беззнаковыми стало еще интереснее...
Из функции с возвращаемым значением unsigned int
возвращаем знаковый int temp, который в loop() преобразуем в переменную опять же с именем temp, но уже типа байт :)
Но с точки зрения синтаксиса ошибок нет ... :)))) Хотя несоответвие типа функции и возвращаемого значения должно, по идее, подсвечиваться предупреждением
Вот что получил:
Значит датчик отвечает, работает. Он у вас на улице? Влажность 1,3% и температура +0,25. Контрольная сумма совпадает.
Это чрезвычайно странные показания датчика. У меня датчик расположен в тёплой комнате; другой скетч сообщает температуру 24.3°C, влажность 24.6%!
Starter381 Нашел в этой статье, оказывается всё таки они разные DHT11 и DHT22 в плане расчета конечных показаний. Немного переделал, у меня только DHT11, попробуйте.
Starter381 Нашел в этой статье,
вместо того чтоб цитировать безграмотные статьи, может лучше в даташит заглянуть?
вот нахера эти гланды через жопу?
Температура и влажность выдаются в виде 16-битного целого, содержащего нужную величину, умноженную на 10. Старший бит температуры дополнительно несет знак.
И все!!
Пример
Влажность 00000010 10000100 = 644 = 64.4%
Я скажу так, Ваш код теперь работает, НО! Ваша логика в этом коде совершенно не понятна. Для начала, расскажите подробнее, зачем вам столько #define, которые ссылаются непонятно на что:
Во-вторых, что означают конкретно эти строки, и что это за ошибки, которые обрабатываются в этом месте:
Ваша логика в этом коде совершенно не понятна. Для начала, расскажите подробнее, зачем вам столько #define, которые ссылаются непонятно на что:
может стоит что-то почитать про микроконтроллеры, прежде чем задавать детские вопросы? А то беретесь работать с датчиком напрямую, без библиотек - а даже элементарные регистры МК ставят вас в тупик.
Напомните, что за цель у вас была изобретать велосипеды, чем не устроила готовая библиотека DHT.h ? Разобраться самому, как оно работает? - так разбирайтесь
Сейчас вы с Joog с грехом пополам повторили код стандартной библиотеки... если вы ничего не поняли, к чему была вся эта эпопея?
Я по специальности изначально фронтендист, так что не будь таким злым. Насчёт #define`ов вопрос снимаю.
Это же простые define, без наворотов.
А вот уже с такими у некоторых начинается непонимание:
Хотя всё тривиально. И использовалось ещё с тех пор, когда Ардуино ещё и в помине не было.)
Обнаружил проблему, что данный код возвращает неадекватные значения в диапазоне от -3200 до -3300 (чаще всего значения колеблются около -3275) при отрицательной температуре. При этом я проверил, что проблема лежит в коде, а не в самом датчике —с библиотекой DHT.h значения считаются нормально.