ラズベリーパイで遊ぶ(23)-DHT11温度および湿度センサーの練習
I.はじめに
DHT11は、周囲の温度と湿度の測定をサポートする強力な複合センサーです。それ自体は比較的単純ですが、データの読み取りと書き込みにシリアルタイミングを使用するため、タイミングプログラミングの練習に非常に適しています。この実験で使用したセンサーモジュールを下図に示します。
このセンサーモジュールには、電源ピンと接地ピンに加えて3つのピンがあり、データの出力と制御コマンドの送信に使用される出力ピンは1つだけであることがわかります。このセンサーモジュールの使い方を紹介します。
2.DHT11センサーモジュールについて
DHT11センサーエレメントには通信ピンが1つしかないため、入力と出力の両方で同じピンを使用する必要があります。つまり、このピンはシリアル単線双方向ピンです。いわゆるシングルライン双方向とは、信号伝送ラインが1つしかないが、双方向で通信できることを意味します。これは、私たちが使用するトランシーバーに少し似ています。一方の側は、一方の側が話すときにのみ聞くことができます。DHT11の完全なユーザーマニュアルアドレスは次のとおりです。
https://www.dfrobot.com.cn/image/data/DFR0067/DFR0067_DS_10.pdf
まず、DHT11が送信する情報データのフォーマットを見てみましょう。文書によると、DHT11の完全な通信は、温度、湿度、および正確性検証のためのデータを含む40ビットのデータを送信します。したがって、DHT11のデータを読み取る場合、計算する前に40ビットのデータを完全に読み取る必要があります。40ビットデータの特定の形式は次のとおりです。
[8ビット湿度整数部データ]+[8ビット湿度小数部データ]+[8ビット温度整数部データ]+[8ビット温度小数部データ]+8ビットチェックデータ
[8ビット湿度整数部データ]と[8ビット湿度小数部データ]と[8ビット温度整数部データ]と[8ビット温度小数部データ]の合計は、結果がそうでない場合など、8ビットチェックデータである必要があります。今回取得したデータは異常であるため、破棄して再度取得する必要があります。
センサー自体から取得するデータ形式は比較的単純であり、より複雑な点はその通信プロセスにあります。全体として、RaspberryPiとDHT11センサー間の通信プロセスは3つの段階に分かれています。
1. Raspberry Piは開始信号を送信し、センサーモジュールからの応答の待機を開始します。
2.センサーモジュールはRaspberryPiから開始信号を受信した後、応答信号を返します。
3. Raspberry Piが応答信号を受信した後、40ビットデータの受信を開始します。
概略図は、次のように、全体的なコミュニケーションプロセスマニュアルに記載されています。
電源投入後、センサーモジュールのバスは常にアイドル状態または通信状態のいずれかになります。アイドル時のバス入力ハイレベルを定義します。上記の通信プロセスの最初の段階では、Raspberry Piが最初にバスレベルをローにプルします。センサーモジュールがこのプルされたロー信号を検出するには、18ミリ秒より長くする必要があります。その後、Raspberry Piがバスを再びハイに引き上げ、Raspberry Piが通信開始信号を送信したことを示し、最初のステージが終了します。
センサーモジュールがRaspberryPiによって開始された開始信号を検出した後、この時点でバスレベルがRaspberryPiによってハイに引き上げられます。センサーモジュールは、バスを介して80マイクロ秒の低レベル信号を送信し、Raspberry Piの開始信号に応答することを示します。その後、センサーモジュールはバスレベルをさらに80マイクロ秒引き上げ、Raspberryを示します。 Piはデータの受信を開始する準備ができており、フェーズ2は終了します。
フェーズ1とフェーズ2のより詳細な概略図は次のとおりです。
ステージ3は、センサーモジュールがデータを送信し、RaspberryPiがデータを受信するステージです。データの各ビットは、0と1の2つの状態で送信されます。センサーが50マイクロ秒の低レベル信号を送信するたびに、1ビットデータが送信されることを意味します。その後、センサーが26マイクロ秒の高レベルを送信する場合〜28マイクロ秒、データビット0が送信されることを意味し、70マイクロ秒のハイレベルが送信される場合、データビット1が送信されることを意味します。その後、データの次のビットが送信されます。実際のプログラミング動作では、ハイレベル時間を正確に測定できない場合がありますが、データビット0とデータビット1のハイレベル時間は大きく異なるため、ループ数をテストすることで大まかに送信できます。変数データが0のときのおおよそのサイクル数とデータ1が送信されるときのおおよそのサイクル数。サイクル数は、データが0か1かを決定するために使用されます。
データビット0の信号図は次のとおりです。
データビット1の信号図は次のとおりです。
各測定間の時間間隔は好ましくは1秒より長く、電源投入後、1秒待ってから測定することに留意されたい。
コンポーネントのシングルバスタイミングプログラミングに触れたことがない場合でも、上記のテキストの説明は一般的に多少抽象的であり、以下のコードを使用して練習します。
3.接続コーディング
DHT11センサーモジュールには3つのピンしかありません。RaspberryPiの任意のGPIOピンを選択して、中央の出力ピンを接続できます。ここでは、物理コードが11のGPIOピンを選択します。上記で紹介したDHT11モジュールの使用方法に従って、次のようにコードを記述します。
#coding:utf-8
import RPi.GPIO as GPIO
import time
import math
# 使用物理编码为11的引脚做总线
P = 11
GPIO.setmode(GPIO.BOARD)
print("开始进行DHT11测量数据获取\n")
# 等待1s后再进行逻辑
time.sleep(1)
def readData():
print("readData")
# 先将总线引脚设置为输出模式
GPIO.setup(P, GPIO.OUT)
# 将总线电平拉低,发出开始信号
GPIO.output(P, GPIO.LOW)
# 手册要求至少保持18ms的低电平,我们这里保持20ms
time.sleep(0.02)
# 拉高电平
GPIO.output(P, GPIO.HIGH)
# 之后将引脚设为输入模式,等待传感器响应
GPIO.setup(P, GPIO.IN)
# 先等待80us的低电平信号
while GPIO.input(P) == GPIO.LOW:
continue
# 再等待80us的高电平信号
while GPIO.input(P) == GPIO.HIGH:
continue
# 开始接收数据
# 循环计数
i = 0
# 存放二进制位数据
data = []
# 存放中间数据
kdata = []
# 每次读取40位数据
while i < 40:
j = 0
# 50us的低电平表示准备传输一位数据
while GPIO.input(P) == GPIO.LOW:
continue
# 开始检测高电平的时间
while GPIO.input(P) == GPIO.HIGH:
j+=1
if j > 100:
return [False, 0, 0]
kdata.append(j)
i+=1
print("--------临时数据----------\n")
print(kdata)
print("--------临时数据----------\n")
# 开始整理数据
i = 0
while i < 40:
tmp = kdata[i]
if tmp > 7:
data.append(1)
else:
data.append(0)
i+=1
print("--------临时数据2----------\n")
print(data)
print("--------临时数据2----------\n")
# 解析湿度整数部分
t1 = data[0:8]
c1 = 0
i = 7
for n in t1:
c1 += n * math.pow(2, i)
i-=1
# 解析湿度整数部分
t2 = data[8:16]
c2 = 0
i = 7
for n in t2:
c2 += n * math.pow(2, i)
i-=1
# 解析温度整数部分
t3 = data[16:24]
c3 = 0
i = 7
for n in t3:
c3 += n * math.pow(2, i)
i-=1
# 解析温度整数部分
t4 = data[24:32]
c4 = 0
i = 7
for n in t4:
c4 += n * math.pow(2, i)
i-=1
# 解析校验
t5 = data[32:40]
c5 = 0
i = 7
for n in t5:
c5 += n * math.pow(2, i)
i-=1
# 进行校验
va = True
print("c1:%d\n2c:%d\n3c:%d\n4c:%d\n5:%d\n"%(c1,c2,c3,c4,c5))
if c1 + c2 + c3 +c4 == c5:
va = True
else:
va = False
return [va, "%d.%d"%(c1, c2), "%d.%d"%(c3, c4)]
while True:
time.sleep(1)
result = readData()
if result[0]:
hum = result[1]
temp = result[2]
print("当前环境湿度: %s %%, 当前环境温度:%s℃\n" % (hum, temp))
else:
print("此次数据无效,已被丢弃\n")
time.sleep(1)
上記のコードにはより詳細なコメントがありますが、それでもいくつかの場所を説明できます。まず、Raspberry Piからstartコマンドを発行するプロセスは比較的単純であり、多くの説明は必要ありません。問題は、40ビットのバイナリデータを取得するために40回ループすることです。データを取得するときは、ループ変数を使用して高レベルの時間比率を記録し、送信されたデータが0か1かを分析できるようにします。異なるデバイスが同時に循環しない場合があることに注意してください。最初に、上記のコードのkdata変数に格納されているデータをテストできます。実行中のコードは次のとおりです。
送信データが0の場合、ループ数は基本的に3または4であることがわかります。また、データ1が送信される場合、ループカウントは約11です。コードでは、7で除算します。分析中に、ループカウントが7より大きい場合、現在の送信データは1であると見なされ、それ以外の場合は0です。
完全な40ビットのバイナリデータを取得したら、検証のために数値に変換します。最終的なコード実行効果を次の図に示します。
テクノロジーに焦点を合わせ、愛を理解し、喜んで共有し、友達になりましょう
QQ:316045346