ゆるく楽しむプログラミング

温湿度センサー DHT11 (1-Wire接続)

ビギナーキットなどに同梱されているメジャーな温湿度センサー

 プルアップ抵抗がセットされたユニット
 センサー単体でも1個300円なので(プルアップ抵抗なし)なので妥当な価格

 
データの読み取りは単線バス(双方向)を通して行います。
アドレスのない1-Wire接続のようです。
※1-Wireは商標登録されているらしいてす、なので、1-Wire接続ではなく 単線バスだそうです。

データの通信手順(プロトコル)

以下の手順で通信を行います

■通信の開始
 ホスト側から:18m秒間LOW信号を出力


■通信開始の応答
 デバイス側から:80μ秒LOW - 80μ秒HIGH


■データ:'0'
 デバイス側から;50μ秒LOW-28μ秒HIGH

■データ'1'
 デバイス側から:50μ秒LOW-70μ秒HIGH

■ デバイスから送信されるデータ
 下記表の順番に40Bit(5Byte)が送信される
内容  範囲  長さ 
湿度の整数部 20~95 8Bit(1Byte)
湿度の小数部 常に0 8Bit(1Byte)
温度の整数部 0~50 8Bit(1Byte)
温度の小数部 0~9 8Bit(1Byte)
Check SUM 0x00~0xFF 8Bit(1Byte)

データの受信方法

■ 内蔵のPULL-UP抵抗を有効にする
 pinMode(DATAPIN, INPUT_PULLUP);

■ データ送信要求 を送信して 入力がLOWになるのを待つ
 pinMode(DATAPIN, OUTPUT); //開始信号
 delay(20); // ※18m秒以上なので、念のため(?)20m秒待つ
 pinMode(DATAPIN, INPUT); // 入力に切り替え
 while(digitalRead(DATAPIN) == LOW) { // 入力値がLOWになるまで待つ
   delayMicroseconds(5) ;
 }

■ 外部割込みを使用してデータを受信する方法
  ※ ArduinoUNO用 : DHT11の信号ピンはArduinoUNOの2番ピンに接続する
    DHT11-INTERRUPT.zip



■ 入力値が変化するまでdigitalRead()を繰り返す:ポーリング処理
 ※DHT11の信号ピンは何処につないでも良い
    DHT11-LOOP.zip

※ <>を全角<>に置き換えています。コピペの際は注意してください。
// 温湿度センサー DHT11 アクセステスト
// 全力でループするバージョン

#define BAUDRATE 9600
#define DATAPIN 2 // コレは何番ピンでも良い

char str[120] ;

// ----- Senser Data
struct dht11_s {
  int8_t humidityN ;   // 湿度の整数部
  int8_t humidityD ;   // 湿度の小数部 ※は常に0
  int8_t temperatureN; // 温度の整数部
  int8_t temperatureD; // 温度の小数部
} dht11 ;

bool readDTH11( ) {
  uint8_t readData[5] ;
  uint8_t checkSum = 0 ;
  int setPos = 0 ;
  int bitLen = 0 ;
  int stat = HIGH ;
  uint8_t bitData ;
  unsigned long beginTime ;
  unsigned long passTime ;
  unsigned long zeroTime = 35 ; // 35μ秒以下なら0 以上なら1と判定 ※仕様では0は26~28μ秒
  bool flagStart = false;

  for (int i=0;i<5;i++) {
    readData[i] = 0 ;
  }

  // ----- データ送信要求 -----
  pinMode(DATAPIN, OUTPUT); //開始信号
  delay(20);
  pinMode(DATAPIN, INPUT);
  while(digitalRead(DATAPIN) == LOW) {
    delayMicroseconds(5) ;
  }

  // ----- ACSEPT -----
  flagStart = false;
  passTime = 0 ;
  beginTime = micros();
  while (passTime < 1000) {
    passTime = micros() - beginTime ;
    if (digitalRead(DATAPIN) !=  stat) {
      if (stat == HIGH) {
        stat = LOW ;
        if (flagStart) {
           break ; 
        }
      } else {
        beginTime = micros();
        flagStart = true ;
        stat = HIGH ;
      }
    }
  }
  
  // ----- データ受信 -----
  bitData = 0x80 ;
  flagStart = false;
  passTime = 0 ;
  beginTime = micros();
  while (bitLen < 40 && passTime < 1000) {
    passTime = micros() - beginTime ;
    if (digitalRead(DATAPIN) !=  stat) {
      if (stat == HIGH) {
        stat = LOW ;
        if (flagStart) {
          // ----- 1Bit 受信 -----
          if (passTime > zeroTime) {
            readData[setPos] |= bitData ;
          }
          if (bitData != 0x01) {
            bitData >>= 1 ;
          } else {
            bitData = 0x80 ;
            setPos ++ ;
          }

          // ----- ステート変数リセット -----
          beginTime = micros();
          flagStart = false;
          bitLen ++ ;
        }
      } else {
        beginTime = micros();
        flagStart = true ;
        stat = HIGH ;
      }
    }
  }

  // ----- 取得データ格納 -----
  dht11.humidityN = readData[0] ;   // 湿度の整数部 Range:5~95
  dht11.humidityD = readData[1] ;   // 湿度の小数部 ※は常に0
  dht11.temperatureN = readData[2]; // 温度の整数部 -20 ~ 
  dht11.temperatureD = readData[3]; // 温度の小数部
  checkSum = readData[0] + readData[1] + readData[2] + readData[3] ;

  return (bitLen == 40 && checkSum == readData[4]) ;
}

void setup() {
  Serial.begin(BAUDRATE);
  Serial.println("\nDHT11 - Read") ;

  pinMode(DATAPIN, INPUT_PULLUP);
}


void loop() {
  if (readDTH11( )) {
    sprintf(str,"気温:%2d.%d℃ 湿度:%2d%%", dht11.temperatureN ,dht11.temperatureD,dht11.humidityN ) ;
    Serial.println(str) ;
  }

  delay(3000) ;
}

参考動画

参考動画で使用している温湿度計デモの配線図とスケッチ
DHT11のプルアップ抵抗は4.7KΩを使用。※PULL-UP抵抗付きのユニットを使用する場合には不要
ディスプレイはOLED SSD1306 または OLED SSD1315 を使用してください。(どちらでも動作します)
タグスイッチは7セグメントっぽい表示とグラフ表示の切り替え用、なくても構いません。
タグスイッチの抵抗は適当で、10KΩ位を推奨

※ Arduino用とRaspberriPi Pico用は別のスケッチ
※ メモリー容量の都合で、ArduinoではフォントをFLASHメモリーに配置しているだけで、ロジックは同じです。

DHT11-DEMO.zip :Arduino用



DHT11-DEMO-Pico.zip : RaspberryPi Pico用 ※mbedのボードライブラリを想定しています



解説動画