{"id":2186,"date":"2015-06-23T19:40:42","date_gmt":"2015-06-23T17:40:42","guid":{"rendered":"https:\/\/playembedded.org\/?p=2186"},"modified":"2021-07-29T10:58:46","modified_gmt":"2021-07-29T08:58:46","slug":"using-dht11-with-chibiosrt","status":"publish","type":"post","link":"https:\/\/playembedded.org\/blog\/using-dht11-with-chibiosrt\/","title":{"rendered":"Using DHT11 with ChibiOS\/RT"},"content":{"rendered":"<h3 id=\"1_A_cheap_sensor_for_humidity_and_temperature\" class=\"level_1\">A cheap sensor for humidity and temperature<\/h3>\n<p>The DHT11 is a basic, low-cost digital temperature and humidity sensor. It uses a capacitive humidity sensor and a thermistor to measure the surrounding air, and spits out a digital signal on the data pin (no analog input pins needed).<\/p>\n<p>The communication on data pin occurs according to a non-standard protocol known as One-Wire protocol.<\/p>\n<h3 id=\"2_Getting_started_with_DHT11\" class=\"level_1\">Getting started with DHT11<\/h3>\n<p>In this article we want to provide a demonstration for DHT11 compatible with ChibiOS\/HAL 3.0, but also explain concepts inside that demo. Following that purpose we need for the DHT11 datasheet.<\/p>\n<p><a href=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/Datasheet_DHT11.pdf\" rel=\"\">DHT11 Datasheet<\/a><\/p>\n<h3 id=\"3_Features_and_connections\" class=\"level_1\">Features and connections<\/h3>\n<figure id=\"attachment_2569\" aria-describedby=\"caption-attachment-2569\" style=\"width: 200px\" class=\"wp-caption alignright\"><a href=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_006_DHT11_mech.jpg\" rel=\"attachment wp-att-2569\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-2569\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_006_DHT11_mech.jpg\" alt=\"DHT11 mechanical draft\" width=\"200\" height=\"245\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_mech.jpg 200w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_mech-122x150.jpg 122w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_mech-20x24.jpg 20w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_mech-29x36.jpg 29w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_mech-39x48.jpg 39w\" sizes=\"auto, (max-width: 200px) 100vw, 200px\"><\/a><figcaption id=\"caption-attachment-2569\" class=\"wp-caption-text\">DHT11 mechanical draft.<\/figcaption><\/figure>\n<h4 id=\"4_Typical_connections\" class=\"level_2\">Typical connections<\/h4>\n<p>Typical circuit requires a pull-up resistor on data pin. In our case <b>Data out<\/b> is connected directly to Port A, pad 8 of a ST Nucleo F4 using a simple short wire, and it works perfectly. Anyway in a definitive circuit is suggested to connect a pull-up resistor of 4,7 k&Omega; as shown at page 4 of datasheet.<\/p>\n<h4 id=\"5_Pin_Description\" class=\"level_2\">Pin Description<\/h4>\n<ol>\n<li>the VDD power supply 3.5~5.5V DC<\/li>\n<li>DATA serial data, a single bus<\/li>\n<li>NC, empty pin<\/li>\n<li>GND ground, the negative power<\/li>\n<\/ol>\n<h4 id=\"6_Data_format\" class=\"level_2\">Data format<\/h4>\n<p>When the <b>DHT11<\/b> is queried , it replies using a 40bit length data packet. Data is organized as:<\/p>\n<ul>\n<li>8bit humidity integer data + 8bit humidity decimal data<\/li>\n<li>8bit temperature integer data + 8bit temperature decimal data<\/li>\n<li>8bit parity bit<\/li>\n<\/ul>\n<p>Humidity rate data is provided as percentage with resolution 1%. Temperature is provided as Celsius with resolution of 1&deg;C. That means on DHT11 data packet, decimal data is always zero. This is quite different for DHT22 that provides same data packet but with higher resolution and in this case decimal data is non-zero.<!--more--><\/p>\n<h4 id=\"7_Data_timing\" class=\"level_2\">Data timing<\/h4>\n<figure id=\"attachment_2570\" aria-describedby=\"caption-attachment-2570\" style=\"width: 1328px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing.jpg\" rel=\"attachment wp-att-2570\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-2570 size-full\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing.jpg\" alt=\"DHT11 timing diagram\" width=\"1328\" height=\"292\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing.jpg 1328w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing-150x33.jpg 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing-300x66.jpg 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing-1024x225.jpg 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing-1200x264.jpg 1200w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing-24x5.jpg 24w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing-36x8.jpg 36w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing-48x11.jpg 48w\" sizes=\"auto, (max-width: 1328px) 100vw, 1328px\"><\/a><figcaption id=\"caption-attachment-2570\" class=\"wp-caption-text\">A timing diagram for the DHT11 one wire protocol communication.<\/figcaption><\/figure>\n<p>According to data sheet DHT11 must be queried from host(our MCU) pulling down data pin for at least 18ms, than sensor lowers data pin for 80us as the response signal, followed by an high logical state output of 80 micro-seconds as notification of starting to send the data packet: so sensor replies with data. DHT11 actually sends out square waves and bit could be recognized measuring the time during which signal stays high: if that time is 26-28us it is a 0-bit, if it is 70 us is a 1-bit.<\/p>\n<figure id=\"attachment_2571\" aria-describedby=\"caption-attachment-2571\" style=\"width: 1400px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2.jpg\" rel=\"attachment wp-att-2571\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-2571 size-full\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2.jpg\" alt=\"DHT11 bits\" width=\"1400\" height=\"332\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2.jpg 1400w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2-150x36.jpg 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2-300x71.jpg 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2-1024x243.jpg 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2-1200x285.jpg 1200w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2-24x6.jpg 24w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2-36x9.jpg 36w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/art_006_DHT11_timing2-48x11.jpg 48w\" sizes=\"auto, (max-width: 1400px) 100vw, 1400px\"><\/a><figcaption id=\"caption-attachment-2571\" class=\"wp-caption-text\">Differences between &lsquo;0&rsquo; and &lsquo;1&rsquo; bit format.<\/figcaption><\/figure>\n<p>Summering getting data from DHT11 requires:<\/p>\n<ol>\n<li>Set a pin as output and pull down that output to start communication.<\/li>\n<li>Set the same pin as input to capture the square wave measuring high and low logical state period.<\/li>\n<li>Eventually control if communication succeeds using check sum.<\/li>\n<\/ol>\n<h3 id=\"8_Using_DHT11_with_ChibiOS_HAL_3_0\" class=\"level_1\">Using DHT11 with ChibiOS\/HAL 3.0<\/h3>\n<p>Rereading above, the question is: what we need for to use DHT11 with ChibiOS? Basically one-wire protocol requires a pin that could be used as output push-pull as well as capture input. HAL has a driver that can capture an input (typically a square wave) and measure time period as well as time during which signal is in logical high state or logical low state. This driver is Input Capture Unit (ICU) ad is associated to a TIM like PWM.<\/p>\n<p>Basically every pin could be used as digital output, but only some pin are connected to a TIM. We have to choose a pin internally connected to a timer channel. Reading Alternate Function table on data-sheet we could see that PA8 could be used as TIM1 Channel 1 thought AF 1 (If you are not familiar with PAL driver checkout the tutorial <a href=\"https:\/\/playembedded.org\/en\/2015\/02\/10\/hello-chibios\/\" target=\"_blank\" rel=\"noopener noreferrer\">Hello ChibiOS<\/a>). Reading ST Nucleo user manual we could learn that PA8 is connected to D7 pin of Arduino Connector.<br>\nLet outlining our program flow:<\/p>\n<ol>\n<li>Set PA8 mode as output push-pull and request data to DHT11 lowering <b>Data out<\/b> for at least 18ms.<\/li>\n<li>Set PA8 as AF1 and start ICU with a clock of at least 1MHz (This way we have a resolution of 1us).<\/li>\n<li>Start capturing data with ICU. Using ICU width callback acquire 41 widths.<\/li>\n<li>For each acquisition we need to write some variable according to widths.<\/li>\n<li>Eventually stop the ICU and restore PA8 mode to default configuration (input pull-up)<\/li>\n<\/ol>\n<p>Note that first acquisition that should be 80 ticks (80us since our resolution is 1us) and others should be 26-28 ticks for a 0-bit or 70 ticks for 1-bit.<\/p>\n<h3 id=\"9_Creating_this_application_from_scratch\" class=\"level_1\">Creating this application from scratch<\/h3>\n<p>First step as always is duplicate a working project (If you don&rsquo;t know how to do that checkout the tutorial <a href=\"https:\/\/playembedded.org\/en\/2014\/10\/19\/a-quick-view-of-chibistudio\/\" target=\"_blank\" rel=\"noopener noreferrer\">Quickview of Chibistudio<\/a> paying particular attention to video. Once we have created a new project, we have to enable ICU in <i>halconf.h<\/i>.<\/p>\n<pre>\/**\n * @brief   Enables the ICU subsystem.\n *\/\n#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)\n#define HAL_USE_ICU                 TRUE\n#endif<\/pre>\n<p>Since we want to use PA8 and so TIM1 CH1 we need to enable ICUD1 in <i>mcuconf.h<\/i><\/p>\n<pre>\/*\n * ICU driver system settings.\n *\/\n#define STM32_ICU_USE_TIM1                  TRUE<\/pre>\n<p>If we want to use chprintf() to print data on a serial we have to edit makefile adding memstreams.c and chprintf.c to CSRC and including related folder modifying INCDIR<\/p>\n<pre># C sources that can be compiled in ARM or THUMB mode depending on the global\n# setting.\nCSRC = $(STARTUPSRC) \\\n       $(KERNSRC) \\\n       $(PORTSRC) \\\n       $(OSALSRC) \\\n       $(HALSRC) \\\n       $(PLATFORMSRC) \\\n       $(BOARDSRC) \\\n       $(TESTSRC) \\\n       $(CHIBIOS)\/os\/hal\/lib\/streams\/memstreams.c \\\n       $(CHIBIOS)\/os\/hal\/lib\/streams\/chprintf.c \\\n       main.c\n...\nINCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \\\n         $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \\\n         $(CHIBIOS)\/os\/hal\/lib\/streams \\\n         $(CHIBIOS)\/os\/various<\/pre>\n<p>Now we are ready to write <i>main.c<\/i>. First of all we have to include chprintf.h declare a base sequential stream to use with chprintf(). Furthermore we could define some constants.<\/p>\n<pre>\/*\n * Enable if your terminal supports ANSI ESCAPE CODE\n *\/\n#define ANSI_ESCAPE_CODE_ALLOWED                  TRUE\nstatic BaseSequentialStream * chp = (BaseSequentialStream*) &amp;SD2;\n\/*===========================================================================*\/\n\/* DHT11 related defines                                                     *\/\n\/*===========================================================================*\/\n\/*\n * Width are in useconds\n *\/\n#define    MCU_REQUEST_WIDTH                     18000\n#define    DHT_ERROR_WIDTH                         200\n#define    DHT_START_BIT_WIDTH                      80\n#define    DHT_LOW_BIT_WIDTH                        28\n#define    DHT_HIGH_BIT_WIDTH                       70\n\/*===========================================================================*\/\n\/* ICU related code                                                          *\/\n\/*===========================================================================*\/\n#define    ICU_TIM_FREQ                        1000000<\/pre>\n<p>Now we can write an ICU configuration according to ChibiOS documentation. Since we need to measure time during high logical states we need to set ICU input as Active High. That means ICU width will measure time between signal rising edge and signal falling edge. Measure could have an uncertainly of &plusmn; 1 tick (In this case 1us). Other configuration are width, period and overflow callbacks, channels selected and value of DIE Register of TIM. We choose only width callback and enable channel 1.<\/p>\n<pre>static ICUConfig icucfg = {\n  ICU_INPUT_ACTIVE_HIGH,\n  ICU_TIM_FREQ,                                \/* 1MHz ICU clock frequency.   *\/\n  icuwidthcb,\n  NULL,\n  NULL,\n  ICU_CHANNEL_1,\n  0\n};<\/pre>\n<p>ICU width callback must be declared before ICU configuration. According to our configuration (ICU_INPUT_ACTIVE_HIGH), width callback is called on falling edge. Here we can get a width measure from driver ICU, and make some elaboration. Lets take a look to the code.<\/p>\n<pre>static uint8_t TEMP, HR, CHECK_SUM, tmp, bit_counter = 0;;\nstatic icucnt_t widths [40];\nstatic void icuwidthcb(ICUDriver *icup) {\n  icucnt_t width = icuGetWidthX(icup);\n  if(width &gt;= DHT_START_BIT_WIDTH){\n    \/* starting bit resetting the bit counter *\/\n    bit_counter = 0;\n  }\n  else{\n    \/* Recording current width. Just for fun  *\/\n    widths[bit_counter] = width;\n    if(width &gt; DHT_LOW_BIT_WIDTH){\n      tmp |= (1 &lt;&lt; (7 - (bit_counter % 8)));\n    }\n    else{\n      tmp &amp;= ~(1 &lt;&lt; (7 - (bit_counter % 8)));\n    }\n    \/* When bit_counter is 7, tmp contains the bit from 0 to 7 corresponding to\n       The Humidity Rate integer part (Decimal part is 0 on DHT 11) *\/\n    if(bit_counter == 7)\n      HR = tmp;\n    \/* When bit_counter is 23, tmp contains the bit from 16 to 23 corresponding to\n       The Temperature integer part (Decimal part is 0 on DHT 11) *\/\n    if(bit_counter == 23)\n      TEMP = tmp;\n    \/* When bit_counter is 39, tmp contains the bit from 32 to 39 corresponding to\n       The Check sum value *\/\n    if(bit_counter == 39)\n      CHECK_SUM = tmp;\n    bit_counter++;\n  }\n}<\/pre>\n<p>This code gets the latest width, checking if it is related to a start bit (80us) or to one of the forty bits sent from DHT11. If current bit is the start one the counter <i>bit_counter<\/i> is reset. During the forty callback occurencies related to data bits, width is stored into a buffer (just for debug purposes).<\/p>\n<p><i>bit_counter<\/i> counts data related callback occurencies and data is &ldquo;built&rdquo; bit by bit and stored into the static variables (<i>HR<\/i>, <i>TEMP<\/i>, <i>CHECK_SUM<\/i>). To do this bit masks are used (Take a look at <a href=\"https:\/\/playembedded.org\/en\/2015\/05\/30\/registers-and-bit-masks\/\" target=\"_blank\" rel=\"noopener noreferrer\">Registers and bit-masks<\/a>). The <i>tmp<\/i> variable is used as temporary variable to build 8-bit lenght words during the sequence of callbacks. So when <i>bit_counter<\/i> reaches the value 7, <i>tmp<\/i> contains the integer part of the humidity rate, on 15 the decimal part of the humidity rate, on 23 the integer part of the temperature and so on&hellip;<\/p>\n<p>Main initialize serial driver (We will use it with chprintf), set pin properly to make request, reset pin for ICU launching this driver, waits time needed by communication and prints out data.<\/p>\n<h3 id=\"10_How_to_port_this_application_on_other_MCUs\" class=\"level_1\">How to port this application on other MCUs<\/h3>\n<p>Most likely we have just to change ICU configuration and pin used by data. Note that every driver configuration in ChibiOS has a part common to every MCU. For ICU the timer frequency, capture mode, and callback are independent from platform. We should expect to modify last part of configuration like DIER. A good idea to understand how is structured configuration, is copying it from a platform demo in chibios3\/testhal (same MCU same configuration, so, as example F401RE and F407 have same configurations).<\/p>\n<pre class=\"lang:c decode:true\">\/*\n    PLAY Embedded demos - Copyright (C) 2014-2016 Rocco Marco Guglielmi\n\n    This file is part of PLAY Embedded demos.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n*\/\n\n\/*\n    Tested under ChibiOS 16.1.4, Project version 1.1\n\n    * 1.1 Change-log\n    * - Fixed bug on Checksum as suggested by Dave Edwards.\n *\/\n#include \"ch.h\"\n#include \"hal.h\"\n\n#include \"chprintf.h\"\n\n\/*\n * Enable if your terminal supports ANSI ESCAPE CODE\n *\/\n#define ANSI_ESCAPE_CODE_ALLOWED                  TRUE\n\nstatic BaseSequentialStream * chp = (BaseSequentialStream*) &amp;SD2;\n\/*===========================================================================*\/\n\/* DHT11 related defines                                                     *\/\n\/*===========================================================================*\/\n\/*\n * Width are in useconds\n *\/\n#define    MCU_REQUEST_WIDTH                     18000\n#define    DHT_ERROR_WIDTH                         200\n#define    DHT_START_BIT_WIDTH                      80\n#define    DHT_LOW_BIT_WIDTH                        28\n#define    DHT_HIGH_BIT_WIDTH                       70\n\/*===========================================================================*\/\n\/* ICU related code                                                          *\/\n\/*===========================================================================*\/\n\n#define    ICU_TIM_FREQ                        1000000\n\nstatic uint8_t TEMP, HR, CHECK_SUM, tmp, bit_counter = 0;;\nstatic icucnt_t widths [40];\n\nstatic void icuwidthcb(ICUDriver *icup) {\n\n  icucnt_t width = icuGetWidthX(icup);\n\n  if(width &gt;= DHT_START_BIT_WIDTH){\n    \/* starting bit resetting the bit counter *\/\n    bit_counter = 0;\n  }\n  else{\n    \/* Recording current width. Just for fun  *\/\n    widths[bit_counter] = width;\n\n    if(width &gt; DHT_LOW_BIT_WIDTH){\n      tmp |= (1 &lt;&lt; (7 - (bit_counter % 8)));\n    }\n    else{\n      tmp &amp;= ~(1 &lt;&lt; (7 - (bit_counter % 8)));\n    }\n\n    \/* When bit_counter is 7, tmp contains the bit from 0 to 7 corresponding to\n       The Humidity Rate integer part (Decimal part is 0 on DHT 11) *\/\n    if(bit_counter == 7)\n      HR = tmp;\n    \/* When bit_counter is 23, tmp contains the bit from 16 to 23 corresponding to\n       The Temperature integer part (Decimal part is 0 on DHT 11) *\/\n    if(bit_counter == 23)\n      TEMP = tmp;\n    \/* When bit_counter is 39, tmp contains the bit from 32 to 39 corresponding to\n       The Check sum value *\/\n    if(bit_counter == 39)\n      CHECK_SUM = tmp;\n    bit_counter++;\n  }\n}\n\n\nstatic ICUConfig icucfg = {\n  ICU_INPUT_ACTIVE_HIGH,\n  ICU_TIM_FREQ,                                \/* 1MHz ICU clock frequency.   *\/\n  icuwidthcb,\n  NULL,\n  NULL,\n  ICU_CHANNEL_1,\n  0\n};\n\n\/*===========================================================================*\/\n\/* Generic function                                                          *\/\n\/*===========================================================================*\/\n\n\/*\n * Red LED blinker thread, times are in milliseconds.\n *\/\nstatic THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"blinker\");\n  while (true) {\n    palClearPad(GPIOA, GPIOA_LED_GREEN);\n    chThdSleepMilliseconds(500);\n    palSetPad(GPIOA, GPIOA_LED_GREEN);\n    chThdSleepMilliseconds(500);\n  }\n}\n\n\/*\n * Application entry point.\n *\/\nint main(void) {\n\n  \/*\n   * System initializations.\n   * - HAL initialization, this also initializes the configured device drivers\n   *   and performs the board-specific initializations.\n   * - Kernel initialization, the main() function becomes a thread and the\n   *   RTOS is active.\n   *\/\n  halInit();\n  chSysInit();\n\n  \/*\n   * Activates the serial driver 2 using the driver default configuration.\n   *\/\n  sdStart(&amp;SD2, NULL);\n\n  \/*\n   * Creates the blinker thread.\n   *\/\n  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);\n\n  chThdSleepMilliseconds(1000);\n\n  \/*\n   * Normal main() thread activity, in this demo it does nothing except\n   * sleeping in a loop and check the button state.\n   *\/\n  while (true) {\n    \/*\n     * Making a request\n     *\/\n    palSetPadMode(GPIOA, GPIOA_PIN8, PAL_MODE_OUTPUT_PUSHPULL);\n    palWritePad(GPIOA, GPIOA_PIN8, PAL_LOW);\n    chThdSleepMicroseconds(MCU_REQUEST_WIDTH);\n    palWritePad(GPIOA, GPIOA_PIN8, PAL_HIGH);\n\n    \/*\n     * Initializes the ICU driver 1.\n     * GPIOA8 is the ICU input.\n     *\/\n    palSetPadMode(GPIOA, GPIOA_PIN8, PAL_MODE_ALTERNATE(1));\n    icuStart(&amp;ICUD1, &amp;icucfg);\n    icuStartCapture(&amp;ICUD1);\n    icuEnableNotifications(&amp;ICUD1);\n    chThdSleepMilliseconds(700);\n#if ANSI_ESCAPE_CODE_ALLOWED\n    chprintf(chp, \"\\033[2J\\033[1;1H\");\n#endif\n    icuStopCapture(&amp;ICUD1);\n    icuStop(&amp;ICUD1);\n\n    chprintf(chp, \"Temperature: %d C, Humidity Rate: %d %% \\n\\r\", TEMP, HR);\n    if(CHECK_SUM == (TEMP + HR)){\n      chprintf(chp, \"Checksum OK!\\n\\r\");\n    }\n    else{\n      chprintf(chp, \"Checksum FAILED!\\n\\r\");\n    }\n  }\n}\n<\/pre>\n<h3 id=\"11_Project_download\" class=\"level_1\">Project download<\/h3>\n<p>The attached demo has been tested under ChibiOS 21.6.x.<\/p>\n<p><a href=\"https:\/\/playembedded.org\/wp-content\/uploads\/2021\/07\/RT-STM32F401RE-NUCLEO64-DHT11-216.7z\" rel=\"\">RT-STM32F401RE-NUCLEO-DHT11-216<\/a><\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>A cheap sensor for humidity and temperature The DHT11 is a basic, low-cost digital temperature and humidity sensor. It uses a capacitive humidity sensor and a thermistor to measure the surrounding air, and spits out a digital signal on the data pin (no analog input pins needed). The communication on data pin occurs according to [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":2404,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1225],"tags":[],"coauthors":[241],"class_list":["post-2186","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-interfacing-externals","red"],"views":12192,"jetpack_featured_media_url":"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2016\/04\/Using-DHT11-with-ChibiOSRT.jpg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts\/2186","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/comments?post=2186"}],"version-history":[{"count":0,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts\/2186\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/media\/2404"}],"wp:attachment":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/media?parent=2186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/categories?post=2186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/tags?post=2186"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/coauthors?post=2186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}