
皆さんこんにちは!メカ旦那です。
先日I2Cの概要について解説しましたが、実際に使ってみた方がイメージしやすいと思います。ラズパイをマスターとして色んなデバイスと通信してみたので解説します。ラズパイ⇔デバイス(LCD)間と、ラズパイ⇔マイコン(Arduino)間の2種類に分けて紹介します。
I2Cについて基礎から理解したい方はまず下記をご覧ください。
Arduino間のI2Cも試してみたので、気になる方はご覧ください。
ラズパイのI2Cについて
ラズパイでI2Cを使うにあたり事前に理解しておくべき事について解説します。
I2Cピン

I2CにはSDA、SCL、GNDの3つが必要になります。ラズパイはGPIO2がSDA、GPIO3がSCLになります。GNDは8つあり任意のピンで結構です。ちなみにラズパイピコは該当ピンが全く異なるのでご注意ください。
プルアップ抵抗
別記事で解説しましたが、I2C出力はオープンドレインになるため、別途プルアップ抵抗が必要になります。ただしラズパイの場合、GPIO2,3の内部で約1.8kΩのプルアップ抵抗が3.3Vに接続されています。つまり最初からプルアップされている為、新たに抵抗を外付けする必要はありません。むしろ外付けすると、合成抵抗値が下がりプルアップが効きにくくなるため避けた方が良いです。
I2Cの有効化

ラズパイでI2Cを利用するには予め設定が必要になります。画像の通り、ラズパイ起動後、左上ロゴより「①設定」を選択し、「②Raspberry Piの設定」を押下します。その後、インターフェースタブを開き、「③I2C 有効」をクリックします。
スレーブアドレスの特定

別記事でも解説しましたが、I2C通信にはスレーブアドレスが必要です。アドレスは固有で決まっている場合と、プログラムで設定できる場合とあります。固有の場合、取扱説明書やデータシートに記載している事もありますが、ラズパイからコマンド送信する事で把握する事ができます。
まずラズパイとデバイスでI2Cの配線を行います。今回は後述するLCDを繋いでみました。その後、ラズパイでターミナル(画像①)を開き、コマンド「i2cdetect -y 1」を送信します(画像②)。すると今I2C接続されているデバイスのアドレス一覧が表示されます。今回はLCDのスレーブアドレス「27」が表示されます。
ちなみに配線が誤っている場合何も表示されません。今後通信が上手くいかない時は、こちらのi2cdetectをお試しの上、正しく配線されているかどうかをご確認ください。
ラズパイ ⇔ デバイス(LCD)間でI2C
ラズパイのI2Cについて説明が終わりましたので、早速事例紹介に行きたいと思います。まずはラズパイ⇔デバイス(LCD)間通信についてです。
動画
こんなイメージで文字表示させています。
使用部品
※私は手元にあったラズパイ3Bを使いましたが、上記最新モデルでも問題なく使用できます。
※上記LCDにはI2C用端子が付いていますが、私の使用品にはパラレルデータ用端子しか付いていなかったため、I2C⇔パラレルを変換する下記モジュールを使用しています。
回路

回路はこちらで、ポイントは以下になります。
プログラム
# -*- coding: utf-8 -*-
from RPLCD.i2c import CharLCD
import time
# LCDのI2Cアドレス(多くのLCDは0x27または0x3F)
lcd = CharLCD('PCF8574', 0x27)
# LCD初期化
lcd.clear()
# 1行目にメッセージ表示
lcd.write_string("Hello, World!")
time.sleep(2)
# 2行目にメッセージ表示
lcd.cursor_pos = (1, 0) # 行, 列 = 2行目先頭
lcd.write_string("Raspberry Pi 3B")
# しばらく表示して終了
time.sleep(10)
lcd.clear()
こちらがラズパイに書き込むプログラムになります。ポイントは以下です。
ラズパイ ⇔ マイコン(Arduino)間でI2C
続いて、ラズパイ⇔マイコン間のI2C通信について解説します。
マイコンはArduino Leonardを使いました。
動画
イメージはこんな感じです。
ラズパイで数値を入力後、ArduinoへI2C信号が送られ、Arduino側でPWMを用いてLEDの明るさを変えています。
PWMって何、、、という方は過去に解説していますのでこちらをご覧ください!
使用部品
※私は手元にあったラズパイ3A+を使いましたが、上記最新モデルでも問題なく使用できます。
Arduino Leonardは有名なArduino Unoとピン配置が異なりますが、能力的に問題なく安価なので、電子工作など簡易的な利用でしたらオススメです!
回路

回路はこちらで、ポイントは以下になります。
プログラム マスター(ラズパイ)側
#ライブラリのインポート
import smbus #ラズパイのI2C用ライブラリ
import sys
#I2Cの設定
I2C_BUS = 1 # ラズパイのI2Cバス番号
ARDUINO_ADDR = 0x09 # ArduinoのI2Cスレーブアドレス
bus = smbus.SMBus(I2C_BUS)
#無限ループ
while True:
try:
#シェルに数値入力をさせる
user_input = input("Enter a number (0-255) or 'q' to quit : ").strip()
#「q」が入力されたら処理を終了させる
if user_input.lower() == 'q':
print("Exiting.")
break
#数値以外が入力されたら警告を表示
if not user_input.isdigit():
print("Please enter a valid number.")
continue
#0未満もしくは255より大きい数字が入力されたら警告を表示
value = int(user_input)
if value < 0 or value > 255:
print("Number must be between 0 and 255.")
continue
#0~255の数値が入力されたらArduinoへ送信
bus.write_byte(ARDUINO_ADDR, value)
print(f'Sent "{value}" to Arduino')
#ctrl + c が入力されたら処理を終了させる
except KeyboardInterrupt:
print("\nInterrupted by user. Exiting.")
sys.exit()
#エラーが出たらシェルに表示させる
except Exception as e:
print(f"Error: {e}")
プログラムについては、マスター・スレーブそれぞれに書き込む必要があります。まずはマスター(ラズパイ)側のポイントです。
プログラム スレーブ(Arduino)側
//ライブラリインポート
#include <Wire.h> //Arduino向けI2Cライブラリ「Wire.h」をインポート
//初期設定
volatile byte receiveData; //LEDに出力する変数receiveDataを宣言
void setup() {
Wire.begin(9); //Arduinoにスレーブアドレス9を設定
Wire.onReceive(turnOnLED); //マスターからのデータ受信時に関数「turnOnLED」を呼び出す
pinMode(5, OUTPUT); //LEDが接続されている5ピンを出力に設定
}
//呼び出し関数
void turnOnLED(int Number) {
if (Wire.available())
receiveData = Wire.read(); //マスターから受信した数値を変数receiveDataに格納
}
//メイン処理
void loop() {
analogWrite(5, receiveData); //LEDピンに変数receiveDataを出力。つまりPWMでLEDの明るさを制御。
}
続いてスレーブ(Arduino)側のコードです。ポイントは以下です。
まとめ
いかがでしたでしょうか。
I2Cと聞くと一見難しそうに聞こえますが、ライブラリを使う事で手軽に利用できる事がお分かりになったかと思います。
ただし、プルアップ抵抗が必要、長距離配線・接触不良に弱い等、I2Cにも弱点は存在します。もし通信が上手くいかない場合、こちらもぜひご参考にしてみてください。
今回はラズパイ⇔Arduino間のI2C通信を紹介しましたが、Arduino間でも試してみたので、気になる方はご覧ください!
コメント