I2C通信は、マイコンと周辺部品の通信でよく使われるシリアル通信です。
ここでは、ArduinoのI2C通信波形を実際に確認しながら、I2C通信の仕様についてまとめていきたいと思います。
準備するもの
この記事では、以下の物を使います。
●Arduino Uno
amazonのスイッチサイエンスから購入する純正のArduinoは、永久保証を受けることができます。
ブレッドボードや電子部品が付いてくるので、すぐに工作を始めることができます。
●LCDディスプレイ
16文字×2行を表示することができるLCDディスプレイです。
本来LCDディスプレイはパラレル信号を入力しないといけませんが、この商品はパラレル通信⇔I2C通信を変換してくれる回路が元から付いているので、I2C通信によるやりとりが可能です。
●CO2センサー
I2C通信で接続することができるCO2センサーです。
精度はそれほど信用できるものではありませんが、手軽にArduinoでCO2を計測することができます。
詳細な使い方は以下の公式HPで紹介されています。
https://wiki.keyestudio.com/KS0457_keyestudio_CCS811_Carbon_Dioxide_Air_Quality_Sensor
●ジャンパーワイヤー
LCDディスプレイやセンサーは端子がオスになっているので、各種ワイヤーを揃えておくと便利です。
●ロジックアナライザ
このロジックアナライザを使用すれば、UART、IIC、SPIなどのシリアル通信のデータを見ることができます。
●解析ソフト pluseview
上記のロジックアナライザのデータを見るために、pluseviewというフリーソフトを使用します。
https://sigrok.org/wiki/Downloads
以下のサイト様で使用方法を詳しく解説されているので、参考にしてください。
I2C通信とは
I2C通信は組み込み機器のマイコンと、センサやLCDなどを接続するとき等によく使われるシリアル通信です。
2本の通信線で同時に複数の部品と通信するので、通信線が少なく省スペースにすることができますが、通信速度はそれほど早くありません。
使用するスケッチ
ArduinoでCO2センサーから取得したデータを、LCDに表示するスケッチを使用します。
CO2センサーとLCDはI2C通信でArduinoと通信します。
詳細は以下の記事でご紹介しています。
ソースコードで重要な箇所を抜粋します。
// set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27,16,2);
// CCS811 sensor(&Wire, /*IIC_ADDRESS=*/0x5A);
CCS811 sensor;
まず、LCDとCO2センサーのアドレスを設定しています。
I2C通信を使う部品は、それぞれ自分のアドレスを持っています。
あらかじめLCDとCO2センサーのアドレスを調べて、そのアドレスを指定してやる必要があります。
今回使用する部品のアドレスは以下の通りです。
部品 | アドレス |
---|---|
LCD | 0x27 |
CO2センサー | 0x5A |
if(sensor.checkDataReady() == true){
lcd.clear();
lcd.setCursor(0,0);
lcd.print("CO2: ");
lcd.print(sensor.getCO2PPM());
lcd.print("ppm");
lcd.setCursor(0,1);
lcd.print("TVOC: ");
lcd.print(sensor.getTVOCPPB());
lcd.print("ppb");
}
CO2センサーの準備ができていたら、CO2センサーからデータを取得してLCDに表示するスケッチです。
I2C通信の仕様
上記のスケッチを実際に動かして取得したI2Cの通信データを見てみましょう。
以下がその通信データです。
ArduinoがSCLの線に流すクロックのタイミングに合わせて、SDLの線でデータをやり取りします。
今回使っている部品のアドレス「0x27」「0x5A」のうち、通信したい方のアドレスを指定して、データをやり取りしているのがわかります。
通信シーケンス
通信するときのシーケンスは以下の通りです。
順番にI2Cの仕様を見ていきたいと思います。
電圧
最大の電圧は5Vで、よく使われる電圧は3.3Vです。
SCL(クロック)
シリアル通信には、信号を正しいタイミングで読み取るための方式として、同期式と調歩同期式の2方式があります。
I2Cは同期式です。
マスターとなるマイコンからクロック信号をSCLに流して、そのクロック信号に合わせて通信データをやり取りします。
通信データの確認
SCLに規則正しいクロック信号が流れているのが分かります。
クロック信号がHighになる(立ち上がり)ときにSDAがHigh(1)かLow(0)かを判断すればいいわけです。
余談
I2Cは「SCL」と「SDA」の通信線2本でデータをやり取りしますが、片方の「SCL」はクロックを流す専用の線なので、肝心の通信データは「SDA」1本でやり取りすることになります。
なので、常にマスターであるArduinoからスレーブである周辺部品に指示を出して、通信データの書き込み / 読み込みをしています。
このような方式を半二重通信といいます。
反対に、UARTのような通信データ用に2本の線があり、お互いの好きなタイミングで通信データをやり取りできる方式を全二十通信といいます。
スタートコンディション・ストップコンディション
SDAで通信データをやり取りするときに、どこからがデータかを判別するための仕組みが「スタートコンディション」と「ストップコンディション」です。
I2C通信は何もデータをやり取りしていないときは、Highの状態にプルアップされています。
この状態で通信データのHigh(1)が送られてくると、何も送られていないのか、High(1)が送られているのか区別がつきません。
そこで、必ず一番初めにスタートコンディションを送り、次から送られてきたデータから読み始めます。
また、上記のルールを守るためには、通信が終えたタイミングでSCLとSDAがHighになっている必要があります。
このため、通信が終われば必ず最後にストップコンディションを送ります。
通信データの確認
確かに、ルールの通り通信が開始/終了しているのが分かります。
アドレス
2本の通信線だけで複数の部品と通信ができる仕組みを実現しているのがアドレスです。
各部品にはあらかじめアドレスが設定されているので、Arduinoは好きな宛先を指定して通信をすることができます。
通信データの確認
今回使用しているLCDとCO2センサーのアドレスのうち通信したい方を指定して、そのあと通信データのやり取りがされています。
SDAの1本のみで、2つの部品と通信することができています。
書き込み(0) 読み込み(1)
7bitのアドレスの末尾が0か1かで、Arduinoが部品に対してデータを書き込むのか、Arduinoが部品からデータを読み込むのか、が変わります。
通信データの確認
7bitのアドレスの後ろに、Write(0)とRead(1)が付いているのが分かります。
Write(0)でまずArduinoからCO2センサーに対してこれから欲しいデータの指示を出して、Read(1)で指示したデータを取得しています。
CO2センサーはアドレスが「0x5A」なので、その後ろに0か1をつけた状態を16進数で表すと、書き込みのときは「B4」、読み込みのときは「B5」というデータをCO2センサに送ればいいことになります。
Ack・Nack
Arduinoも周辺部品も、何かのデータを正常に受信したときにはAckを、受信が失敗したときはNackを返します。
この仕組みを使うことで、お互いに通信がうまくいっているのか確認しながらやり取りをすることができます。
通信データの確認
まずはAckの例です。
ArduinoがCO2センサーに対して読み込みのコマンドを送った後に、信号がLowになりAckが帰ってきているのが分かります。
Arduinoは読み込みのコマンドを送ったら、信号をHigh(何も信号が流れていない状態)に戻しますが、すぐさまCO2センサーがLow(0)を出力することでAckとなります。
CO2センサーはArduinoからコマンドを受け取ったあと、かなりシビアな時間でAckを返すことが要求されますね。
次にNackの例です。
ArduinoがCO2センサーからデータを受信したあとに、SDAがLow(0)にならずHigh(1)のままになっています。
通信に失敗したときや、そもそもアドレスが間違えたときなどは、このようにデータの後がHigh(1)のままとなり通信が失敗したことが分かります。
まとめ
ArduinoとLCD、CO2センサーがI2Cで通信するときの波形を参考に、I2C通信の仕様をご紹介しました。
I2Cは2本の通信線で複数の部品と通信するぶん、UARTなどに比べると少し複雑な通信の制御が必要になりますが、Arduinoではとても簡単に実現することができますね。
実際に波形を見ることでI2Cの理解もより深まると思いますので、ぜひ皆さんも一度波形を確認してみることをオススメします。
コメント