アフィリエイト広告
アフィリエイト広告

温湿度センサ DHT11 を使ってみる (3)

DHT11 から、温度と湿度の測定値を読み出すことができましたので、温湿度計を作ってみることにしましょう。

温湿度センサ DHT11 を使ってみる (2)
前回は、温湿度センサ DHT11 のデータシートを読んでみました。 通信インターフェースは独自プロトコルのようですが、そんなに難しい手順ではありません。自前でスケッチを書いて、テストしてみることにします。 回路図 DHT11 を Ardui...

測定値は、温度と湿度をそれぞれ 2 桁の 7 セグメント LED 表示器に表示させることにします。
温度の測定範囲が -20〜60℃ ですが、室温が氷点下になることはまずないので、最低値は 0℃ にして、マイナス表示はしません。湿度は 5〜95%RH なので、問題ないです。

回路図

回路図です。なんだか、見慣れた回路図、になってきちゃいました。

今回も LED ドライバ IC TM1630 を使って 7 セグメント LED を駆動します。TM1630 は 4 桁表示モードですが、2 桁ずつを個別に表示させます。そんな使い方も、簡単にできちゃうんですね。そのあたりはスケッチの解説で。

ちなみに、DHT11 の電源は Arduino の 5V 出力を使っています。TM1630 はわりとノイズが出ますので、影響を避けるためです。

スケッチ

DHT11 からデータを読み出すスケッチと、TM1630 を駆動するスケッチを並べただけです。詳細は、これまでの記事を参照して下さい。

なお、シリアル通信の部分はデータの確認用ですので、取っ払っちゃってかまいません。

  1. // Temperature Humidity Meter 2022.05.31 by meyon
  2. // DHT11 Definition
  3. const byte pinDHT11 = 7;
  4. // 7-SD Driver TM1630 Definition
  5. #define DISPLAY_MODE 0x00
  6. #define WRITE_REG_AUTO_ADDR 0x40
  7. #define SET_DISPLAY_ADDR 0xC0
  8. #define DISPLAY_ON 0x88 | 0x84
  9. #define STB_ENABLE LOW
  10. #define STB_DISABLE HIGH
  11. #define DOT_POSITION -1
  12. const byte dioPin = 10;
  13. const byte clkPin = 11;
  14. const byte stbPin = 12;
  15. const byte numberOfDigits = 2;
  16. byte gridData[numberOfDigits] = {0};
  17. const byte digit[] = {
  18.   0b01111110, // 0
  19.   0b00001100, // 1
  20.   0b10110110, // 2
  21.   0b10011110, // 3
  22.   0b11001100, // 4
  23.   0b11011010, // 5
  24.   0b11111010, // 6
  25.   0b01001110, // 7
  26.   0b11111110, // 8
  27.   0b11011110, // 9
  28.   0b00000000, // 10:blank
  29.   0b00100000, // 11:dot
  30. };
  31. const byte blank = 10;
  32. const byte dot = 11;
  33. void setup() {
  34. // 7-SD Driver TM1630 Setup
  35.   pinMode(dioPin, OUTPUT);
  36.   pinMode(clkPin, OUTPUT);
  37.   pinMode(stbPin, OUTPUT);
  38.   Serial.begin(9600);
  39. }
  40. // Read Data from DHT11
  41. void readDHT11(byte *temp, byte *hmd) {
  42.   const int timeout = 500; // us
  43.   byte startResponse = 0;
  44.   byte detectedValue[5] = {0};
  45.   byte checkDigit = 0;
  46.   pinMode(pinDHT11, OUTPUT);
  47.   delay(20);
  48.   pinMode(pinDHT11, INPUT);
  49.   startResponse = pulseIn(pinDHT11, HIGH, timeout);
  50.   if(startResponse) {
  51.     for(byte i=0; i<5; i++) {
  52.       for(byte j=0; j<8; j++) {
  53.         byte duration = pulseIn(pinDHT11, HIGH, timeout);
  54.         detectedValue[i] *= 2;
  55.         if(54 < duration) detectedValue[i] |= 1;
  56.       }
  57.     }
  58.     for(byte i = 0; i < 4; i++) {
  59.       checkDigit += detectedValue[i];
  60.     }
  61.     if((detectedValue[4] == checkDigit) && checkDigit) {
  62.       *hmd = detectedValue[0];
  63.       *temp = detectedValue[2] + (0x04 < detectedValue[3] ? 1 : 0);
  64.       if(0x7F < detectedValue[3]) *temp = 0;
  65.     }
  66.     for(byte i=0; i<5; i++) {
  67.       Serial.print(detectedValue[i]);
  68.       Serial.print(" ");
  69.     }
  70.   }
  71. }
  72. // 7-Segment Display Drive
  73. void displayNumbers(int n, byte addr) {
  74.   for (byte i = 0; i < numberOfDigits; i++) {
  75.     int exponentialInDecimal = pow(10, i) + 0.5;
  76.     bool zeroSuppression = (0 != i) && (DOT_POSITION < i) && (exponentialInDecimal > n);
  77.     gridData[i] = zeroSuppression ? blank : n / exponentialInDecimal % 10 ;
  78.   }
  79.   digitalWrite(stbPin, STB_ENABLE);
  80.   shiftOut(dioPin, clkPin, LSBFIRST, DISPLAY_MODE);
  81.   digitalWrite(stbPin, STB_DISABLE);
  82.   digitalWrite(stbPin, STB_ENABLE);
  83.   shiftOut(dioPin, clkPin, LSBFIRST, WRITE_REG_AUTO_ADDR);
  84.   digitalWrite(stbPin, STB_DISABLE);
  85.   digitalWrite(stbPin,STB_ENABLE);
  86.   shiftOut(dioPin, clkPin, LSBFIRST, SET_DISPLAY_ADDR | addr);
  87.   for (byte i = 0; i < numberOfDigits; i++) {
  88.     shiftOut(dioPin, clkPin, LSBFIRST, digit[gridData[i]]);
  89.     shiftOut(dioPin, clkPin, LSBFIRST, DOT_POSITION == i ? digit[dot] : 0);
  90.   }
  91.   digitalWrite(stbPin, STB_DISABLE);
  92.   digitalWrite(stbPin, STB_ENABLE);
  93.   shiftOut(dioPin, clkPin, LSBFIRST, DISPLAY_ON);
  94.   digitalWrite(stbPin, STB_DISABLE);
  95. }
  96. void loop() {
  97.   static const int interval = 2500; // ms
  98.   static unsigned long previousMillis = 0;
  99.   static byte humidity = 0;
  100.   static byte temperature = 0;
  101.   if(interval < millis() - previousMillis) {
  102.     readDHT11(&temperature, &humidity);
  103.     displayNumbers(temperature, 0x04);
  104.     displayNumbers(humidity, 0x00);
  105.     Serial.print("/ ");
  106.     Serial.print(temperature);
  107.     Serial.print("C ");
  108.     Serial.print(humidity);
  109.     Serial.print("%\n");
  110.     previousMillis = millis();
  111.   }
  112. }

4 桁表示モードの TM1630 で、温度と湿度をそれぞれ 2 桁ずつ表示させるための変更点だけを記しておきます。

TM1630 表示レジスタアドレス
TM1630 アドレス指定コマンド

7 セグメント LED の何桁目に表示させるかは、左の表の表示レジスタアドレスによります。

1〜4 桁目は GRID1〜GRID4 に対応しています。
温度は GRID3 と GRID4 に、湿度は GRID1 と GRID2 に表示させることにしましょう。

アドレスはデータの数だけ自動インクリメントするようにしていますので、最初のアドレスだけを指定すればよいです。したがって、温度は 04H 、湿度は 00H ということになります。

  1.   shiftOut(dioPin, clkPin, LSBFIRST, SET_DISPLAY_ADDR | addr);

106 行目。表示レジスタのアドレスを指定するコマンドです。
アドレス指定コマンド SET_DISPLAY_ADDR の値は 0xC0 です。これにアドレスとして、温度は 0x04 を、湿度は 0x00 を加えて、アドレスの指定を行ないます。

  1.     displayNumbers(temperature, 0x04);
  2.     displayNumbers(humidity, 0x00);

アドレスは引数として渡すことにします。

  1. const byte numberOfDigits = 2;

もう一点。19 行目の表示桁数を 2 に変更します。

以上で、2 桁ずつ独立した表示が可能になりました。

ブレッドボード

DHT11 を使った温湿度計

毎度おなじみの、ブレッドボードです。

一番上はいつもの電源。5V と 9V を供給しています。
7 セグメント LED の 4 桁を常に表示しているので、5V のレギュレータが少し暖かくなります。

次が 7 セグメント LED と ドライバ IC TM1630 。
4 桁の LED をそのまま使ってますが、2 桁を 2 個にするのが良いと思います。

3 つ目のブレッドボードに DHT11 が載ってます。

一番下は、言わずと知れた Arduino UNO です。

これ、きちんと製作しようかしらん (^_^;)

製作後記

まぁなかなか良くできたんじゃね?って思ってます。
気に入らないのは、起始信号の 20ms が長げーよ、ってこと。ローエンドの機種なので仕方ないケド。

20ms の間に他の処理ができるようなスケッチも、じつは書いてみたんだけど、時間が不安定になっちゃって、ビットの読み取りエラーが頻発してしまう。ライブラリではどうしているんだろうと、つらつら眺めてみたんですが、ほとんど同じことやってました (^_^;)

DHT11 読み取りの関数を呼び出したら、20ms の起始信号に続いて、データの読み取りに約 4ms 必要です。この間、他の処理ができなくなるのは、仕様です (;´Д`)

なので、7 セグメント LED 点灯させるには TM1630 とか使いたくなる。
ただ、TM1630 へコマンドを送るのも 2ms x 2 回必要なので、リアルタイムに何かやるのは無理っぽい。TM1630 に関しては、SPI 使えば速くできると思いますが、その価値あるかどうかは考え方次第です。

タイトルとURLをコピーしました