I2C接続LCDの通信フォーマットの理解
書面だけではわかりにくいI2C接続LCDの通信方法について、実際の通信波形を観察することで理解を深められると思い、本記事を作成しました。
通信フォーマットに即したプログラムを作成し、出力される波形をオシロスコープで確認します。
フォーマット、プログラム、出力される波形がどのように関係しているのかを理解できればI2C接続LCDをより気軽に使えるようになると思います。
- I2C通信の仕組み
- 使用する部品と配線
- 通信フォーマットの確認
- Arduinoでのプログラム
- オシロスコープで波形を確認
I2C通信の仕組み
1台のマスタと1~複数のスレーブをSCL(クロック線)とSDA(データ線)で接続します。SCL,SDAともにプルアップされており、待機中はともにHIGHとなっています。マスタが常に通信の主導権を持っており、マスタがSCLで送信するクロック信号を基準にデータ信号をSDAで通信します。
スレーブは個々にアドレスを持っており、マスタがアドレスを指定することで特定のスレーブと通信ができます。
データの受信側は1byte(8bit)ごとにACK信号(アクノリッジ)というデータ受信を確認したことを伝える信号を返送し、互いに確認を取りながらデータ送信を行います。
使用する部品と配線
今回使用するLCD表示機は秋月電子で購入したAE-AQM1602A(KIT)になります。550円で購入しました。マスタにはArduino UNO(互換機)を使用します。配線図は下の通りになります。
通信フォーマットの確認
LCD表示機に同封されていたデータシートにLCD表示機へ書き込む際の通信フォーマットの記載がありました。少し見にくかったので書き直しました。
通信フォーマットから8bit(1byte)ごとにACK信号があることがわかります。また、1度に送られる8bitのデータの種類も「スレーブアドレスバイト」「制御バイト」「データバイト」があることがわかると思います。
スレーブアドレスバイト
7~1bit:スレーブアドレス
0bit:R/W・・・受信(読込)Readか送信(書込み)Writeかを選択
受信(読込)Readの場合は「R/W =1」 |
送信(書込み)Writeの場合は「R/W =0」 |
制御バイト
7bit:Co・・・複数のデータバイトを送るか否かを選択
次に送るデータバイトがある場合は「Co=1」 |
最後のデータバイトの場合は「Co=0」 |
6bit:RS・・・制御バイトの後に続くデータバイトの種類を選択
液晶の設定(制御コマンド)の場合は「RS=0」 |
液晶の表示データの場合は「RS=1」 |
5~0bit:未設定(0にする)
データバイト
7~0bit:液晶の設定や表示データを入れる
通信のスタート条件とストップ条件
SCLが「HIGH」の時にSDAが「LOW」になると通信開始となり、SCLが「HIGH」の間にSDAが「HIGH」になると通信終了となります。なのでSDAの通信中の「HIGH」、LOW」の変化はSCLが「LOW」の時に行われます。
Arduinoでのプログラム
今回はI2C通信の波形を観察することを目的にしているため、できるだけ簡単なプログラムにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
#include <Wire.h> void setup() { Wire.begin();//i2c初期化 init_LCD();//液晶初期化 } void loop() { //「W」を表示 Wire.beginTransmission(0b00111110);//通信開始の指示,7~1bit:スレーブアドレス,0bit:R/W=0(書込み)・・・・・・・・スレーブアドレスバイト Wire.write(0b01000000);//7bit:Co=0(最後のデータバイト),6bit:RS=1(液晶の表示データ),5~0bit:0(未設定)・・・・・制御バイト Wire.write(0b01010111);//7~0bit:データバイト(任意の文字)・・・・・・・・・・・・・・・・・・・・・・・・・・・・・データバイト Wire.endTransmission();//通信終了の指示 delay(2000); //表示をクリア Wire.beginTransmission(0b00111110);//通信開始の指示,7~1bit:スレーブアドレス,0bit:R/W=0(書込み)・・・・・・・・スレーブアドレスバイト Wire.write(0b00000000);//7bit:Co=0(最後のデータバイト),6bit:RS=0(液晶の設定),5~0bit:0(未設定)・・・・・制御バイト Wire.write(0b00000001);//7~0bit:データバイト(表示をクリア)・・・・・・・・・・・・・・・・・・・・・・・・・・・・データバイト Wire.endTransmission();//通信終了の指示 delay(2000); } //液晶初期化 void init_LCD() { delay(100); Wire.beginTransmission(0x3E);//0b00111110 Wire.write(0x00);//0b00000000 Wire.write(0x38);//0b00111000 Wire.endTransmission(); delay(20); Wire.beginTransmission(0x3E);//0b00111110 Wire.write(0x00);//0b00000000 Wire.write(0x39);//0b00111001 Wire.endTransmission(); delay(20); Wire.beginTransmission(0x3E);//0b00111110 Wire.write(0x00);//0b00000000 Wire.write(0x14);//0b00010100 Wire.endTransmission(); delay(20); Wire.beginTransmission(0x3E);//0b00111110 Wire.write(0x00);//0b00000000 Wire.write(0x73);//0b01110011 Wire.endTransmission(); delay(20); Wire.beginTransmission(0x3E);//0b00111110 Wire.write(0x00);//0b00000000 Wire.write(0x52);//0b01010010 Wire.endTransmission(); delay(20); Wire.beginTransmission(0x3E);//0b00111110 Wire.write(0x00);//0b00000000 Wire.write(0x6C);//0b01101100 Wire.endTransmission(); delay(20); Wire.beginTransmission(0x3E);//0b00111110 Wire.write(0x00);//0b00000000 Wire.write(0x38);//0b00111000 Wire.endTransmission(); delay(20); Wire.beginTransmission(0x3E);//0b00111110 Wire.write(0x00);//0b00000000 Wire.write(0x01);//0b00000001 Wire.endTransmission(); delay(20); Wire.beginTransmission(0x3E);//0b00111110 Wire.write(0x00);//0b00000000 Wire.write(0x0C);//0b00001100 Wire.endTransmission(); delay(20); } |
通常は8bit部分は16進数で記載しますが、今回はわかりやすいようにメインとなるloop関数の部分は2進数で記載したいと思います。(2進数の場合は0bで始まり、16進数の場合は0xで始まる)1行ごとにコメントに各bitの内容を記載しました。
液晶初期化のプログラムについてはデータシートを参考に作成しました。こちらは8bit部分を16進数で記載しています。(コメントには2進数を記載しておきます。)設定内容の詳細については本記事では説明はしないことにします。
このプログラムで「W」と「無表示」が2秒間隔で点滅することを確認しました。
オシロスコープで波形を確認
11行~14行目が「W」を表示させるプログラムになります。下に通信波形を示します。
なぜか、スレーブアドレスバイトが左にズレていることがわかります。これはスタートビットが入っているためと思います。スタートビットをコントロールする「Wire.beginTransmission」の中に「00111110」を「01111100」に変える効果があるのだと思います。(勉強不足ですいません)
制御バイト、データバイトはプログラム通りの波形になっています。
18行~21行目が「表示をクリア」にするプログラムになります。下に通信波形を示します。
こちらの波形もスレーブアドレスバイトが左にズレていることが確認できますが、制御バイト、データバイトはプログラム通りの波形になっています。
また、通信の開始及び終了条件についても、
開始条件・・SCLが「HIGH」の時にSDAが「LOW」
終了条件・・SCLが「HIGH」の間にSDAが「HIGH」
になっていることと、SDAの通信中の「HIGH」、「LOW」の変化がSCLが「LOW」の時に行われていることもわかるかと思います。
今回は実際にI2C通信の波形を観察することで、どのように情報を伝達しているかがわかっりました。次回は単語の表示に挑戦していきたいと思います。