ラズパイでI2C通信を行う
ラズパイを使ってハードウェアを制御するシリーズ、第三回目はI2C通信です。
今回は実際にデバイスをラズパイに接続して動作確認を行ったので、その手法も合わせてまとめておきたいと思います。
I2Cとは?
I2Cは Inter-Integrated Circuit の略でアイ・スクエアード・シーと読みます。
SCL, SDAの二本の信号線からなるシリアルバスです。
規格の詳細は割愛しますが、こちらに日本語の規格仕様書がアップされています。http://ekousaku.web.fc2.com/doc/I2C.pdf
ラズパイとデバイスの接続
ラズパイでI2Cを使用するにはデバイスと以下のように接続します。
I2Cの端子はオープンコレクタなので、外付けのプルアップ抵抗が必要です。センサーモジュールをお使いの場合はそちらに実装されていることがあるので、回路図で確認してください。
ラズパイのI2C端子は設定を変えることでGPIO2をSDAに, GPIO3をSCLに割り当てることができます。
今回はアナログデバイセズの加速度センサーADXL345を使って動作確認をしてみます。
(こちらのサイトからモジュールを購入しました)
http://akizukidenshi.com/catalog/g/gM-06724/
データシート
http://akizukidenshi.com/download/ds/freescale/ADXL345_jp.pdf
センサーモジュールとの接続は以下の回路図のようにしました。CS端子とVDDを接続するとI2Cモードで動作するようになります。
実際の接続(まだ電源は入れていません)
I2Cを使うための設定
Rasbianのデフォルト設定ではラズパイでI2Cを使うことはできません。
GUIの設定メニューからI2Cを有効にします。
設定ーRaspberry Piの設定ーインターフェース
I2Cを有効にした後、再起動するとI2Cが使用できるようになります。
デバイスがI2C接続で認識されているかを確認するために以下のコマンドを実行します。
$ i2cdetect -y 1
正しく認識されると以下のように表示されます。0x1dが接続されている加速度センサーのスレーブアドレスです。
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- 1d -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Pythonライブラリのインストール
ラズパイのpythonでI2C通信を行うにはWiringPiライブラリを使用します。
pipコマンドでインストールします。
$ pip3 install wiringpi
I2Cで通信を行うプログラム
上記でインストールしたWiringPiライブラリを使って値を読み書きするサンプルコードを以下に示します。
import wiringpi slv_addr = 0x1D #デバイスのスレーブアドレス read_addr = 0x00 #デバイス内でアクセスしたいアドレス write_addr = 0x1E #デバイス内でアクセスしたいアドレス write_data = 0x08 #書き込むデータ値 #初期設定 wiringpi.wiringPiSetup() i2c = wiringpi.I2C() #get I2C Fd = i2c.setup(slv_addr) #setup I2C device #アドレス"read_addr"の値を読み出す read_data = i2c.readReg8(Fd, read_addr) print('read_data = 0x{:02x}'.format(read_data)) # デバイスID 11100101 が読めるはず #>>read_data = 0xe5 #アドレス"write_addr"に対してwrite_dataを書き込む i2c.writeReg8(Fd, write_addr , write_data) #正しく書き込めたことを確認 read_data = i2c.readReg8(Fd, write_addr) print('write_data = 0x{:02x}'.format(read_data)) #>>write_data = 0x08
read, writeとも8bit用の関数を使用していますが、16bitの関数も準備されています。
- int wiringPiI2CWriteReg8 (int fd, int reg, int data) ;
- int wiringPiI2CWriteReg16 (int fd, int reg, int data) ;
- int wiringPiI2CReadReg8 (int fd, int reg) ;
- int wiringPiI2CReadReg16 (int fd, int reg) ;
wiringpiのサイト
http://wiringpi.com/reference/i2c-library/
リアルタイムに3軸加速度を読み出すプログラム
i2cのアクセス関数を用いてリアルアイムにx,y,z方向の加速度を読み出すプログラムを作りましたので、参考までに乗せておきたいと思います。
import wiringpi import time slv_addr = 0x1D #初期設定 wiringpi.wiringPiSetup() i2c = wiringpi.I2C() #get I2C Fd = i2c.setup(slv_addr) #setup I2C device i2c.writeReg8(Fd, 0x2D , 0x08) #測定スタート try: while True:
#x,y,z方向の加速度を取得(2の補数表現) x_data = i2c.readReg16(Fd, 0x32) y_data = i2c.readReg16(Fd, 0x34) z_data = i2c.readReg16(Fd, 0x36) #2の補数を10進に変換 if(x_data & 0x8000): x_data = ((~x_data & 0xFFFF) + 1)*-1 if(y_data & 0x8000): y_data = ((~y_data & 0xFFFF) + 1)*-1 if(z_data & 0x8000): z_data = ((~z_data & 0xFFFF) + 1)*-1
#加速度に変換(Dレンジ ±2g) x_data = 2 * 9.8 * x_data / 0x7FFF y_data = 2 * 9.8 * y_data / 0x7FFF z_data = 2 * 9.8 * z_data / 0x7FFF print('x: {:2.2f}, y: {:2.2f}, z: {:2.2f} [m/s^2]'.format(x_data, y_data, z_data)) time.sleep(0.1) except KeyboardInterrupt: print('!FINISH!')
実行結果は以下の通りです。センサーを動かすと加速度が変化することが確認できました。
まとめ
ラズパイでデバイスとI2C通信を行う方法を記載しました。加速度への変換部分がこれでよいのか自信がないですが、I2Cの読み書きは問題ないはず。
せっかく加速度センサを購入したので、何か面白い使い道がないか考えてみたいと思います。