はじめに
RaspberryPi4(ラズパイ)で、温度センサ「TMP102」とI2C通信をする方法を解説します。言語は「Python」ライブラリは「smbus2」を使います。
TMP102は配線・通信が簡単で、初めてI2C通信をする方におすすめのセンサーです。この記事の配線・コードをマネしてもらえれば、初心者でも簡単に温度センサが使えます。
記事では「RaspberryPi4」を使用していますが「RaspberryPi2~4」「RaspberryPi Zeroシリーズ」でも解説と同じように使えます。
~ この記事の内容 / Contents ~
環境
この記事は以下の環境で作成しています。
環境 | バージョンなど | 備考 |
RaspberryPi | Pi4 4GB | RaspberryPi 2/3/4 Zero各種でも使えます |
RaspberryPi OS | bullseye 64bit版 | |
Python | 3.9.2 | OS プリインストールのバージョンです |
ライブラリ | smbus2 |
RaspberryPiとの接続
RaspberryPiとTMP102をI2Cで接続します。
ピン番号 | 内容 | 備考 |
1 | 3V3 power | センサへの電源供給です |
3 | SDA | I2Cの通信線です |
5 | SCL | I2Cの通信線です |
6 | Ground | センサへのグラウンドです。 |
ADDR0でアドレスを安定させる
TMP102には「ADDR0」のピンを電源/GNDにつなぐことで、デバイスのアドレスが変わる仕組みが存在します。アドレスが不安定になる場合は、ADDR0への接続を試してみてください。(上記の回路ではGNDに接続しています)。
ADDR0の接続 | アドレス |
3V3 (OUT) に接続 | 0x49 |
GNDに接続 | 0x48 |
未接続 | 0x49 / 0x48 が不安定に切り替わる場合あり |
ピンアサイン
※ RaspberryPi 公式のGitHubより引用
使用する部品
今回の使用する部品は以下の通りです。
RaspberryPi 4 (8GBモデル)
スイッチやLEDをつなげて使うなら、価格が下がった「RaspberryPi4」がおすすめです。
温度センサTMP102
今回使い方を解説する温度センサです。
ブレッドボード
国内サンハヤト製のブレッドボードです。少々堅めの指し心地ですが、海外製と違ってピン穴の番号がすべて印刷されており、品質も高いのでおすすめです。
ジャンプワイヤ (オス-メス タイプ)
RaspberryPiで使う場合は、以下のオスーメスタイプがおすすめです。
エネループ
使い捨ての乾電池もいいですが、エネループなら4本充電時の電気代が約1円。モーター・ポンプなどの電池が消耗しやすい実験・工作におすすめです。
※ はじめて使う方は充電器とのセットがおすすめです
電池ボックス
電源に使用する乾電池用のボックスとスナップです。記事では単4を使っていますが、容量の大きい単3タイプをお勧めします。単3でも単4でも電圧は変わりません。
プログラム概要
今回のプログラムの概要は以下の通りです。
- I2Cの設定をする
- 温度センサからデータを取得する
- 取得したデータを温度に変換・表示する
実行結果
実行結果は以下の通りです。エアコンの設定値と同程度の室温が表示されました。
esu@raspberrypi:~/src $ sudo python tmp102.py
24.8125
24.875
25.0
24.8125
24.875
24.8125
24.8125
25.25
24.875
24.875
I2Cの設定
I2Cの有効化
RaspberryPiはデフォルトでI2Cの通信が無効化されています。初めてI2C通信を使う方は、こちらの記事を参考に、I2Cを有効化してください。
smbus2のインストール
以下のコマンドで「smbus2」をインストールします。
RaspberryPiでよく使われる「SMBus」は、RaspberryPi OS(bulls eyes) にデフォルトでインストールされていますが、Pythonで使う際の公式のドキュメントの情報量が少なかったので「smbus2」を使用しています。
sudo pip install smbus2
以下のように「Successfully installed …」と表示されればインストールは完了です。
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting smbus2
Downloading https://www.piwheels.org/simple/smbus2/smbus2-0.4.3-py2.py3-none-any.whl (11 kB)
Installing collected packages: smbus2
Successfully installed smbus2-0.4.3
全体コード
全体コードは以下の通りです。詳細な内容は後述する「コードのポイント」で解説します。
import time
from smbus2 import SMBus
# バス番号を指定します(基本的に1でOKです)
busNum = 1
smbus2 = SMBus(busNum)
# I2Cのアドレスを指定します
# TMP102の場合は「0x48」です
addr = 0x48
# 温度情報を1秒おきに100回取得します
for i in range(100):
# TMP102の温度情報(12bit)は2byteに分かれて送られるため
# 2byte分Readします
data = []
data = smbus2.read_i2c_block_data(addr,0,2)
# 温度データは「1」で、0.0625度を表すため、温度データに「0.0625」を
# 掛け算することで、実際の”温度”に変換できます。
tmp = 0
tmp = data[0] << 4
tmp += data >> 4
# 温度情報を表示します
print(tmp * 0.0625)
# 1秒待機します
time.sleep(1)
コードのポイント
バス番号の指定
I2C通信に使うバス番号を指定します。前述したピンに接続している場合は「1」を指定します。
# バス番号を指定します(基本的に1でOKです)
busNum = 1
smbus2 = SMBus(busNum)
read_i2c_data_block関数でセンサからデータを取得する
read_i2c_block_data関数で温度データを取得します。
# TMP102の温度情報(12bit)は2byteに分かれて送られるため
# 2byte分Readします
data = []
data = smbus2.read_i2c_block_data(addr,0,2)
引数の項目とコード上の指定は以下の通りです。
TMP102からは温度データが2byte送られるので、2byte分のデータを取得します。取得したデータは戻り値として、配列で返されます。
引数 | 内容 | コード上の指定 |
1 | デバイスのアドレス | 0x48 |
2 | 開始するレジスタのアドレス | 0 |
3 | 取得したいデータ数 | |
戻り値 | 指定したデータ数分の受信データ | data[] |
2つの受信データをシフトして結合する
TMP102は温度データを2byte(16bit)に分けて送信し、そのうち「12bit」しか使用しません。そのため、以下のようにビットシフトとデータの結合を行って、受信データから温度データを作成します。ビットシフトの内容はイメージと合わせて後述します。
# 受信データの 1つ目は8bit全て、2つ目は下位4bitを使用します
# そのため、2つのデータをビットシフトして結合します。
tmp = data[0] << 4
tmp += data >> 4
# 温度データは「1」で、0.0625度を表すため、温度データに「0.0625」を
# 掛け算することで、実際の”温度”に変換できます。
print(tmp * 0.0625)
① 1つ目のデータ(data[0])を、左に4ビットシフトする
1つ目のデータの「8~1のビット」に、温度データの「12~5ビット」のデータが格納されています。
そのままではビットの番号が合わないので、ビットを左にシフトして温度データのビットの番号に合わせます。シフトした結果は、tmpという変数に代入します。
② 2つ目のデータ (data[ 1])を右に4ビットシフトする
2つめのデータの「8~5ビット」に、温度データの「4~1ビット」のデータが格納されています。
こちらもビット番号が合わないので、ビットを右にシフトして温度データのビットの番号に合わせます(右にあふれたデータは削除、左側には0が追加されます)。
シフトすると、tmpの空いている部分にピッタリと合うようになるので、2つ目のデータをtmpに結合(足し算)します。
上記の変換を行うことで、「tmp」に、TMP102の温度データ(12bit)の値をセットすることができます。
温度データから実際の温度へ変換する
TMP102からの温度データは、1単位につき「0.0625度」となっています。そのためtmpの内容に0.0625を掛け算すると、実際の温度の数値になります。
上のイメージの、tmp(0001 1010 0000)を十進数にすると「416」になります。
416 × 0.0625の掛け算すると「26度」になります。
まとめ
Raspberry Pi Picoで、Pythonを使ってI2C通信を行う方法について解説しました。参考になればうれしいです。
RaspberryPiで「アナログ入力」を使う方法
このブログでは、RaspberryPiで「A/D変換」を行う方法についても解説しています。A/D変換を使うとRaspberryPiで「Arduino」や「RaspberryPi Pico」のような「アナログ入力」を扱えるようになります。興味のある方は、以下の記事も併せてご覧ください。
おすすめの最新書籍
今月号の日経Interfaceは「Linuxチューニング術50」
今月号のInterfaceは『Linux チューニング術 50』です。
Linuxを組み込んだ機器を”本格的”に作ろうとすると「起動を早くしたい」「いきなり電源を切られてもデータを守りたい」など、対応が必要なチューニングはおおいですよね。
今回の記事は、「カーネルをいじらない」方法でチューニングを行う方法が解説されています。
こういった”実用的”な特集はレアですし、知っておいても損はない情報だと思います。
私も仕事でこの手の問題に何度も遭遇していますが、こういったOSレベルの難しそうな設定を、さらっとできちゃう人はかっこいいですよね。
興味のある方は、以下のリンクから確認できます。
質問・要望 大歓迎です
「こんな解説記事作って」「こんなことがしたいけど、〇〇で困ってる」など、コメント欄で教えてください。 質問・要望に、中の人ができる限り対応します。
使えたよ・設定できたよの一言コメントも大歓迎。気軽に足跡を残してみてください。記事を紹介したい方はブログ、SNSにバシバシ貼ってもらってOKです。