温湿度センサーDHT20とAHT25から温度データと湿度データを読み取る方法を紹介します。
Raspberry PiとRaspberryPi OSに標準でインストールされているプログラム言語のPythonを使用して、I2C通信でデータを読み取ります。
サンプルプログラムでは、データ読み取り以外に測定条件設定も行います。
ちなみに、DHT20とAHT25は、同一のI2Cアドレスで全く同じプログラムで動作しました。
仕様についても精度以外の違いは無いように読み取れます。
DHT20とAHT25の主な仕様
【湿度測定】
DHT20
精度:±3%(typical)
再現性:±0.1%RH
ヒステリシス:±1%RH
分解能:0.024%RH(typical)
AHT25
精度:±2%(typical)
以下DHT20と同じ
【温度測定】
DHT20
精度:±0.5℃(typical)
再現性:±0.1℃
ヒステリシス:±0.1℃
分解能:0.01℃
AHT25
精度:±0.3℃(typical)
以下DHT20と同じ
準備
DHT20/AHT25の購入
DHT20はプラスチックケースに入って脚が4本出ている形状です。
0.1インチピッチ(2.54mm間隔)なので、特に気を遣うことはありません。
AHT25はモジュールの状態で、コネクタ付きのケーブルが付属されていました。
下の写真は秋月電子通商で購入したDHT20とAHT25モジュールで、今回はこれらのモジュールを使います。
【DHT20】
【AHT25】
モジュールとRaspberry Piの接続
接続図
接続写真 DHT20
接続写真 AHT25
Raspberry Piの通信設定とPythonの操作方法
Raspberry PiのI2C通信設定を有効にします。
下の記事でRaspberry PiのI2C通信設定と、Pythonの基本操作を説明しています。
I2C通信プログラミング
プログラムコード
Pythonプログラムです。DHT20とAHT25は同じプログラムで動作します。
※修正(2022.4.11)
18行目をコメントアウト
18行目のifがインデントエラーの原因となる為(while 1:でインデントエラー)。
import smbus
import time
# I2C設定
i2c = smbus.SMBus(1)
address = 0x38
#トリガ設定コマンド
set = [0xAC, 0x33, 0x00]
#データ読み込み用
dat = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
# DHT20/AHT25設定
time.sleep(0.1)
ret = i2c.read_byte_data(address, 0x71)
# if ret != 0x18:
# initialization process
# 繰り返し
while 1:
# トリガ測定コマンド送信
time.sleep(0.01)
i2c.write_i2c_block_data(address, 0x00, set)
# データの読み込み
time.sleep(0.08)
dat = i2c.read_i2c_block_data(address, 0x00, 0x07)
# データ変換
hum = dat[1] << 12 | dat[2] << 4 | ((dat[3] & 0xF0) >> 4)
tmp = ((dat[3] & 0x0F) << 16) | dat[4] << 8 | dat[5]
# 物理量変換
hum = hum / 2**20 * 100
tmp = tmp / 2**20 * 200 - 50
# 表示
print("hum: " + str(hum))
print("tmp: " + str(tmp))
time.sleep(1)
プログラムの説明
プログラムの流れです。
- I2C通信の設定をします
- センサーの設定をします
- センサーにトリガ測定コマンドを送ります
- センサーから温湿度データを取得します
- データを物理量に変換し画面に表示します
- 3.~5.を繰り返します。
1.I2C通信の設定をします
# I2C設定
i2c = smbus.SMBus(1)
address = 0x38
i2c = smbus.SMBus(1)
インスタンス生成です。使用するBus1を指定します。
address = 0x38
アドレス指定です。DHT20とAHT25のアドレスはどちらも0x38(16進数)で、通信時に指定します。
Raspberry Piにセンサーを接続した状態で、LXTerminalから「i2cdetect -y 1」コマンドを入力すると、アドレスが0x38であることを確認出来ます。
2.センサーの設定をします
各種設定のときは、データシートで指定された待機時間のウェイトを入れています。
# DHT20/AHT25設定
time.sleep(0.1)
ret = i2c.read_byte_data(address, 0x71)
if ret != 0x18:
# initialization process
time.sleep(0.1)
電源投入後100msec以上待機します。
ret = i2c.read_byte_data(address, 0x71)
0x71でステータスを取得します。取得したステータスが0x18でない場合は、0x1B、0x1C、0x1Dレジスタを初期化します。
※レジスタの初期化方法は、「公式ウェブサイトを参照」とデータシートに記載されています。
残念ながら見つけることが出来なかったので、コメント(#initialization process)にしています。
データシートの『7.4 Sensor Reading Process』で詳細を確認できます。
『公式ウェブサイト』のサンプルプログラム(aht20-21 51mcu demo.zip)をダウンロードしたところ、レジスタの初期化の記述がありました。
トップページの下段の『下载中心』という所からダウンロードページに行けました。
main.cファイルのmain()関数で、ステータスを読み込んだ結果と0x18のandをとってエラー判断をしています。ここでエラーがあった場合にAHT20_Start_Init()をコールしています。この関数がレジスタの初期化関数と思われます。
いずれ、このAHT20_Start_Init()関数を移植して動作確認してみます。
2022.4.11
3.センサーにトリガ測定コマンドを送ります
# トリガ測定コマンド送信
time.sleep(0.01)
i2c.write_i2c_block_data(address, 0x00, set)
time.sleep(0.01)
10msec待機します。
i2c.write_i2c_block_data(address, 0x00, set)
set(トリガ測定コマンド)をセンサーに送ります。
setの中身は、[0xAC, 0x33, 0x00]の3バイトです。
データシートの『7.4 Sensor Reading Process』で詳細を確認できます。
4.センサーから温湿度データを取得します
# データの読み込み
time.sleep(0.08)
dat = i2c.read_i2c_block_data(address, 0x00, 0x07)
time.sleep(0.08)
80msec待機します。
dat = i2c.read_i2c_block_data(address, 0x00, 0x07)
ステータス 8bit、湿度データ 20bit、温度データ 20bit、CRC 8bitの合計56bit(7バイト)を読み込みます。
ステータス 8bit
dat[0]がステータスです。このステータスのbit[7]が0であれば、測定完了を意味します。1であれば測定中です。
このステータスは、80msecの待機を実行すれば0になり、待機時間を短くすると1になることを確認しました。
湿度データ 20bit
dat[1]、dat[2]、dat[3]の上位4bitの合計20bitが湿度データです。
温度データ 20bit
dat[3]の下位4bit、dat[4]、dat[5]の合計20bitが温度データです。
CRC 8bit
CRCは、データ通信中にノイズなどで値が変化してしまった時に、間違いを発見するために使用します。
CRCの詳しい説明はこちら
「巡回冗長検査」(2021年8月21日 (土) 20:49 UTCの版)『ウィキペディア日本語版』
5.データを物理量に変換し画面に表示します
# データ変換
hum = dat[1] << 12 | dat[2] << 4 | ((dat[3] & 0xF0) >> 4)
tmp = ((dat[3] & 0x0F) << 16) | dat[4] << 8 | dat[5]
読み込んだデータは、8bitの入れ物5つに入っています。
これを20bitの湿度データと、20bitの温度データにします。
湿度データ
温度データ
データシートの『7.4 Sensor Reading Process』の『5.Calculate the temperature and humidity value』で詳細を確認できます。
# 物理量変換
hum = hum / 2**20 * 100
tmp = tmp / 2**20 * 200 - 50
データシートで指定された計算で物理量に変換します。
hum = hum / 2**20 * 100
Relative Humidity Conversion
RH[%] = (SRH / 220) × 100%
tmp = tmp / 2**20 * 200 – 50
Temperature Conversion
T[℃] = (ST / 220) × 200 – 50
データシートの『8 Signal Conver』で詳細を確認できます。
# 表示
print("hum: " + str(hum))
print("tmp: " + str(tmp))
print(“hum: ” + str(hum))
測定した湿度と温度を画面に表示します。
5.3.~4.を繰り返します
# 繰り返し
while 1:
while 1:
Stopボタンが押されるまで繰り返します。
※この『while 1:』は、22行目のwhile文です。
プログラムの実行結果
プログラムを実行します。
①Runボタンを押します。
②温度データと湿度データを1秒間隔で画面に表示します。
③Stopボタンを押すとプログラムは終了します。
以上、DHT20およびAHT25モジュールからI2C通信で湿度データと温度データを読み込んで画面に表示するサンプルでした。
まとめ
うまく動作させることは出来たでしょうか?
DHT20とAHT25は同じメーカーではありますが、まさかI2C通信のアドレスまで一緒だったのは、びっくりしました。センサー自体は同一で、精度で選別しているのかもしれません。
とりあえず両方を同時に使うことは無いと思うので問題にならないと思います。
プログラミングやソフトウェアの記事です。
コメント
こんにちは
こちらのテーマと似た様なケースを今実験中です。
大気圧と気温を測り、ファイルに出力し(=未完)、
ファイルをグラフ化して気圧の高低推移を
サインカーブの様な感じで見たい(=未完)。
しかし、現在「手こずって居ます」w
私が実験しているスクリプトでは
走らせると「流れる様」に結果が、コンソールに表出します。
日、時、大気圧、気温の記録がその時刻の1回だけ欲しい。
(そして、経時的に例えば10分インターバルで計測し
結果をファイルに追記させたい。)
とりあえず、「流れる様」に表示される計測状況を止めたい。
勿論、
[ctrl]+c
で止める事は出来ますが、ともかく日、時、大気圧、気温の1行文
だけほしい。
そこで、こちらの
=====
#繰り返し
while True:
======
が、目に留まりました。
この「while」は、条件が満たされている間中、繰り返すん
だったな。
(プログラム参考書では、はっきりイメージ出来なかったが
実際のプログラムの中では、こう使われるのか)
記事の解説が役立ちました
『そうか、私が実験中のスクリプト(Webの記事からコピーした
実験用プログラム)にも、
while( True):
のブロックがあるぞ』
ここを、「#」で止めて観たらどうか?
結果
二回 インデントエラーで止まりましたが、修正を試して、
お陰で様で、上手く活きました。
これは、時間を措き手動実行させた結果です。
$ python3 lps25_2.py
2022/02/02,12:45, 1003.0 , 85.69 , 19.54
$ python3 lps25_2.py
2022/02/02,12:46, 1003.05 , 85.27 , 19.59
$ python3 lps25_2.py
2022/02/02,12:48, 1003.04 , 85.32 , 19.7
(数値は気圧、標高、気温)
(これまでですと、表示時間は固定で(プログラクがONされた時間)
記録だけが、ざーっと表示され、記録としては意味が有りませんでした
経時的に時=記録になっていない、センサーは動いてますだけの出力)
この状態で、[ crontab ]を使って、経時実行させれば
良さそうです・・・先はまだまだ長そうw。
でも、ここ三日ほど、さ迷っていましたが・・
今朝、お陰様で一つ解決しました
ありがとう、ございます。
とんかつさん、コメントありがとうございます。
記事の内容がお役にたてて幸いです。
ちなみにサンプルプログラムの『time.sleep(1)』という記述を『time.sleep(600)』にすると10分間隔で計測します。
※どの程度まで正確にインターバル計測が出来るかは不明です。すみません。
こんばんは
電子工作もPythonやRaspberry Piも初心者です(ラズパイ電子工作の入門本を一通り真似して作ったことがある程度です)。
小さな湿度センサーで測りたいものがあったのですが、使い方が分からず、このような記事を書いていただいて本当にありがたいです。
AHT25を書いていただいたように接続し、ラズパイの設定でi2cも有効にし、上記のプログラムコード1〜44行目を真似して書いて実行したところ、
——-
Traceback (most recent call last):
File “/usr/lib/python3.5/ast.py”, line 35, in parse
return compile(source, filename, mode, PyCF_ONLY_AST)
File “/home/pi/ (私が保存したプログラム) , line 22
while 1:
^
IndentationError: expected an indented block
————
と出ました。
1つ目のエラーは対処が分からず、
2つ目のエラーは、行頭に空白が必要か?と
while 1:
の前に空白を入れました。
そうすると、今度はエラーは出ないのですが、温湿度の結果が表示されません。
また解説に
while True:
が書かれていますので、プログラムの最後に追記したところ
今度は、
SyntaxError: unexpected EOF while parsing
と出てしまいます。
初心者レベルで申し訳ありませんが、アドバイスいただけないでしょうか。
るま様
ご質問ありがとうございます。
①エラー”Indentation Error”は、サンプルプログラムのコメントアウト忘れが原因です。すみません。
詳細な原因は、
18行目の『if』の後に、字下げ(インデント)した『# initialization process』を記述していますが、これはコメントなので字下げしても関係ありません。
『if』の次の処理は、22行目の『while 1:』となり、インデントエラーが発生していると思われます。
対策は、
18行目の『if』は、現時点では使用していない(ステータスエラーがあっても初期化方法がわからない)ので『#』を付けてコメントにします。
②エラー”Syntax Error”は、プログラムの最後に『while True:』を追加した影響だと思われます。
記事の内容が『while True:』と『while 1:』を混同して使って、混乱させてしまったと思います。
記事の修正しました。
ザックリまとめますと、
①18行目をコメントにする。
②最後のwhile True:を削除する。
わかりずらい説明ですみません。これで試してみてください。
よろしくお願いします。
ワッホー様
素早いご回答本当にありがとうございます。
そして、分かりやすくご説明いただいて本当に助かりますm(_ _)m
ワッホー様のアドバイスで、測定できるようになりましたー!!!
ワッホー様の親切なご対応に感動しております。
まだまだ、パーツを購入しても使い方が自力では分からないわたくしですが、
raspberry piで電子工作楽しいですね。
本当にありがとうございます。
るま様
測定が出来る様になって良かったです。
私も電子工作を楽しんでます。
また、何かありましたらご指摘よろしくお願いします。