今回は、DHT11という温度・湿度センサーを使用して、温度と湿度をモニタリングするプログラムを作成する。
シリアル入力で動き、温度や湿度を計測できるセンサーである。以下の図のようにラズパイ側でLOW→HIGHの順番に出力すると、スタートシグナルとなり、順番に決まった時間に決まった信号が出力される。具体的な手順は、以下のとおりである。
#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() を呼び出しているだけである。