Raspberry Piで温度センサー(DS18B20)から温度を取得する方法

DS18B20_title

大変大変!

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」の線にしないといけなかったようです。

DS18B20_module

Raspberry Pi &ブレッドボード回路作成

再び繋ぎ直し、今度はRaspberry Pi側の回路作成です。

こちらはDQピンをGPIO4に、VDDピンを3.3V、GNDピンをGNDへ接続しました。
で、DQピンとVDDピンの間を10KΩの抵抗でプルアップします。

201605071015534

これで物理的にはOK。

Raspbianに1-wireデバイスを認識させる

1-wireデバイスをRaspbianに認識させるには、I2Cとは別の設定が必要です。

1./boot/config.txtの編集

まず、/boot/config.txt に以下の記述を追加します。

dtoverlay=w1-gpio-pullup,gpiopin=4
 初心者の疑問
本で学習していると、Raspberry Piには内部にプルダウン/プルアップ抵抗が内蔵されていてプログラムから設定できると書いてありますが、1-wireデバイスについてはGPIO.setup()でコントロールするものではないようなので(後述)、ここでGPIO4の内部プルアップを有効にしておくのですね。あれ?でもさっき物理的にプルアップ抵抗を取り付けましたよね?これは必要なのでしょうか?

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-gpio')

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で実行するとコンソールに温度が出力されます。

20160507131606

お役に立ちましたでしょうか?
まだまだ勉強中なのでおかしなところもあるかもしれませんが、ご指摘いただければ幸いです。では!

2 件のコメント

  • 匿名希望 より:

    とても分かりやすい情報ありがとうございます。参考にさせて頂きました。
    fritzingの配線図でDS18B20の向きが反対のように思われますがいかがでしょうか?

    • コメントありがとうございます。
      DS18B20ですが、モジュールの配線をよく見ると途中でクロスしてまして、写真の接続状態と逆になっています。
      ですので、fritzingの配線図は厳密には図の通りになりますね。
      fritzingではモジュールの配線が図にできなかったので誤解を招きやすい内容になってしまって申し訳ありません。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

2016-05-07