複数のDS18B20防水センサーで温度測定-農家のIoT入門(8)
前回の記事で、RaspberryPi と Pythonで使う防水センサーを選びました。
今回は、実際に回路を組んで・プログラミングをして、地温を測定してみましょう。
DS18B20を1個接続する場合の回路
まず、購入した防水温度センサー、DS18B20をブレッドボードで使いやすくするよう、ジャンパワイヤーをハンダ付けしました。
センサー1個につき、電源・GND・信号で3本ずつ線が出ています。
防水加工したDS18B20は様々なお店で売っているので、それぞれ多少の差異がありますが、上記のやつは線がすでに剥いてあり、しかもハンダで固めてあるので、そのままでもブレッドボードにさせます。
ただ、抜けやすいし使いにくいので、ジャンパワイヤーを取り付けた方がいいでしょう。
はんだ付けしたところは、熱収縮チューブで保護しておきます。
ドライヤーとかで温めると縮まるチューブです。
続いて、ブレッドボードで配線します。
DS18B20の配線は簡単で、信号線と電源をプルアップ抵抗で繋いで、信号線はGPIOの入力に繋げればOKです。
赤線が5V電源。青線がGND。白線がGPIO4と、それぞれRaspberryPiのピンに繋がっています。
(3.3Vでも動きますが、ケーブルが長くなる場合などは5Vの方が安定するようです)
プルアップ抵抗は、DS18B20公式では4.7kΩを繋ぐと指定されていましたが、安定させる為だけだと思うので、多少違っても問題は無いと思います。(手元にあった5.1kΩを繋ぎました)
プルダウン抵抗・プルアップ抵抗を理解する-農家のIoT入門(3)
GPIOピンが4番なのは、公式のモジュールで指定されているピンだからです。
RaspberryPi側の設定
RaspberryPi側でも設定がいくつか必要です。
DS18B20を使うための設定として、まず1-Wireを有効にします。
3線使う場合でも、この設定は必須です。
この画面を出すには、RaspberryPiの「メニュー」 > 「設定」> 「Raspberry Pi」の設定 > 「インターフェイス」のタブ・・と選んでいけば、上の設定画面に入れます。
ここで、1-Wireの有効にチェック入れればOKです!
この設定をすると、 /boot/config.txt が編集されます。
続いて、この /boot/config.txt に1行追加します。
(ポートの電圧を上げないと測定がうまくいかないようです))
dtoverlay=w1-gpio,pullup=on
vimが入っているなら、Terminalで次のコマンドを打てば編集できます。
$ sudo vim /boot/config.txt
なお、お恥ずかしながら初学者の私はここで結構詰まりました。
・vimって何?
・vimのインストールがうまくいかない
・vimの編集方法がわからない
このあたりで詰まった人は、一個ずつ勉強していくしかないかな?・・という感じです。
なお、pullup=onの設定も、vimで編集可能です。
DS18B20を1個接続する場合のプログラミング
最後に、Python3でプログラミングします。
いつものように、他のブログも大いに参考させて頂きながらですが、こんな感じです。
- 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(3)
- except KeyboardInterrupt:
- pass
簡単に解説すると。
5・6行目:
DS18B20を使う為に追加するカーネルモジュール
8~10行目:
ここまでの設定が正しく出来ていると、/sys/bus/w1/devices/ 内に、28-から始まる15桁のフォルダが新しく作られています。
これが、センサー1個1個のシリアル番号のような物で、センサー毎に異なります。
このコードだと、9行目で28から始まるフォルダを探すよう指示しています。
1個しかセンサーを繋がないなら、これで対応可能です。
そして、このフォルダ内にw1_slave というファイルがあり、ここに測定したデータが格納されます。
12~16行目:
w1_slave に格納されたデータを取得しています。
18~27行目:
取得したデータから、温度データのみ取り出しています。
29~32行目:
取得した温度を3秒毎に表示します。
コードを走らせると、このように温度が表示されました。
途中からセンサーを指で温めてみましたが、ちゃんと温度上昇していますね。成功です。
(温度が正しいかは、またいずれ検証します。)
DS18B20を複数個接続する場合の回路
このセンサーを選んだ理由のひとつが、複数個接続しやすい事です。
10個程度なら、並列に繋げばいいだけです。
という事で、まずは2個繋いでみましょう。
上の図と同じように、ブレッドボード上で接続します。
ちょっとゴチャゴチャしてわかりにくいですが、右側にセンサー2個分の配線をしています。
プルアップ抵抗は、左側で1個だけで良いので楽ですね。
DS18B20を複数個接続する場合のプログラミング
最後に、センサー2個接続でのプログラミングです。
接続してあるセンサーの数だけ、先程の28-から始まるフォルダが増えます。
そして、それぞれのw1_slave ファイルにデータが書き込まれていくので、センサーごとの温度が簡単に取得できる仕組みです。
ですので、プログラムもそれぞれの w1_slave を読み込むように変更するだけ・・・なのですが、ここは大いに悩みました。
というのも、回りくどい書き方をすれば簡単なんですけど、シンプルに書きたかったので。
・・でもエラーばかりで解決しなかったので、回りくどい方を載せておきます。
(そのうち上達したら修正します)
- import os
- import glob
- from time import sleep
- os.system('modprobe w1-gpio')
- os.system('modprobe w1-therm')
- device_file1 = '/sys/bus/w1/devices/28-3c01b607d2db/w1_slave'
- device_file2 = '/sys/bus/w1/devices/28-3c01b6073639/w1_slave'
- def read_temp_raw1():
- f = open(device_file1, 'r')
- lines1 = f.readlines()
- f.close()
- return lines1
- def read_temp_raw2():
- f = open(device_file2, 'r')
- lines2 = f.readlines()
- f.close()
- return lines2
- def read_temp1():
- lines1 = read_temp_raw1()
- while lines1[0].strip()[-3:] != 'YES':
- sleep(0.2)
- lines1 = read_temp_raw1()
- equals_pos = lines1[1].find('t=')
- if equals_pos != -1:
- temp_string1 = lines1[1][equals_pos + 2:]
- temp_c1 = float(temp_string1) / 1000.0
- return temp_c1
-
- def read_temp2():
- lines2 = read_temp_raw2()
- while lines2[0].strip()[-3:] != 'YES':
- sleep(0.2)
- lines2 = read_temp_raw2()
- equals_pos = lines2[1].find('t=')
- if equals_pos != -1:
- temp_string2 = lines2[1][equals_pos + 2:]
- temp_c2 = float(temp_string2) / 1000.0
- return temp_c2
- try:
- while True:
- print("t1=" + str(read_temp1()))
- print("t2=" + str(read_temp2()))
- sleep(3)
- except KeyboardInterrupt:
- pass
8~9行目:
センサーが2つになったので、それぞれのシリアル番号になるフォルダ名を直接指定。
11~43行目:
センサーごと、温度を取得。
()内の変数を変える事で取得したかったけど、エラーが消せないから1個ずつ取得しています。
センサーの数が増えると面倒なので、なんとかしたい。
47~48行目:
それぞれの温度をプリント。
どっちかわかるよう、t1とt2で表示をわけることに。
同じところに置いたセンサーなのに、若干温度に差がありますね。
個体差でしょうか。校正が必要かも・・・
でも、ちゃんと取得出来ているので、ひとまずクリアです!
次回は、これを以前やったようにGoogleスプレッドシートに送って、クラウド上で見られるようにしてみます。