Raspberry Piで温度センサー(DS18B20)から温度を取得する方法
2016-05-07
大変大変!
「Raspberry Piで学ぶ電子工作 超小型コンピュータで電子回路を制御する」という本(Kindle本が便利!)でRaspberry Pi 3を勉強してたら、7章で「I2C接続するデバイスの例:温度センサ ADT7410」という箇所が出てきたんですよ。
ところが私が購入したキットでは、1-wireデバイスでピンが3本しかない温度センサー「DS18B20」で、全然違うものが入ってたんですよ…!
初心者になんという仕打ち…!
それでもなんとか繋いでみる
まあ、入っていたものは仕方がありません。 I2Cから急遽1-wireの勉強をし(以前「Raspberry Piで遊ぼう!」という本を購入しており、こちらに1-wireデバイスの説明があったので)、繋いでみることにします。
デバイスから煙が!
入っていたDS18B20は、繋ぎやすいようにモジュール型になっていたのですが、デバイスの線の順番がそのままピンの順番に対応しているのだろうと勘違いして「-」のピンに3.3Vの電源を繋いでしまいました。
すると、しばらくして臭い匂いと共にデバイスからモヤーっと煙が…やばい、間違えた…。
調べてみると、以下のように「-」が「GND」、真ん中のピンが電源の「VDD」、「S」のところがデータ「DQ」の線にしないといけなかったようです。
Raspberry Pi &ブレッドボード回路作成
再び繋ぎ直し、今度はRaspberry Pi側の回路作成です。
こちらはDQピンをGPIO4に、VDDピンを3.3V、GNDピンをGNDへ接続しました。
で、DQピンとVDDピンの間を10KΩの抵抗でプルアップします。
これで物理的にはOK。
Raspbianに1-wireデバイスを認識させる
1-wireデバイスをRaspbianに認識させるには、I2Cとは別の設定が必要です。
1./boot/config.txtの編集
まず、/boot/config.txt に以下の記述を追加します。
dtoverlay=w1-gpio-pullup,gpiopin=4
2.カーネルモジュールのロード
1-wire用の以下のカーネルモジュールをロードします。
$ sudo modprobe w1-gpio
$ sudo modprobe w1-therm
ここで一度再起動します。
$ sudo reboot
確認
モジュールが読み込まれているかを「lsmod」コマンドで確認します。
$ lsmod | grep w1
w1_therm 3396 0
w1_gpio 3401 0
wire 24703 2 w1_gpio,w1_therm
で、1-wireデバイスはすでに繋がれてますからここでデータが取得できちゃいます。
まず、以下のパスにある「w1_slave」の内容を出力してみると…
$ cat /sys/bus/w1/devices/28-(ここでタブキーで補完する)/w1_slave ab 01 4b 46 7f ff 0c 10 20 : crc=20 YES ab 01 4b 46 7f ff 0c 10 20 t=26687
上の「t=26687」を1,000で割ると「26.687」という摂氏温度(℃)が分かります。
温度取得のPythonプログラムを作成
最後に、Pythonプログラムの作成です。
これはAdafruit’s Raspberry Pi Lesson 11. DS18B20 Temperature SensingというPDFファイルの中にサンプルプログラムがありました。
それを元に「Raspberry Piで学ぶ電子工作 超小型コンピュータで電子回路を制御する」に沿うように改変します。
※PDFにあるサンプルプログラムの関数(read_temp())は華氏(F)も一緒に返却するようですが、ここでは必要ないので削除しました。
温度取得(出力)プログラムコード
1-wireデバイスからデータを取得するプログラムの実態は、定期的に「w1_slave」ファイルの中身をファイル関数で読み取るだけなので「RPi.GPIO」ライブラリを使わなくても出来るようになっています。
import os
import glob
from time import sleep
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
# 生の温度データを取得する関数
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
# 温度データのみを取り出して返す関数
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos + 2:]
temp_c = float(temp_string) / 1000.0
return temp_c
try:
while True:
print(read_temp())
sleep(1)
except KeyboardInterrupt:
pass
プログラム実行
これを適当なファイル名で保存し、IDLEで実行するとコンソールに温度が出力されます。
お役に立ちましたでしょうか?
まだまだ勉強中なのでおかしなところもあるかもしれませんが、ご指摘いただければ幸いです。では!
2016-05-07
12 件のコメント
とても分かりやすい情報ありがとうございます。参考にさせて頂きました。
fritzingの配線図でDS18B20の向きが反対のように思われますがいかがでしょうか?
コメントありがとうございます。
DS18B20ですが、モジュールの配線をよく見ると途中でクロスしてまして、写真の接続状態と逆になっています。
ですので、fritzingの配線図は厳密には図の通りになりますね。
fritzingではモジュールの配線が図にできなかったので誤解を招きやすい内容になってしまって申し訳ありません。
質問失礼します。
$ cat /sys/bus/w1/devices/28-(ここでタブキーで補完する)/w1_slave
ab 01 4b 46 7f ff 0c 10 20 : crc=20 YES
ab 01 4b 46 7f ff 0c 10 20 t=26687
とありますが、タブキーで補完できない場合はどうしたらよいでしょうか?
コメントありがとうございます!
/devices/
のところまで入力した状態でTabキーを2回押すとディレクトリのリストが出てくると思いますので、その中から正しいそうなものを直接入力してみてください。
お返事ありがとうございます!
早速タブキーで打ち込んでみたのですが、
そのようなファイルやディレクトリはありませんと表示されてしまいます、、、。
おかしいですね。
/sys/bus/w1/devices/
まで入力した状態でタブキーを2回押すのですがダメでしょうか?参考にさせていただいております。
プログラムコード中に
os.system(‘modprobe w1-gpio’)
が2行ありますが、片方は
os.system(‘modprobe w1-therm’)
ということでよろしかったでしょうか。
tokumei さま、ご指摘ありがとうございます!
確かに間違いですね。先程修正させていただきました。
突然すいません
プログラムを利用させてもたっています。
温度センサーを複数つないだ時のプログラムはどうなりますか
3週間ぐらいいろいろしらべたのですが、プログラムの経験がないので苦戦して連絡させてもらいました。
mochidukiさま
ちょっとそのあたりの応用的な部分については分かりかねます。。
申し訳ございません。
複数繋げると複数のリストが出てきますよ。
個々のセンサーがIDを持っているので個別に確認してください。