Raspberry Pi PR

RaspberryPi(ラズパイ)でI2C通信をする方法【smbus2】

記事内に商品プロモーションを含む場合があります

はじめに

RaspberryPi4(ラズパイ)で、温度センサ「TMP102」とI2C通信をする方法を解説します。言語は「Python」ライブラリは「smbus2」を使います。

TMP102は配線・通信が簡単で、初めてI2C通信をする方におすすめのセンサーです。この記事の配線・コードをマネしてもらえれば、初心者でも簡単に温度センサが使えます。

記事では「RaspberryPi4」を使用していますが「RaspberryPi2~4」「RaspberryPi Zeroシリーズ」でも解説と同じように使えます。

環境

この記事は以下の環境で作成しています。

環境 バージョンなど 備考
RaspberryPi Pi4 4GB RaspberryPi 2/3/4  Zero各種でも使えます
RaspberryPi OS bullseye 64bit版
Python 3.9.2 OS プリインストールのバージョンです
ライブラリ smbus2

RaspberryPiとの接続

RaspberryPiとTMP102をI2Cで接続します。

RaspberryPi4とTMP102を実際に接続した画像
全体の配線
TMP102側の配線を解説する画像
TMP102側
RaspberryPi4側の配線を解説する画像
RaspberryPi側
全体の配線イメージを解説するイラスト画像
配線イメージ
ピン番号 内容 備考
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です。

ABOUT ME
えす
現役のソフトウェアエンジニアです。 C++ C# Python を使ってます。10年ちょい設計/開発部門にいましたが、今はQAエンジニアっぽいことをしています。

COMMENT

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

Index