Raspberry Piで電子工作(7) 温度・湿度センサー

今回は、DHT11という温度・湿度センサーを使用して、温度と湿度をモニタリングするプログラムを作成する。

DHT11

シリアル入力で動き、温度や湿度を計測できるセンサーである。以下の図のようにラズパイ側でLOW→HIGHの順番に出力すると、スタートシグナルとなり、順番に決まった時間に決まった信号が出力される。具体的な手順は、以下のとおりである。

  1. 最初に、18msLOW、20~40マイクロ秒HIGHと出力する。
  2. 次にDHT11から、「80マイクロ秒のLOW、80マイクロ秒のHIGH」という動作で応答が返ってくる。
  3. 以下、順番に1ビットずつデータが送信される。26~28マイクロ秒の場合は0、70マイクロ秒の場合は1というように解釈すればよい。
  4. 以下の順番で、データが出力される。データは全部で40bit(5バイト)となる。
    1. 湿度の整数部分(8bit)
    2. 湿度の小数部分(8bit)→実際はデータなし??
    3. 温度(摂氏)の整数部分(8bit)
    4. 温度(摂氏)の小数部分(8bit)
    5. パリティビット(検査ビット)(8bit)

今回製作する回路

今回は、以下のように配線した。3端子しかなく、2端子は5VとGNDなので、難しくない。

作成したプログラム

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>
#define MAXTIMINGS 85 // 1信号の長さの最大値(マイクロ秒)
#define DHTPIN 29     // 温度センサーの接続ピン
int dht11_dat[5] = {0, 0, 0, 0, 0}; // 温度センサーのデータ格納

void read_dht11_dat(void) {
    uint8_t laststate = HIGH;
    uint8_t counter = 0;
    uint8_t j = 0; // ビット数カウント用
    uint8_t i;     // 時間(マイクロ秒)計測用

    // 0で初期化
    dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;

    /* 18msピンをLOWにする */
    pinMode(DHTPIN, OUTPUT);
    digitalWrite(DHTPIN, LOW);
    delay(18);
    /* 40msピンをHIGHにする */
    digitalWrite(DHTPIN, HIGH);
    delayMicroseconds(40);
    /* DHTPINをINPUTにして情報を読み込む準備をする */
    pinMode(DHTPIN, INPUT);

    /* 値が変更された場合、データを読み込む */
    for (i = 0; i < MAXTIMINGS; i++) {
        counter = 0;
        /* 前回と同じ値の場合 */
        while (digitalRead(DHTPIN) == laststate) {
            counter++;
            delayMicroseconds(1);
            if (counter == 255) {
                break;
            }
        }
        laststate = digitalRead(DHTPIN);

        if (counter == 255)
            break;

        /* 初めの2回はデータではないので無視 */
        if ((i >= 3) && (i % 2 == 0)) {
            /* 各ビットをストレージバイトに流し込む */
            dht11_dat[j / 8] <<= 1;
            if (counter > 28)          // 28マイクロ秒以上の場合
                dht11_dat[j / 8] |= 1; // ビットデータを1とする
            j++;
        }
    }

    /* 40bit(5byte)のデータを格納して、パリティビット(最後の8bit)を利用して、正しいか確認する */
    if ((j >= 40) && (dht11_dat[4] == ((dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF))) {
        printf("Humidity = %d.%d %% Temperature = %d.%d ℃\n", dht11_dat[0], dht11_dat[1], dht11_dat[2], dht11_dat[3]);
    }
    // パリティビットと一致しなかった場合
    else {
        // メッセージを表示して終了
        printf("Data not good, skip\n");
    }
}

int main(void) {
    printf("Raspberry Pi wiringPi DHT11 Temperature test program\n");
    wiringPiSetup();

    while (1) {
        read_dht11_dat(); // 関数呼び出し
        delay(2000); // 2秒待ち
    }

    return 0;
}

プログラムの説明

5, 6行目で使用するピンを指定(マクロ定義)する。

7行目で温度センサーのデータを格納する配列を用意する。(グローバル変数で宣言)

9行目からの関数read_dht11_dat()で、データを取得する。
以降、関数の中の動作について説明する。

16行目で、配列dht11_datを0で初期化する。

29行目からは、値を読み込み、配列に格納する処理をしている。
値が同じ場合は、変化するまで何もしない処理になる。

45行目では、初めの2回分のデータを無視するようにしている。(単なる応答データのため)

46行目以降は、データを配列に格納している。
28マイクロ秒以上の場合、ビットデータを1、それ以外は0を格納する。

55行目からは、パリティビットと比較し、一致すれば温度と湿度を表示し、不一致の場合は、「Data not good, skip」と表示する。
パリティビットはdht11_dat配列0~3を足した数となる。

main関数は、 read_dht11_dat() を呼び出しているだけである。


トップページに戻る