環境
- 開発ボード アオノドン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秒おきに表示されます。
付記 nRF52840との適合性
センサの電源電圧範囲が、3.3V - 5.5V。 Nordic nRFの特性を活かした電池駆動などの場合には、 3.3V を供給するのはあまり良い選択とは言えない。2V台でも動作するセンサが望ましい。