PR
スポンサーリンク

【初心者】I2Cとは?ラズパイ、LCDを使って試してみた

皆さんこんにちは!メカ旦那です。

先日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⇔パラレルを変換する下記モジュールを使用しています。

回路

回路はこちらで、ポイントは以下になります。

  • ラズパイの信号電圧は3.3Vですが、変換モジュールは5Vの為、直結では通信できません。そこで「4ch双方向ロジックレベル変換モジュール」を間に接続し、3.3V⇔5Vの電圧変換を行っています。
  • 私が使用したLCDのようにパラレルデータ用端子しかない場合、I2C⇔パラレル変換の「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()

こちらがラズパイに書き込むプログラムになります。ポイントは以下です。

  • LCD用ライブラリ「RPLCD.i2c」を使用します。
  • I2Cはマスターからスレーブアドレスを出力する必要があります。今回のLCDはデフォルトでアドレス「0x27」が設定されているので、関数内に記載します。アドレスがわからない場合は前述した通り、配線後ラズパイのターミナルで「i2cdetect -y 1」を入力するとわかります。
  • LCDの1行目にメッセージを表示した後、カーソルを2行目の先頭に移動させ、続けてメッセージを表示させています。

ラズパイ ⇔ マイコン(Arduino)間でI2C

続いて、ラズパイ⇔マイコン間のI2C通信について解説します。
マイコンはArduino Leonardを使いました。

動画

イメージはこんな感じです。
ラズパイで数値を入力後、ArduinoへI2C信号が送られ、Arduino側でPWMを用いてLEDの明るさを変えています。

PWMって何、、、という方は過去に解説していますのでこちらをご覧ください!

使用部品

※私は手元にあったラズパイ3A+を使いましたが、上記最新モデルでも問題なく使用できます。

Arduino Leonardは有名なArduino Unoとピン配置が異なりますが、能力的に問題なく安価なので、電子工作など簡易的な利用でしたらオススメです!

回路

回路はこちらで、ポイントは以下になります。

  • ラズパイの信号電圧は3.3Vですが、Arduinoは5Vの為、直結では通信できません。そこで電圧変換する「4ch双方向ロジックレベル変換モジュール」を接続しています。
  • ラズパイからI2CでArduinoへ信号を送ります。
  • Arduino側で赤LEDを接続しており、明るさを変えています。

プログラム マスター(ラズパイ)側

#ライブラリのインポート
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}")

プログラムについては、マスター・スレーブそれぞれに書き込む必要があります。まずはマスター(ラズパイ)側のポイントです。

  • ラズパイ向けライブラリ「smbus」を利用する事で簡単にI2C通信ができます。冒頭でインストールします。
  • Arduinoはスレーブアドレスを任意に設定する事ができます。今回はArduino側では0x09と設定していますので、ラズパイ側コードでも変数へ代入して使用します。
  • シェルに数値入力を促すメッセージを表示させます。0~255の数値を入力した場合のみ、Arduinoへ送信します。
  • q もしくは ctrl + C を入力すると処理を終了させます。

プログラム スレーブ(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)側のコードです。ポイントは以下です。

  • Arduino向けライブラリ「Wire.h」を利用する事で簡単にI2Cを行うことができます。冒頭でインストールします。
  • 関数「Wire.begin()」でスレーブアドレスを任意に設定する事ができます。今回は9で設定します。
  • マスターからのデータ受信時に関数turnOnLEDを呼び出し、変数に値を書き込みます。そしてメイン処理でLEDピンに変数を出力し明るさを変えます。

まとめ

いかがでしたでしょうか。
I2Cと聞くと一見難しそうに聞こえますが、ライブラリを使う事で手軽に利用できる事がお分かりになったかと思います。

ただし、プルアップ抵抗が必要、長距離配線・接触不良に弱い等、I2Cにも弱点は存在します。もし通信が上手くいかない場合、こちらもぜひご参考にしてみてください。

今回はラズパイ⇔Arduino間のI2C通信を紹介しましたが、Arduino間でも試してみたので、気になる方はご覧ください!

メカ旦那

旧帝大工学部を卒業後、電気制御設計職をしています。生産設備や産業用ロボット等、様々な開発に取り組んでいます。電験三種も保持しています。イラストや画像を用いて電気・電子・制御をわかりやすく解説します!

メカ旦那をフォローする
Raspberry Pi
スポンサーリンク

コメント