【電子工作】Raspberry PiでGrove温湿度センサー(DHT20)を使ってみよう!

ラズパイ

今回は Raspberry Pi 3BGrove Temperature & Humidity Sensor v2.0(DHT20) を使って、温度と湿度をPythonで取得する方法を紹介します。

このセンサーは I²C通信 で簡単に扱えるので、初心者の方でも気軽にセンサープログラミングを体験できます!

スポンサーリンク
スポンサーリンク

使用するもの

商品画像 商品名 特徴 Amazon 楽天
Raspberry Pi 4 画像なし Raspberry Pi 4 OS:Raspberry Pi OS Amazon 楽天
microSDカード(32GB以上) 画像なし microSDカード(32GB以上) OS・ログ保存 Amazon 楽天
Grove 温湿度センサー(DHT20) 画像なし Grove 温湿度センサー(DHT20) 低価格のデジタル温度・湿度センサー Amazon 楽天
SeeedStudio Grove Base HAT for Raspberry Pi 画像なし SeeedStudio Grove Base HAT for Raspberry Pi 本製品(推奨) または ジャンパワイヤで接続する。 Amazon 楽天
Raspberry Pi 4 画像なし

Raspberry Pi 4

OS:Raspberry Pi OS

microSDカード(32GB以上) 画像なし

microSDカード(32GB以上)

OS・ログ保存

Grove 温湿度センサー(DHT20) 画像なし

Grove 温湿度センサー(DHT20)

低価格のデジタル温度・湿度センサー

SeeedStudio Grove Base HAT for Raspberry Pi 画像なし

SeeedStudio Grove Base HAT         for Raspberry Pi

Grove Base HAT(推奨)または ジャンパワイヤで接続する。

※DHT20温湿度センサーは秋月電子の方が安い場合もあるので、ご確認下さい。

配線方法

① Grove Base HATを使う場合(おすすめ)

一番簡単な方法です!
Base HATをPiに装着し、任意のGrove I²Cポートにセンサーを接続するだけでOKです。

  • Groveケーブルを差し込むだけで配線完了
  • 電源や信号のレベル変換もBase HATが自動で処理してくれます

② ジャンパワイヤで直接接続する場合(今回はこちら)

ピン対応は以下の通りです。

DHT20ピンRaspberry Piピン
GNDGND(物理ピン6など)
VCC3.3V(物理ピン1)
SDAGPIO2(物理ピン3)
SCLGPIO3(物理ピン5)

注意:Raspberry PiのI²Cは3.3V系なので、センサーも3.3V給電にしましょう。

配線後のイメージです。参考になされて下さい。

Raspberry Pi側の準備

① I²Cを有効化する

ターミナルを開いて次のコマンドを実行します。

sudo raspi-config

メニューが開いたら
Interface Options → I2C → Enable
を選択して有効化し、再起動します。

② 必要なパッケージをインストール

sudo apt update
sudo apt install -y python3-pip python3-smbus i2c-tools

③ センサーが認識されているか確認

以下のコマンドを実行して、0x38 が見えればOKです。

i2cdetect -y 1

出力例:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- 38 -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  

Pythonで温湿度を取得する

サンプルコード

以下を dht20_read.py という名前で保存します。

#!/usr/bin/env python3
import time
from smbus2 import SMBus, i2c_msg

I2C_BUS = 1
ADDR    = 0x38

def dht20_init(bus):
    while True:
        status = bus.read_byte(ADDR)
        busy   = (status & 0x80) != 0
        cal    = (status & 0x08) != 0
        if (not busy) and cal:
            return
        time.sleep(0.05)

def dht20_read(bus):
    bus.write_i2c_block_data(ADDR, 0xAC, [0x33, 0x00])
    time.sleep(0.08)

    read = i2c_msg.read(ADDR, 7)
    bus.i2c_rdwr(read)
    data = list(read)

    raw_h = ((data[1] << 12) | (data[2] << 4) | (data[3] >> 4)) & 0xFFFFF
    raw_t = (((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]) & 0xFFFFF

    humidity = raw_h / 1048576.0 * 100.0
    temperature = raw_t / 1048576.0 * 200.0 - 50.0

    return round(temperature, 2), round(humidity, 2)

def main():
    with SMBus(I2C_BUS) as bus:
        dht20_init(bus)
        while True:
            t, h = dht20_read(bus)
            print(f"Temp: {t:.2f} °C  Humidity: {h:.2f} %RH")
            time.sleep(2)

if __name__ == "__main__":
    main()

出力例

Temp: 24.12 °C  Humidity: 52.47 %RH
Temp: 24.09 °C  Humidity: 52.58 %RH

これでリアルタイムに温度・湿度が表示されます!

よくあるトラブルと対処法

症状対策
i2cdetect0x38 が出ないSDA/SCLの接続を確認。Groveケーブルを逆挿ししていないかもチェック。
値が出ない / 固まる待機時間(0.08秒)を0.1秒程度に増やしてみる。
読み取りが不安定電源電圧を3.3Vに変更。ケーブルを短くする。
5Vで動かしていた3.3V動作が推奨。PiのI²Cは5V非対応。

まとめ

  • DHT20はI²C接続で配線がシンプル
  • Python + smbus2 で簡単にデータ取得
  • CSV保存でログ解析も可能

Raspberry Piでの温湿度測定は、IoT入門や環境モニタ作りの第一歩にぴったりです!

おまけ: プログラム解説

全体像(このプログラムは何をしているか?)

  1. Raspberry Pi の I²C バス(配線した SDA/SCL)経由で、センサー(DHT20, アドレス 0x38)に「測定して」と命令を出す
  2. 少し待ってから、センサーの生データ(7バイト)を読み取る
  3. 生データを温度(℃)・湿度(%)に変換する式で計算
  4. 2秒おきに「温度・湿度」を表示し続ける

1) インポートと定数

import time
from smbus2 import SMBus, i2c_msg

I2C_BUS = 1
ADDR    = 0x38
  • smbus2:I²C 通信をするための Python ライブラリ。SMBus は「I²C バスを開くためのクラス」、i2c_msg は「まとめて読み書きするためのヘルパー」です。
  • I2C_BUS = 1:Raspberry Pi は標準で I²C-1 を使います(GPIO2/3 がそのバス)。
  • ADDR = 0x38:DHT20(AHT20互換)の I²C 7bit アドレス。i2cdetect -y 1 で見える「38」がこれ。

2) 初期化(センサーが準備OKになるのを待つ)

def dht20_init(bus):
    while True:
        status = bus.read_byte(ADDR)
        busy   = (status & 0x80) != 0
        cal    = (status & 0x08) != 0
        if (not busy) and cal:
            return
        time.sleep(0.05)
  • status = bus.read_byte(ADDR):センサーの ステータスレジスタ を1バイト読む
  • 0x80(bit7):busy ビット。1なら測定中や内部処理中。0になれば読み取り可能
  • 0x08(bit3):校正完了ビット。1なら内部キャリブレーション済み(= 使える状態)

busy=0 かつ 校正=1 になったら準備OK」。それまで 50ms 間隔で待っています。

3) 1回の測定シーケンス

def dht20_read(bus):
    bus.write_i2c_block_data(ADDR, 0xAC, [0x33, 0x00])  # 測定開始コマンド
    time.sleep(0.08)  # 80msほど待つ(データ変換時間)

    read = i2c_msg.read(ADDR, 7)  # 7バイト読み取り
    bus.i2c_rdwr(read)
    data = list(read)
  • 測定開始コマンドは AC 33 00(データシート既定)。これで「温湿度の同時測定」を開始。
  • 変換時間は約 80ms。足りないとデータが未確定のことがあるので 0.08~0.1s が目安。
  • 応答は 7バイト:[status, d1, d2, d3, d4, d5, d6](環境や実装差はありますが、この読み取りで問題ありません)

厳密には、コマンド後に busyビットが0になるまでループで待つ 実装もあります。今回は 80ms スリープで簡易化。

4) 生データのビット詰めをほどく(20bit×2)

raw_h = ((data[1] << 12) | (data[2] << 4) | (data[3] >> 4)) & 0xFFFFF
raw_t = (((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]) & 0xFFFFF
  • DHT20/AHT20 の生データは湿度20bit・温度20bitの計40bitで届きます。
  • 配列 data はバイト列。ビット演算で 20bit を取り出しています。

配列イメージ(7バイト)

data[0]=status
data[1]=H[19:12]
data[2]=H[11:4]
data[3]=H[3:0] | T[19:16]
data[4]=T[15:8]
data[5]=T[7:0]
data[6]=(未使用 or CRC 等 実装差)

ビット演算の意味(超ざっくり)

  • << は左シフト(桁上げ)、>> は右シフト(桁下げ)、| はOR(くっつける)、& はAND(マスク)
  • 0xFFFFF は 20bit の 1(= 2^20 – 1)。20bit 以上を切り落とすマスク。

豆知識(data[1] << 12)data[1] を 12ビット左にずらして、上位桁に置くイメージです。

5) 変換式(生の20bit → 実際の単位)

humidity = raw_h / 1048576.0 * 100.0      # 2^20 = 1048576
temperature = raw_t / 1048576.0 * 200.0 - 50.0
  • 湿度[%RH] = raw_h / 2^20 * 100
  • 温度[℃] = raw_t / 2^20 * 200 - 50

これは DHT20/AHT20 系の公式換算式(データシート)です。
最後に round(x, 2) で小数2桁に丸めています。

6) メインループ(2秒おきに測る)

def main():
    with SMBus(I2C_BUS) as bus:   # I²C-1 を開く
        dht20_init(bus)           # 準備OKになるまで待機
        while True:               # 無限ループ
            t, h = dht20_read(bus)
            print(f"Temp: {t:.2f} °C  Humidity: {h:.2f} %RH")
            time.sleep(2)         # 2秒おき
  • with SMBus(...):処理が終わったら自動でクローズしてくれる書き方
  • Ctrl + C を押すと終了(KeyboardInterrupt)します

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