Nordic nRF52840 で温度湿度センサ DHT11 を使う

# 環境

- 開発ボード アオノドン2019(Raytac MDBT50Q / Nordic nRF52840 搭載)
- IDE Segger Enbedid Studio
- 開発PC Ubuntu 18.04LTS
- nRF5_SDK_16.0.0_98a08e2


# 接続

アオノドン2019は、ウラ面に Grove 端子がある。これを使って DHT11 を接続した。
Grove 端子の白が DHT11 のデータ線となる。
アオノドン2019では白ケーブルが GPIO7 に割り当てられている。
アオノドンや Grove 端子を使わなくても GPIO7 にデータ線を接続すれば同じプログラムでデータが取得できる。


# DHT11 データ転送手順


訳のわからないデータシートを読んでわかったこと。

1ワイヤの独自プロトコル。DHT11へ送る論理コマンドは無し。ホストからのデータ線の引き下げ→引き上げをトリガとしてセンサからデータが発信される。

センサからのデータは 40bit。

## データ形式

- 8bit:湿度整数データ
- 8bit:湿度小数点以下第一位データ(常に0)
- 8bit:温度整数データ
- 8bit:温度整数データ
- 8bit:bit0〜7 温度小数点以下第一位データ(0〜9)  bit8で零下温度を表す
- 8bit:チェックビット。

### チェックビットデータの定義

8bit湿度整数データ＋8bit湿度小数点以下第一位データ＋8bit温度整数データ＋8bit(零下フラグおよび温度度小数点以下第一位データ) 

## 転送開始シーケンス

- Startシグナル ホストより SDAラインの引き下げ 18ms 〜 30ms → SDAラインの引き上げ
- レスポンスシグナル センサよりSDAライン 83μs 引き下げ、 87μs引き上げ
- データ 40bit がセンサより送信


## 転送ビットプロトコル

ビットデータ40ビットのうちの任意の1ビットは以下のように構成される


|bit|sequence|
|:---:|:---:|
| 0 | 50μs Lo + 26〜28μs Hi |
| 1 | 50μs Lo + 70μs Hi |


# コード

(Public Domain)

```


#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "nrf.h"
#include "nrf_delay.h"
#include "app_error.h"
#include "bsp.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"


#define DHT11_PIN 7

int DHT11ReadByte(void)
{
  int ByteData=0,i;
  unsigned long int counter=0;
  for(i=0;i<8;i++)
  {
    ByteData = ByteData * 2;
    counter = 0;
    while(0==(nrf_gpio_pin_read(DHT11_PIN))) // may be 50us
    {
      counter++;
      nrf_delay_us(1);
      if ( 200 < counter  ){
        NRF_LOG_INFO("error1\n");
        return -1;
      }
    }
    counter = 0;
    while(1==(nrf_gpio_pin_read(DHT11_PIN)))
    {
      counter++;
      nrf_delay_us(1);
      if ( 200 < counter  ){
        NRF_LOG_INFO("error2\n");
        return -1;
      }
    }
    if(counter<30)  // 40... error
    {
            // 26-28us : Bit data "0"
    } else {
      ByteData = ByteData +1; // 70us : Bit data "1"
    }          	
  }
  return ByteData;
}

void DHT11ReadData()
{	
  int counter,err,humiInt,humiDec,tempInt,tempDec,checkSum,decimal_value1,decimal_value2,decimal_value3;
  nrf_gpio_pin_set(DHT11_PIN);
  nrf_delay_ms(250);
  nrf_gpio_cfg_output(DHT11_PIN);
  nrf_gpio_pin_clear(DHT11_PIN);   // Send Start Signal
  nrf_delay_ms(20);   
  nrf_gpio_pin_set(DHT11_PIN);
  nrf_delay_us(40);                // Send Start Signal end
  nrf_gpio_cfg_input(DHT11_PIN, NRF_GPIO_PIN_PULLUP);
  nrf_delay_us(1);
  counter=0;
  while(nrf_gpio_pin_read(DHT11_PIN)==0) // Receive LOW answer ( 83us)
  {
    nrf_delay_us(1);
    counter++;
    if ( 200 < counter ){
        NRF_LOG_INFO("got wrong start1\n");
        return;
    }
  }
  counter=0;
  while(nrf_gpio_pin_read(DHT11_PIN)==1) // Recieve High answer ( 87us)
  {
    nrf_delay_us(1);
    counter++;
    if ( 200 < counter ){
      NRF_LOG_INFO("got wrong start2\n");
      return;
    }
  }
  humiInt = DHT11ReadByte();
  humiDec = DHT11ReadByte();
  tempInt = DHT11ReadByte();
  tempDec = DHT11ReadByte();
  checkSum = DHT11ReadByte();

  if (((humiInt + humiDec + tempInt + tempDec) & 0xff) != checkSum) 
  {
     NRF_LOG_INFO("got wrong values\n");
     return -1;
  } else {
    if ( 127 < tempDec ){
      tempInt=0-tempInt;
      tempDec=tempDec-128;
    }
    NRF_LOG_INFO("TEMP: %d.%d  HUMI: %d.%d",tempInt,tempDec,humiInt,humiDec);
  }
}


int main(void)
{
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    NRF_LOG_INFO("Temp/Humi sensor DHT11 example started.");
    nrf_gpio_cfg_input(DHT11_PIN, NRF_GPIO_PIN_PULLUP);
    SEGGER_RTT_WriteString(0, "DHT11 init complete\n");
    while (true)
    {
        DHT11ReadData();
        nrf_delay_ms(3000);
        NRF_LOG_FLUSH();
    }
}


```

# ビルド

sdk_config.h は examples/peripheral/temperature を使います。

このフォルダーをコピーして、DHT11という名前にしました。


「Nordic SDK で printf と NRF_LOG」
https://qiita.com/nanbuwks/items/3673691779b2e6eca89a
に記したように、ログ出力を適宜直します。

main.cの内容を上記のように直し、SES上でDebug and Buildすると
デバッグターミナルに温度湿度が3秒おきに表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/b061a51a-e53d-b3e1-2426-1d9bc10afb98.png)



# 付記 nRF52840との適合性

センサの電源電圧範囲が、3.3V  - 5.5V。 Nordic nRFの特性を活かした電池駆動などの場合には、 3.3V を供給するのはあまり良い選択とは言えない。2V台でも動作するセンサが望ましい。