»Начало 
Raspberry Pi и DHT22


Raspberry Pi и DHT22


DHT22 е комбиниран сензор за температура и влажност. На доста места в Интернет можете да намерите схема на свързване на DHT22 към Pi (например тук и тук). Самият сензор пък можете да закупите от Robotev, където се подвизава под името RHT-03, но е същия сензор.

Свързването не е проблем, но самото сваляне на резултатите от сензора се оказа малко приключение.

Ако сте решили да разберете как точно работи сензора ви препоръчвам документацията тук.

В общи линии комуникацията със сензора започва когато свалите пина на Pi-то за повече от 1 ms, като се препоръчва да го направите за 18ms. След това трябва да вдигнете пина за време между 20 и 40 us.

В резултат на това сензора трябва да ви отговори с ниско ниво за 80 us последвано от високо ниво за още 80 us.

След това ще сензора започва да изпраща 5 байта, като последния е чексума на предишните 4. Нулата представлява ниско ниво за 50 us, следвано от високо ниво за 26-28 us. Единицата пък е ниско ниво за 50 us следвано от високо ниво за 70 us.

Въпреки, че на няколко места в Интернет можете да намерите код на C и на Python за отчитането на резултатите, то моя първи сблъсък се оказа почти катастрофален.

Руската версия на кода разчита на броенето на импулси и по този начин се определя дали е настъпила промяна в нивата, а от там и дали сензора изпраща нула или единица за съответния бит. Кода на Adafruit на C и на Python работи на същия принцип.

При мен първите опити с руския код връщаха или нули или нищо. Кода на Adafruit на Python зависваше в някакъв цикъл очакващ някакво ниво, което очевидно не се случваше. След коментирането на цикъла, отново не получавах никакъв свестен резултат.

Първоначално помислих, че съм объркал свързването, но всичко беше наред. Просто не получавах информацията от сензора. Смених pull up резистора от 4.7k на 10k, но отново без успех. На някои места се споменаваше, че хората получавали по-стабилни резултати ако захранвали сензора на 5V вместо 3.3V, но при мен и това не даде резултат.

Вече бях започнал да се чудя дали не съм повредил сензора или пък да е дефектен, когато след може би десетократна проба с кода имах някакъв резултат! Верен или не нямаше значение, но пък беше напредък. Вече можех да зарежа поялника и да започна да си играя с кода.

Оказа се, че веднъж на седем осем опита все пак се получаваше някакъв резултат. Премахването на проверката на чек сумата до голяма степен осигури повече резултати, но пък бяха и доста грешни :)

Какъв обаче можеше да бъде проблема? В кода можете да видите, че се прави проверка на броя на получените битове, като резултатите се игнорират ако се получат по-малко от 40 бита. Всичко хубаво до тук, но защо не ги получавах всичките, както си личеше от DEBUG съобщенията?

В този момент се сетих, че бях пуснал motion с една USB камера на Pi-то. Тя "яде" само няколко процента CPU, но реших да я спра. И хоп! И руския код и кода на Adafruit на C и на Python тръгнаха! Очевидно Pi-то не беше достатъчно бързо за да отчита въпросните us. Толкова малко натоварване обаче не беше нормално да катурне колата. Дори заигравката с nice на процесите не подобри отчитането.

Поиграх си малко с кода опитвайки се да го оптимизирам за да спестя някоя и друга операция и стигнах до момент, в който успявах да отчитам правилно сензора от 3-4 опита с пуснат motion. Това обаче ме дразнеше и логичния подход беше кърнел драйвер или пък външен микроконтролер, към който да е свързан сензора. Туй като на мен микроконторлерите не са ми кой знае каква страст, то логично беше да се пробвам малко с писането на драйвер.

За моя радост обаче такъв вече беше написан: http://www.tortosaforum.com/raspberrypi/dht11driver.htm

Незнайно защо обаче при мен компилацията на драйвера уж протичаше нормално, insmod се изпълняше нормално, но rmmod паникоьосваше Pi-то. Подозирам, че проблема се дължеше на мързела ми да компилирам кърнел и се пробвах да компилирам драйвера само с хватката с Module.symvers. Може и NFS-то на root-а да е замесен, но в крайна сметка след десетина опита модула или чупеше Pi-то при insmod или при rmmod или пък се държеше странно, като например инциализирана с нула променлива се показваше като -2193091234 или каквото там ви хрумне. Та, затова съвет: крос компилирайте на друга машина. Аз вече имах такава машина за компилиране на x86 върху x86_64, та не ми костваше само:

crossdev -S -v -t armv6j-hardfloat-linux-gnueabi

На който му се чете повече: http://wiki.gentoo.org/wiki/Raspberry_Pi_Cross_building

Ето и инструкция как да компилирате самия модул: http://bchavez.bitarmory.com/archive/2013/01/16/compiling-kernel-modules-for-raspberry-pi.aspx

След това е лесно:

Правите някъде една папка в която слагате Makefile и dht11km.c, нагласяте пътищата в Makefile и сте готови за make.

obj-m = dht11km.o

all:
        make ARCH=arm CROSS_COMPILE=${CCPREFIX} -C /mnt/storage/pi/linux-3.10.24 M=$(PWD) modules

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
        make -C /mnt/storage/pi/linux-3.10.24 M=$(PWD) clean

Имайте предвид, че Makefile не обича интервалите, така че разстоянието пред make са два TAB-а. Удебелените надписи трябва да ги промените според вашите пътища.

make!

Ще получите dht11km.ko, който копирате на Pi-то, insmod-вате го с параметрите, които искате и сте вие.

Параметрите са:

gpio_pin=4 - това е GPIO пин-а, а не пин-а на конектора!
driverno=80 - major - за да получите информацията от сензора трябва да създаде нов char device с нещо като: mknod /dev/dht11 c 80 0
format=3 - изходния формат

НО ... има едно голямо НО. След като пуснах motion, драйвера отказа да връща информация.

Ако сте любопитни като мен, вероятно вече сте разгледали C файла и сте забелязали, че тук подхода за разлика от руското решение и това на Adafruit е правилен т.е. не се броят импулси за време, а се разчита на прекъсвания, които се генерират от промяна на нивата на пин-a. Супер ще си кажете, както и аз си казах още преди да започна да го мъча и дори бях тръгнал да преправям userspace програмите по този начин, не се отказах.

Защо обаче всичко се сгромоляса ... малко вероятно е това да се дължеше на използването на CPU-то, както си мислех първоначално и след като драйвера използва прекъсвания тук трябваше да бъде и заровено кучето.

vmstat 1

... и се хващате за главата. Една глупава USB web камера прави 8000! прекъсвания в секунда. Мамка му един средно натоварен сървър прави сигурно четири пъти по-малко, а какво остава за едно Pi.

След като вече знаех причината следваше да се намери и работещо решение. До тук изключих използването на userspace програма, защото просто нямаше как да получи real time приоритет. Драйвера с използването на прекъсвания също отпадаше след като си имах и без това толкова много. Но защо пък да не вземем най-доброто от двата варианта?

Не е много трудно обаче да спрете прекъсванията да не ви се бъркат и да броите микросекунди. Този подход не е изобщо добро решение, ако ще правите много работи върху една машина, но за моите цели върши работа.

Затова направих един цикъл и на всяка микросекунда отчитам нивото на пин-а. Така при промяната му според изминалото време от последната промяна на нивото се отчита времето, което е изминало за съответното ниво. По този начин попълваме бит по бит резултата.

Ако на някой му се играе може да оптимизира алгоритъма, защото не е оптимално решение, но това за някой друг път. Евентуално ...

И така ето кода на модифицирания драйвер: http://jeckyll.net/images/JeckyllNet/download/dht22/dht22_kernel_driver.tgz

Оригиналния драйвер е писан за DHT11, който по същество говори абсолютно същия протокол, но информацията се получава само в два байта, а не в четири, както при DHT22 (или поне аз не виждам друга разлика в кода, който съм прегледал до сега, но нямам DHT11 и не съм го тествал).

Затова съм добавил параметър type, който може да бъде 11 за DHT11, 22 за DHT22 и 2302.

Добавен и четвърти изходен формат, който изглежда така:

OK 22800 48100

Три колони разделени с интервал, като в първата се връща кода OK при успешна операция и BAD, ако информацията не е коректна. Температурата умножена по 1000 е в колонка две, а в третата е относителната влажност умножена по 1000. Защо по 1000? Резултатите винаги са цели числа и без много мъка могат да бъдат ползвани за нещо, като това:





За сравнение това е графиката от DS18B20:



Има разлика до две десети между отчитането на температурата от DHT22, което е до десета и DS18B20, която е до хилядна или поне такива резултати връщат.

Можете да върнете оригиналния алгоритъм на драйвера, ако модифицирате #define USE_INTR на 1.

При мен драйвера не е връщал грешка и не е правил нов опит за прочитане на информацията от сензора (които между другото са ограничени на пет) вече втори ден, като се отчита всяка минута. Между отчитанията трябва да оставяте поне по две секунди или поне така пише в документацията.

Не ползвайте драйвера ако имате други критични към времето приложения, защото честото му отчитане може да окаже негативно влияние. Все пак спираме прекъсванията макар и за кратко. Или пък го отчитайте на интервал от минута или повече. Поне аз не съм забелязал някакви странични ефекти, но знае ли човек :) Предупредени сте ... и умната!

А да ... разбира се снимката на джаджата:





Коментари

Все още няма коментари


напиши нов коментар
Какво е това?

Това трябва да бъде нещо като микро блог или просто начин да записвам разни кратки мисли, идеи, линкове и т.н.

Към всеки пост може да има "закачени" следните елементи:

  Линк към страница
  Прикачена картинка
  Прикачен видео файл
Показва времето на публикуването, заедно с линк към страницата с поста и коментарите
2.4HGz OFF / 5GHz Only ON
bye bye Debian ... apt-get dist-upgrade може да деинсталира ядро :) E ... крайно време беше да го разкарам това недоразумение :)
drWEB Live CD е Gentoo базирано - well done!
Като едно време ... 3.11

Linux notebook 3.11.0-gentoo-dr #1 SMP PREEMPT Tue Sep 3 22:17:44 EEST 2013 i686 Intel(R) Core(TM)2 CPU T7200 @ 2.00GHz GenuineIntel
вчера 3.6.4, днеска 3.6.5 ... така е то ...
не искам глупави thumbail-и от firefox ПЪК! browser.pagethumbnails.capturing_disabled = true
... напоследък дори журналистите имат проблем с разбиране на написаното ...
Мързи ме да напиша около 20 реда код вече ... 10 дни ...
noteX31 ~ # uptime
23:12:42 up 1016 days, 14:39, 2 users, load average: 1.45, 0.64, 0.24
4:30 поздрава за всички, които отърваха Ugly Kid Joe :P
нЕкви хора си правят нЕкъв PR ... и разказват, че станали жертви ...
noteX31 ~ # uptime
10:36:05 up 939 days, 2:03, 4 users, load average: 0.11, 0.66, 0.52
... като не си гледаш разните странни E-Mail-и като например hostmaster@... ти изтича SSL сертификата ...
stretch
stretch
stretch
stretch
interoffice
interoffice
interoffice
interoffice