Arduinoで実験 (I2C制御の液晶)

2013/04/25


◆ I2C

I2C は SCL と SDA の 2本の線で接続された機器を制御する通信方法で、制御元となる機器をマスター、制御先の機器をスレーブという。 マスターは固有のアドレスを持つ複数のスレーブを制御でき、アドレスを指定することにより目的のデバイスを制御できる。

Arduino の心臓部である ATmega328P は、マイコン自体で I2C をサポートしており A4(SDA), A5(SDL) ピンが専用の線となっている。

Arduino IDE では、I2C通信のための <Wire.h> ライブラリがあり、I2C の細かい制御方法を知らずとも使いこなすことができる。

<Wire.h> ライブラリでは、7ビットの I2C アドレスをサポートしており、8ビット目は Read/Write 信号に用いている。 よって 8ビットのアドレスを持つ機器に対しては右シフトし0ビット目を捨てる必要があるらしい。

I2C で通信する際、 SDA と SCL は 3kΩ程度の抵抗でプルアップする必要がある。 プルアップやプルダウンは入力端子が解放状態の場合、や未入力状態の場合に適切な論理レベルとなるようにするものらしい。 これも難しいことはわからん。


◆ Wire.h ライブラリ

I2C 通信用ライブラリ <Wire.h> を使用して制御する。 ライブラリ内で pinMode の設定が行われるので setup() では必要ない。 また、内蔵プルアップも有効となる。

Wire.h の具体的な使用方法は Arduino日本語リファレンスに詳しくあるので特に書かないが、I2C通信で制御する際にコマンド等は間違っていないのに思ったような動作を行わないような場合は動作タイミングを疑ってみる。 マイコンに比べ I2C は通信速度が遅いので delay(1) 等入れて見ると良い場合がある。


◆ I2C 低電圧キャラクタ液晶モジュール SB1602BW

ストロベリーリナックスで取り扱っている携帯電話用の液晶モジュールで、データシートでは 3.3V 動作とあるが、 データは5Vでも動かしても今のところ問題は起きていない。 もし実験する場合は自己責任でお願いします。

プルアップ抵抗を入れるべきであるが、<Wire.h> ライブラリ内で内蔵プルアップを有効にしているので、外部でプルアップ抵抗を使用しない。 もちろん、動作が不安定な場合は適切な抵抗を入れた方がよい。

種別 定格・番 個数 備考
マイコン Arduino UNO 1  
I2C制御のディスプレイ SB1602BW 1 Vf = 2.1V / If = 20mA (peak = 30mA)
配線は、以下の通りにする。
Arduino の A4  ⇔  ③ SDA
           A5  ⇔  ② SCL 

           3V3 ⇔  ⑤ Vdd
           3V3 ⇔  ① リセット
           GND ⇔  ④ GND 

配線が完了したら次のスケッチを実行する。 スケッチでは、コマンド/データ送信関数、初期化関数を使用している。

//
// 06-01 I2C制御のキャラクタ液晶ディスプレイを使う
//

#include <Wire.h>      // Wire.h ライブラリをインクルード

#define I2C_ADDR 0x3E  // ディスプレイの I2C アドレス 

void setup() {
  Wire.begin(0);       // I2C マスターとして初期化
  initLCD();           // LCD の初期化

  writeBUS(1, 'H');    // 一文字表示
  writeBUS(1, 'e');
  writeBUS(1, 'l');
  writeBUS(1, 'l');
  writeBUS(1, 'o');
}

void loop() {
}

// コマンド送信関数
void writeBUS(boolean rs, byte b) {
  (rs)? rs = 0x40 : rs = 0;
  Wire.beginTransmission(I2C_ADDR);
  Wire.write(rs);
  Wire.write(b);
  Wire.endTransmission();
  delay(1);
}

// LCD 初期化関数
void initLCD(void) {
  delay(50);               // 電源投入後の待機時間
  writeBUS(0, 0b00111000); // 0x38 Function set
  writeBUS(0, 0b00111001); // 0x39 Function set
  writeBUS(0, 0b00010100); // 0x14 Internal OSC frequency
  writeBUS(0, 0b01111100); // 0x7c Contrast set
  writeBUS(0, 0b01011111); // 0x5f Power/Icon/Contrast control
  writeBUS(0, 0b01101010); // 0x6a Fllower control
  delay(300);              // 待機時間
  writeBUS(0, 0b00111000); // 0x38 Function set
  writeBUS(0, 0b00001100); // 0x0c Display on/off control
  writeBUS(0, 0b00000001); // 0x01 Clear Display
  delay(200);
}

以下は ST7032i の制御コマンドである。

名称 RS RW DB
7 6 5 4 3 2 1 0
Clear
Display
0 0 0 0 0 0 0 0 0 1  
Return
Home
0 0 0 0 0 0 0 0 1 *  
Entry
Mode
0 0 0 0 0 0 0 1 I/D S I/D: cursor move
S: display shift
Display
On/Off
0 0 0 0 0 0 1 D C B D: display
C: cursor
B: blink
Function
Set
0 0 0 0 1 DL N DH * IS DL: line
N: mode
DH: double height font
IS: instruction table
Set DDRAM
Address
0 0 1 ad ad ad ad ad ad ad ad: address
BusyFlag /
Read Address
0 1 BF ad ad ad ad ad ad ad BF: busy flag
ad: address
Write Data 1 0 d d d d d d d d d: data
Read Data
from RAM
1 1 d d d d d d d d d: data
Instruction table ( IS = 0 )
Cursor /
Display
Shift
0 0 0 0 0 1 S/C R/L * * S/C: shift
R/L:
Set CGRAM
Address
0 0 0 1 ad1 ad1 ad1 ad2 ad2 ad2 ad1: char addr.
ad2: data bit
Instruction table ( IS = 1 )
Internal OSC frequency 0 0 0 0 0 1 BS F2 F1 F0 BS:
F2-0: OSC freqency
Set CGRAM
Address
0 0 0 1 ad1 ad1 ad1 ad2 ad2 ad2 ad1: char addr.
ad2: data bit
Power/Icon/
control/
Contrast set
0 0 0 1 0 1 Icon Bon C5 C4 Icon: Icon on/off
Bon: set booster on/off
C5-4: contrast
Set Icon address 0 0 0 1 0 0 ad ad ad ad ad: Icon address
Follower control 0 0 0 1 1 0 Fon Rab Rab Rab Fon: follower curcuit
Rab: select follower
Contrast set 0 0 0 1 1 1 C3 C2 C1 C0 Contrast set

待機時間を省略しているが Clear Display と Return Home では 2ms程度の待機時間を必要とする。 他は 0.03ms程度の待機時間。

HD44780 互換コマンドであるが、Instraction table (IS) を立てることによりコマンドを拡張している。 以下に拡張コマンドをまとめる。

Instruction table ( IS = 1 )
  RS RW 7 6 5 4 3 2 1 0
Internal OSC frequency 0 0 0 0 0 1 BS F2 F1 F0
BS: bias selection
  1 : 1/4
  0 : 1/5 (default)
F2-0: Internal OSC freqyency adjust
  F2, F1, F0 : default = 1, 0, 0 ( 3V = 183Hz, 5V = 192 Hz)

バイアス選択は正直何だかわからないので初期値を使用する。

内蔵オシレータを設定。 動作電圧 3Vの場合と 5Vの場合とで異なる。 これもなんかわからないので初期値を使用する。

Instruction table ( IS = 1 )
  RS RW 7 6 5 4 3 2 1 0
Set Icon RAM address 0 0 0 1 0 0 AC3 AC2 AC1 AC0
AC3-0: Icon RAM address  00H ~ 0FH

アイコンのアドレスを設定

Instruction table ( IS = 1 )
  RS RW 7 6 5 4 3 2 1 0
Power/Icon control/Contrast set 0 0 0 1 0 1 Ion Bon C5 C4
Ion: set Icon display on/off
  1 : on
  0 : off
Bon: switch booster circuit
  1: on (default)
  0: off

Ion はアイコンの表示/非表示のスイッチ

Bon は内部の昇圧回路を動作させるスイッチ。初期値はオン。

コントラスト値であるが、コントラスト値は 6ビットで指定され、上位 2ビットをここで設定する。 詳細は Contrast set で。

Instruction table ( IS = 1 )
  RS RW 7 6 5 4 3 2 1 0
Follower control 0 0 0 1 1 0 Fon Rab2 Rab1 Rab0
Fon: switch follower circuit
  1 : on
  0 : off
Rab2-0: V0 generator amplified ratio
  Rab2, Rab1, Rab0 : default = 0, 1, 0

Follower circuit とは何のことかわからない。 その後に続く Rab が V0 Generator とあるので、0V の発生回路なのかしらん? 正直、ここいらを掘り下げる気はないので初期値の 0b 0110 1010 とすることにする。

Instruction table ( IS = 1 )
  RS RW 7 6 5 4 3 2 1 0
Contrast set 0 0 0 1 1 1 C3 C2 C1 C0
C3-0 : Contrast set (low byte)

Power/Icon control/Contrast set と組み合わせてコントラスト値を設定する。

コントラスト値は 0 ~63 までの 7ビットの値で設定し、値が大きいほど表示が濃くなる。

上位 2ビットと下位 1バイトとを別けて設定しないといけないのでプログラムでの工夫が必要となる。

アイコン表示
LCD上の9種のアイコンを表示/非表示します。 電池マークのアイコンなど、4つの表示でひとつのアイコンとなる物もある。
Set Icon address でアイコンの種別を設定した後、Write Data to RAM で表示したいビットを立てます。
アイコンの種別 アドレス  
AC3 AC2 AC1 AC0
アンテナ 0 0 0 0 00010000
電話 0 0 1 0 00010000
音波 0 1 0 0 00010000
→◇ 0 1 1 0 00010000
上下 0 1 1 1 00011000
1 0 0 1 00010000
スピーカーに× 1 0 1 1 00010000
電池 1 1 0 1 00011110
タイマー 1 1 1 1 00010000
上下マークの上のみを表示したい場合は 00010000
      下の身を表示したい場合は 00001000
電池マークの左 00010000
      中 00001000
      右 00000100
     外枠 00000010

アイコンの表示を行う際に ISビットを立てるので、アイコン表示/非表示を行ったら必ず ISビットを 0 にしないと文字表示されないので注意が必要

サンプルでアイコンを表示してみる。 次のスケッチの loop() を先ほどのスケッチの loop() と置き換えてください。

//
// 06-02 アイコン表示実験スケッチ
//

void loop() {
 電話マークを表示
  writeBUS(0, 0b00111001); // IS ビットを立てる
  writeBUS(0, 0b01000000); // アイコン種別を指定
  writeBUS(1, 0b00010000); // 表示
  writeBUS(0, 0b00111000); // IS ビット = 0
  delay(1000);

// 電話マークを比表示
  writeBUS(0, 0b00111001); // IS ビットを立てる
  writeBUS(0, 0b01000000); // アイコン種別を指定
  writeBUS(1, 0b00000000); // 比表示
  writeBUS(0, 0b00111000); // IS ビット = 0
  delay(1000);

// 電池満タン
  writeBUS(0, 0b00111001);
  writeBUS(0, 0b01001101);
  writeBUS(1, 0b00011110);
  writeBUS(0, 0b00111000);
  delay(1000);

// ひとつ減る
  writeBUS(0, 0b00111001);
  writeBUS(0, 0b01001101);
  writeBUS(1, 0b00011010);
  writeBUS(0, 0b00111000);
  delay(1000);

// ふたつ減る
  writeBUS(0, 0b00111001);
  writeBUS(0, 0b01001101);
  writeBUS(1, 0b00010010);
  writeBUS(0, 0b00111000);
  delay(1000);

// 電池が空
  writeBUS(0, 0b00111001);
  writeBUS(0, 0b01001101);
  writeBUS(1, 0b00000010);
  writeBUS(0, 0b00111000);
  delay(1000);

while(1);
}