{"id":316,"date":"2013-08-25T13:07:02","date_gmt":"2013-08-25T13:07:02","guid":{"rendered":"http:\/\/ermine-electronics.co.uk\/?p=272"},"modified":"2014-10-04T08:46:24","modified_gmt":"2014-10-04T08:46:24","slug":"am2302-dht22-temp-humidity-sensor-and-jal-on-a-16f628-at-4mhz-clock","status":"publish","type":"post","link":"https:\/\/www.richardmudhar.com\/blog\/2013\/08\/am2302-dht22-temp-humidity-sensor-and-jal-on-a-16f628-at-4mhz-clock\/","title":{"rendered":"AM2302 (DHT22 ) Temp Humidity sensor and JAL on a 16F628 at 4MHz clock"},"content":{"rendered":"<p>Having decided I<a title=\"Humidity and Temperature sensor on Cosm IoT\" href=\"http:\/\/www.richardmudhar.com\/blog\/2013\/05\/humidity-and-temperature-sensor-on-cosm-iot\/\"> can&#8217;t be bothered with digital sensors with oddball serial interfaces like the DHT22<\/a> it was time to suck it up when I needed a number of sensors. Cost adds up with lots of sensors &#8211; though that Honeywell product more than paid for itself a few times over in much better hatch rates (fertile eggs are about \u00a32 a pop by post, that&#8217;s how much of a loss you eat for every failure to hatch!) not every sensor application affects the bottom line like that. Sometimes low cost trumps accuracy, reliability and serviceability. Enter the AM2302, apparently a.k.a. DHT22, produced by the fine <a href=\"http:\/\/www.aosong.com\" target=\"_blank\">Aosong corporation<\/a>. Their website looks like line noise on my browser, but apparently they are based in <a href=\"http:\/\/en.wikipedia.org\/wiki\/Guangzhou\">Guangzhou<\/a>, which is China&#8217;s third largest city, a conurbation of nearly thirteen million souls.<\/p>\n<figure id=\"attachment_288\" aria-describedby=\"caption-attachment-288\" style=\"width: 238px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.richardmudhar.com\/blog\/wp-content\/uploads\/2013\/08\/1308_am2302_P1050532.jpg\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"wp-image-288 size-medium\" src=\"https:\/\/i0.wp.com\/www.richardmudhar.com\/blog\/wp-content\/uploads\/2013\/08\/1308_am2302_P1050532-238x300.jpg?resize=238%2C300\" alt=\"AM2302, humidity and temperature sensor, a.k.a. DHT22 apparently\" width=\"238\" height=\"300\" srcset=\"https:\/\/i0.wp.com\/www.richardmudhar.com\/blog\/wp-content\/uploads\/2013\/08\/1308_am2302_P1050532.jpg?resize=238%2C300&amp;ssl=1 238w, https:\/\/i0.wp.com\/www.richardmudhar.com\/blog\/wp-content\/uploads\/2013\/08\/1308_am2302_P1050532.jpg?resize=815%2C1024&amp;ssl=1 815w, https:\/\/i0.wp.com\/www.richardmudhar.com\/blog\/wp-content\/uploads\/2013\/08\/1308_am2302_P1050532.jpg?resize=624%2C783&amp;ssl=1 624w, https:\/\/i0.wp.com\/www.richardmudhar.com\/blog\/wp-content\/uploads\/2013\/08\/1308_am2302_P1050532.jpg?w=1024&amp;ssl=1 1024w\" sizes=\"auto, (max-width: 238px) 85vw, 238px\" \/><\/a><figcaption id=\"caption-attachment-288\" class=\"wp-caption-text\">AM2302, humidity and temperature sensor, a.k.a. DHT22 apparently<\/figcaption><\/figure>\n<p>The sensors are cheap, nasty and have poor accuracy, but the price is right, it&#8217;s the cheapest way to get a humidity and temperature sensor. Five for \u00a317.70 or a unit price of \u00a33.54 from a Chinese supplier on ebay, Buyincoins ISTR. They have a non-standard one-wire interface. That requires you to be able to tell a 30\u03bcS high duration from a 68\u03bcS high duration. No problem, eh, even with a PIC running on the internal 4MHz oscillator so each clock cycle is 1\u03bcS?<\/p>\n<p>There was already a JAL library for this, called <a href=\"http:\/\/jallib.googlecode.com\/svn\/trunk\/include\/external\/temperature\/temperature_humidity_dht11.jal\">temperature_humidity_dht11.jal<\/a> so I am in development heaven.<\/p>\n<p><iframe loading=\"lazy\" src=\"http:\/\/www.youtube.com\/embed\/5FaMmh2AU0U?feature=player_detailpage&amp;rel=0\" width=\"550\" height=\"320\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>Except it doesn&#8217;t work &#8211; it acts up after about 20s in the video. It sort of works some times, tantalising short runs of OK in amongst loads of timeout errors. I fiddle with the power supply a little as the AM2302 is claimed to be finicky on the need for 5V. No luck. Tracing the library code I find it barfs around<\/p>\n<p><!--more--><\/p>\n<pre lang=\"JAL\">      -- as soon as we detect it's going high, we need to measure duration:\r\n      --   * 26-28us means 0\r\n      --   * 70us means 1\r\n      -- If we wait 40us and check pin level, we should be able to know\r\n      -- if it was a '1' (pin is still high) or a '0' (pin is low)\r\n      -- (ok, we're assuming there won't be any timeouts here...)\r\n      delay_10us(4)\r\n      if pin_dht11 == high then\r\n         -- '1'\r\n         _dht11_buffer[buf_idx] = _dht11_buffer[buf_idx] | (1 &lt;&lt; bit_idx)\r\n      else\r\n         -- '0'\r\n      end if<\/pre>\n<p>Which looks fair enough, until you take a look at what that actually means in assembler, in particular the routine just before it that loops on the low until the pin goes high<\/p>\n<pre lang=\"pic16\"> \r\n;  104       while pin_dht11 == low loop\r\nl__l471\r\n                               btfsc    v_portb, 7 ; pin_b7\r\n                               goto     l__l472\r\n;  105          counter = counter + 1\r\n                               incf     v___counter_1,f\r\n                               btfsc    v_status, v__z\r\n                               incf     v___counter_1+1,f\r\n;  106          if counter == DHT11_TIMEOUT_TRY then\r\n                               movlw    232\r\n                               subwf    v___counter_1,w\r\n                               movwf    v__pic_temp\r\n                               movlw    3\r\n                               subwf    v___counter_1+1,w\r\n                               iorwf    v__pic_temp,w\r\n                               btfss    v_status, v__z\r\n                               goto     l__l471\r\n;  107             return  DHT11_TIMEOUT\r\n                               retlw    2\r\n;  109       end loop\r\nl__l472\r\n;  117       delay_10us(4)<\/pre>\n<p>&nbsp;<\/p>\n<p>There&#8217;s a lot of guff in there, you could easily pick up a random delay of up to 15\u03bcS if you just miss the test in the loop and have to do all that testing for timeout. Putting extra diagnostics in there shows it tends to catch only about 37 or 38 or the 40 bits, waiting and timing out for the missed bits at the end which never come. What seems to be happening is the uncertainty of when the rising edge is detected is eating into the detection of the corresponding falling edge, as a result it skips a bit or two.<\/p>\n<p>Changing<\/p>\n<p>delay_10us(4)for<\/p>\n<p>delay_10us(2)<br \/>\ndelay_5us()<\/p>\n<p>turned this from a seriously ratty and unusable sensor to something much more reliable. The original example for the jal DHT11 library ran at a much higher clock speed than 4MHz, so the problem here is due to me being a cheapskate and using a low clock frequency. However, if you are going to use one of these sensors then you&#8217;re a cheapskate by definition&#8230;<\/p>\n<p>A look at the waveform on the scope seemed to indicate the periods were about right, however I only have an analogue scope and catching something that only happens every five seconds using the delay timebase is no fun. I had suspected that buyincoins might have supplied some rejects perhaps with an out of spec timing, but that&#8217;s probably unfounded \ud83d\ude09<\/p>\n<p>There&#8217;s a case to try and tighten this loop up. Using assembler for that loop is one way to reduce the variation. An easier way is to\u00a0use a byte not a word in the timeout loop counter, since it only needs to dwell on Tlow from the datasheet, a maximum of 55\u03bcS, so a byte counter capable to counting up to 255 is more than enough. That would drop out the variation in needing to handle the overflow register, which would shorten this a lot and simplify the code. So I created a 4MHz version of this code, and the corresponding bit of assembler is<\/p>\n<pre lang=\"pic16\"> \r\n;  103       while pin_dht11 == low loop\r\nl__l471\r\n                               btfsc    v_portb, 7 ; pin_b7\r\n                               goto     l__l472\r\n;  104          counter = counter + 1\r\n                               incf     v___counter_1,f\r\n;  105          if counter == DHT11_TIMEOUT_TRY then\r\n                               movlw    200\r\n                               subwf    v___counter_1,w\r\n                               btfss    v_status, v__z\r\n                               goto     l__l471\r\n;  106             return  DHT11_TIMEOUT\r\n                               retlw    2\r\n;  108       end loop\r\nl__l472\r\n;  116       delay_10us(3)<\/pre>\n<p>which has a delay of 8\u03bcS if you&#8217;re unlucky enough to just miss the\u00a0 test<\/p>\n<p>btfsc v_portb, 7<\/p>\n<p>and a delay of 3\u03bcS if you catch it just right, reducing the sampling jitter to 5\u03bcS as opposed to about 12. Inserting the delay of 30\u03bcS plus the worst case 3\u03bcS gives 33\u03bcS, and another 2\u03bcS happen after the delay to make a shortest delay of 35\u03bcS and longest delay (if you&#8217;ve just missed the test in the loop) of 47\u03bcS. That&#8217;s good enough to detect something other than the worst-case max 30\u03bcS high (Th0) of a 0 bit from anything longer which is a 1.<\/p>\n<p><iframe loading=\"lazy\" src=\"http:\/\/www.youtube.com\/embed\/umyuvD6nhaw?feature=player_detailpage&amp;rel=0\" width=\"550\" height=\"320\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>&nbsp;<\/p>\n<p>My replacement JAL library <a href=\"http:\/\/www.richardmudhar.com\/blog\/wp-content\/uploads\/2013\/08\/temperature_humidity_am2302_4M.txt\">temperature_humidity_am2302_4M<\/a><\/p>\n<p>this is a text file, rename to jal and stick it in your JAL library and include it in your code<\/p>\n<p>Use like this<\/p>\n<pre>const bit USE_DHT22 = true\r\n; const byte DHT11_TIMEOUT_TRY = 202\r\ninclude temperature_humidity_am2302_4M\r\n;include temperature_humidity_dht11<\/pre>\n<p>If you have declared DHT11_TIMEOUT_TRY as a word you need to stop doing that or declare it as a byte<\/p>\n<p>This gave me a win on this device with the 16F628. I&#8217;m still not tremendously impressed with the accuracy, swapping the devices makes it a little bit hard for me to believe the accuracy claim of \u00b11\u00b0C, though they aren&#8217;t terrible, \u00b12\u00b0C would be better. I still wonder if the low cost means these are factory rejects a little out of spec. But at least it works form a data transfer point of view.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Having decided I can&#8217;t be bothered with digital sensors with oddball serial interfaces like the DHT22 it was time to suck it up when I needed a number of sensors. Cost adds up with lots of sensors &#8211; though that Honeywell product more than paid for itself a few times over in much better hatch &hellip; <a href=\"https:\/\/www.richardmudhar.com\/blog\/2013\/08\/am2302-dht22-temp-humidity-sensor-and-jal-on-a-16f628-at-4mhz-clock\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;AM2302 (DHT22 ) Temp Humidity sensor and JAL on a 16F628 at 4MHz clock&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[57,13],"tags":[17,26,33,35,265,7,50],"class_list":["post-316","post","type-post","status-publish","format-standard","hentry","category-electronics","category-sensors","tag-am2302","tag-dht22","tag-humidity","tag-jal","tag-microcontroller","tag-pic-micro","tag-temperature"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p5aOO7-56","jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/posts\/316","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/comments?post=316"}],"version-history":[{"count":2,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/posts\/316\/revisions"}],"predecessor-version":[{"id":1433,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/posts\/316\/revisions\/1433"}],"wp:attachment":[{"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/media?parent=316"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/categories?post=316"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/tags?post=316"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}