0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MachiKaniaでDHT11を使って温度と湿度を測定する

0
Posted at

はじめに

先日購入した電子工作ステーションで購入したラズパイ福袋2026に入っていたDHT11温湿度センサーモジュールをMachiKaniaから利用できないをChatGPTと相談しながら試して温度と湿度を測定できました。そのまとめを記します。

検証環境

今回は下記のハードウェア、ソフトウェアで検証しました。

ハードウェア

下記のハードウェアを使用しました。

ソフトウェア

  • MachiKania type P 1.6.1.0 KM-1511

接続

DHT11モジュールとRaspberry Pi Picoは次の表に示すように接続します。
DATA端子は4.7kΩの抵抗でプルアップしています。

DHT11 Pico(物理)
VCC 3V3(36)
DATA GP1(2)
GND GND(38)

実態配線図を以下に示します。

DHT11_ブレッドボード.png

DHT11

DHT11は安価な温度・湿度センサーで、その仕様は電子工作ステーションの製品ページでは次のように記されています。精度が高いセンサーとはいえないですね。

  • 電源電圧:3.3~5.5V
  • 測定範囲温度:0℃~50℃(±2℃)
  • 測定範囲湿度:20〜90%(±5%)
  • サンプリング間隔:2秒以上

電子工作ステーションのDHT11温湿度センサーは-20°C〜60°C(±2°C)とありますが今回使用した基板に搭載されているモジュールは2017年以前のバージョンのようです。

DHT11の通信方式は秋月電子通商のDHT11の製品ページにはシリアル単線(1-wireライク)通信と記されています。詳しくはDHT11のデータシートに記されています。

MachiKaniaには1-wireの関する命令がないのでデータシートに従った信号の送受信が必要です。

測定手順

データシートによるとホストとDHT11の間でデータ通信は次の手順で実行します。

  1. 測定を開始する信号をホストからDHT11に送信します
    1. ホストから18m秒以上のローレベルを送信
    2. 最大で35マイクロ秒ハイレベルの信号を送信
  2. DHT11は測定開始の信号を受信後、応答信号として83マイクロ秒のローレベルを送信します
    その後、周辺機器へ受信準備完了を通知する87マイクロ秒のハイレベルの信号を送信します
  3. 次に40個のデータを送信します。データの0と1は54マイクロ秒のローレベルの後のハイレベルの信号の長さで次のように判別します
    • データ0:23から27マイクロ秒のハイレベル
    • データ1:68から74マイクロ秒のハイレベル
  4. 40個のデータ送信後、DHT11が入力状態に遷移したことを知らせる54マイクロ秒のローレベルの信号を送信します

40個のデータは順番に湿度の整数部8ビット、湿度の小数部8ビット、温度の整数部8ビット、温度の小数部8ビット、チェックディジット8ビットの合計5バイトのデータです。ただし、湿度の小数部は0です。

チェックディジットは湿度と温度の4バイト全てを加算した値です。4つのデータを加算した値と受信したチェックディジットの値を比較すれば受信したデータに誤りがあるかを確認できます。

DHT11の温度の精度が±2℃、湿度の精度が±5%なので小数部の値は正確でないと言えるので表示は整数部のみで十分です。

プログラム

MachiKaniaによるDHT11を使った温度と湿度測定プログラムをChatGPTに作ってもらいました。

手順1の測定開始の信号を作るコード

測定手順1の測定開始の信号は次のコードで生成します。DHT11からデータを読み取るサブルーチンDHT11_READの冒頭部で実行します。DHT11を接続したピン番号をサブルーチンの引数にしています。

LABEL DHT11_READ
  VAR PIN,SUM
  PIN=ARGS(1)
<略>

  OUT PIN,0
  DELAYMS 20
  OUT PIN,1
  DELAYUS 30

<略>  
RETURN

手順2の応答信号との検出

測定開始信号を受信下DHT11が応答の信号(ローレベル83マイクロ秒、ハイレベル87マイクロ秒、その後ローレベル)を送信するのでそれを検出を次のコードで実行します。サブルーチンWAIT_LEVELはピン番号、受信する信号レベル、タイムアウト時間を引数としています。

指定したレベルの信号が得られないときはサブルーチンを状態コードを設定してサブルーチンを抜けます。タイムアウト時間は余裕を持った値を指定しています。もう少し小さな値にしても動作しました。

  IF GOSUB(WAIT_LEVEL, PIN, 0, 200) THEN STAT=1 : RETURN
  IF GOSUB(WAIT_LEVEL, PIN, 1, 200) THEN STAT=2 : RETURN
  IF GOSUB(WAIT_LEVEL, PIN, 0, 200) THEN STAT=3 : RETURN

サブルーチンWAIT_LEVELのコードは次のとおりです。受信する信号レベルがタイムアウトするまでに得られると0を、得られないときは1を返します。

REM -------------------------------------------------
REM Wait until IN(PIN) == LEVEL with timeout [us]
REM return 0: success, 1: timeout
REM -------------------------------------------------
LABEL WAIT_LEVEL
  VAR PIN,LEVEL,TOUT,START
  PIN=ARGS(1)
  LEVEL=ARGS(2)
  TOUT=ARGS(3)

  START=CORETIMER()
  WHILE (CORETIMER()-START) < TOUT
    IF IN(PIN)=LEVEL THEN RETURN 0
  WEND
RETURN 1

手順3の40個のデータ受信

DHT11から送信される40個のデータの受信とチェックサムの確認は次のコードで実行します。

配列Bは受信した5バイトのデータを順に格納します。
FORループの最初でDHT11からの信号がハイレベルになる時間とローレベルになる時間を計り、その差からハイレベルになっている時間を得ます。
ハイレベルになっている時間が50マイクロ秒より大きいときはデータ1を受信したことになるのでデータを記憶する配列要素の値をインクリメントします。これを8回繰り返すと1バイト分の値が得られます。
40個分のデータを受信し終えたら湿度、温度の各データを加算してチェックサムを求め、受信したチェックサムの値と比較して受信したデータの誤りを確認し、誤りがればコード6を返してサブルーチンを抜けます。

  BI=0
  BC=0
  FOR I=0 TO 4
    B(I)=0
  NEXT

  FOR I=0 TO 39
    REM each bit: LOW ~50us then HIGH (26-28us=0, ~70us=1)

    REM wait for HIGH start
    IF GOSUB(WAIT_LEVEL, PIN, 1, 120) THEN STAT=4 : RETURN
    T0=CORETIMER()

    REM wait for LOW end of HIGH pulse
    IF GOSUB(WAIT_LEVEL, PIN, 0, 180) THEN STAT=5 : RETURN
    T1=CORETIMER()

    HIW=T1-T0

    REM MSB first: shift left then add bit
    B(BI)=B(BI)*2
    IF HIW>50 THEN B(BI)=B(BI)+1

    BC=BC+1
    IF BC=8 THEN
      BI=BI+1
      BC=0
    ENDIF
  NEXT

  REM ---- Checksum ----
  SUM=(B(0)+B(1)+B(2)+B(3)) AND $FF
  IF SUM!=B(4) THEN STAT=6 : RETURN

全プログラム

以下がMachiKaniaでDHT11を使って2秒間隔で温度と湿度を測定して表示するプログラムです。

DHT11.BAS
USEVAR DHTPIN,TEMP,HUM,STAT
USEVAR BI,BC,HIW,T0,T1,DUMMY
USEVAR PIN,LEVEL,TOUT,START,SUM

REM =========================
REM DHT11 read sample (KM-BASIC / MachiKania)
REM DATA pin: GP1 (change DHTPIN if needed)
REM =========================

DHTPIN=1

DO
  GOSUB DHT11_READ, DHTPIN

  IF STAT=0 THEN
    PRINT "TEMP(C)= "; TEMP
    PRINT "HUM(%) = "; HUM
  ELSE
    PRINT "DHT11 ERROR = "; STAT
  ENDIF

  REM DHT11は読み取り間隔 2秒以上推奨
  WAIT 120
LOOP

END

REM -------------------------------------------------
REM Wait until IN(PIN) == LEVEL with timeout [us]
REM return 0: success, 1: timeout
REM -------------------------------------------------
LABEL WAIT_LEVEL
  VAR PIN,LEVEL,TOUT,START
  PIN=ARGS(1)
  LEVEL=ARGS(2)
  TOUT=ARGS(3)

  START=CORETIMER()
  WHILE (CORETIMER()-START) < TOUT
    IF IN(PIN)=LEVEL THEN RETURN 0
  WEND
RETURN 1


REM -------------------------------------------------
REM DHT11_READ(PIN)
REM STAT=0 ok
REM STAT!=0 error
REM HUM: integer %RH
REM TEMP: integer degC
REM -------------------------------------------------
LABEL DHT11_READ
  VAR PIN,SUM
  PIN=ARGS(1)

  STAT=0
  DIM B(4)

  REM ---- Start signal (host) ----
  OUT PIN,0
  DELAYMS 20
  OUT PIN,1
  DELAYUS 30

  REM ---- Release / switch to input by reading ----
  DUMMY=IN(PIN)

  REM ---- Sensor response: LOW 80us, HIGH 80us, then LOW ----
  IF GOSUB(WAIT_LEVEL, PIN, 0, 200) THEN STAT=1 : RETURN
  IF GOSUB(WAIT_LEVEL, PIN, 1, 200) THEN STAT=2 : RETURN
  IF GOSUB(WAIT_LEVEL, PIN, 0, 200) THEN STAT=3 : RETURN

  REM ---- Read 40 bits (5 bytes) ----
  BI=0
  BC=0
  FOR I=0 TO 4
    B(I)=0
  NEXT

  FOR I=0 TO 39
    REM each bit: LOW ~50us then HIGH (26-28us=0, ~70us=1)

    REM wait for HIGH start
    IF GOSUB(WAIT_LEVEL, PIN, 1, 120) THEN STAT=4 : RETURN
    T0=CORETIMER()

    REM wait for LOW end of HIGH pulse
    IF GOSUB(WAIT_LEVEL, PIN, 0, 180) THEN STAT=5 : RETURN
    T1=CORETIMER()

    HIW=T1-T0

    REM MSB first: shift left then add bit
    B(BI)=B(BI)*2
    IF HIW>50 THEN B(BI)=B(BI)+1

    BC=BC+1
    IF BC=8 THEN
      BI=BI+1
      BC=0
    ENDIF
  NEXT

  REM ---- Checksum ----
  SUM=(B(0)+B(1)+B(2)+B(3)) AND $FF
  IF SUM!=B(4) THEN STAT=6 : RETURN

  HUM=B(0)
  TEMP=B(2)

 RETURN

実行結果

実行結果を以下に示します。

IMG_3220.jpeg

冷蔵庫の冷凍室にセンサーを入れてると温度が0°Cを下回ると50や51という値になり、0°C未満が測れないことが確認できました。

さいごに

DHT11がシリアル単線通信でデータを送信するということでどうプログラムするのか大まかにはわかるもののコードはどう書くのか、迷ったのでChatGPTに投げかけたところほぼ動作するプログラムが得られました。正しく動作するよだったのでデータシートとにらめっこしながらその内容を理解するという逆の流れになってしまいました。スパッとコードが書けると良かったのですがが・・・(^◇^;)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?