今回は、40文字×4行LCD C-51849NFJをI2C化します。
●ブレッドボード試作回路
この回路もarduinoでLCDを点灯させるだけの単純なものです。回路的には「40文字×4行LCDモジュールを使ってみる」でブレッドボードで製作したものとほとんど同じです。
次の写真は「40文字×4行 LCDモジュールを使ってみる」で掲載したものですが、これにジャンパとI2C信号を接続すれば、同等となります。
●エリア設定コマンドの追加
LCDを制御するコマンド(I2Cで受信する2バイトのデータ)は、1バイト目がレジスタセレクトの0×00(LCDコマンド)か0×01(LCDデータ)、2バイト目がコマンドコードか文字コードとなっています。ここまでは、前回の14ピンLCD用のソフトと同じです。
さらに、40文字×4行対応では、エリアを指定するコマンドを追加しています。このコードは1バイト目が0xFFで、2バイト目がエリア番号(0/1/2)となっています。エリア番号は”0″がエリア0、”1″がエリア1、”2″がエリア0とエリア1の両方です。
●プログラム/ファームウェア(I2CLcdCtrl404.ino)
このプログラムも前回の14ピンLCD用(I2CLcdCtrl.ino)と同じような構造ですが、C-51849が8ビットモードで作動する関係で、初期化やデータ、レジスタの書き込み処理が8ビット用になっています。
次にコードを示します。
// // I2C制御 LCDコントローラ(OPTREX C-5184NFJ-SLW-ADN) // copyright (c) 2013 http://www.wsnak.com // // 40文字×4行 LCDモジュールのI2C化キット // // 12/11/16 // /* OPTREX C-5184NFJ-SLW-ADN専用 LCDへ接続して、I2Cデバイス化する、Arduino使用のコントローラ */ #include <Wire.h> char StrBuf[16]; /* LCD DATA PORTD2-7(D2-D7), PORTB0,1(D8,D9) LCD E1 D10 LCD E2 D11 LCD RS D12 */ #define E1_ON digitalWrite(10, HIGH) #define E1_OFF digitalWrite(10, LOW) #define E2_ON digitalWrite(11, HIGH) #define E2_OFF digitalWrite(11, LOW) #define RS_CMD digitalWrite(12, LOW) // RS=0 #define RS_DATA digitalWrite(12, HIGH) // RS=1 #define LCD_DAT PORTD // D0~D7 #define TST_SW !(PINC&(1<<3)) // PC3 (A3) ジャンパショート時テスト byte CmdCnt; byte Cmd, Data; byte SelArea; // 0=E1, 1=E2 2=E1&E2 選択 void writeCmd(void); // プロトタイプ void WriteData(byte dat); void WriteCmd(byte dat); void POut8bit(byte dat); void LcdInit(void); void E_Pulse(void); // ----------------------------------- // 初期化 // ----------------------------------- void setup(void) { // Serial.begin(19200); // シリアル初期化 // 入力ポートのデジタルバッファをイネーブルにする DIDR0 &= ~(1<<ADC3D); // ADC3 // A3(PC3) ディジタル入力に再設定 DDRC &= ~(1<<3); // input PORTC |= (1<<3); // pullup enable // Wire.begin(0x50); Wire.begin(0x30); Wire.onReceive(hSlvRcv); CmdCnt = 0; pinMode(2, OUTPUT); // LCD DB2 pinMode(3, OUTPUT); // LCD DB3 pinMode(4, OUTPUT); // LCD DB4 pinMode(5, OUTPUT); // LCD DB5 pinMode(6, OUTPUT); // LCD DB6 pinMode(7, OUTPUT); // LCD DB7 pinMode(8, OUTPUT); // LCD DB0 <- アサイン注意 pinMode(9, OUTPUT); // LCD DB1 <- アサイン注意 pinMode(10, OUTPUT); // LCD E1 pinMode(11, OUTPUT); // LCD E2 pinMode(12, OUTPUT); // LCD RS E1_OFF; RS_CMD; LcdInit(); if(TST_SW) { delay(500); SelArea = 0; // E1 WriteData('A'); WriteData('R'); WriteData('E'); WriteData('A'); WriteData('1'); WriteData(' '); SelArea = 1; // E2 WriteData('A'); WriteData('R'); WriteData('E'); WriteData('A'); WriteData('2'); WriteData(' '); SelArea = 2; // E1,E2 WriteData('A'); WriteData('R'); WriteData('E'); WriteData('A'); WriteData('1'); WriteData('&'); WriteData('2'); } } // ----------------------------------- // メインループ // ----------------------------------- void loop(void) { } // ----------------------------------- // スレーブ受信ハンドラ // ----------------------------------- void hSlvRcv(int cnt) { int i; for(i = 0; i < cnt; i+=2) { Cmd = Wire.read(); Data = Wire.read(); writeCmd(); } } // ----------------------------------- // コマンド書き込み(I2Cコマンド処理) // ----------------------------------- void writeCmd(void) { switch(Cmd) { case 0x00: // LCDコマンド WriteCmd(Data); break; case 0x80: // LCDデータ WriteData(Data); break; case 0xFF: // エリア設定コマンド SelArea = Data; break; } } // ----------------------------------- // LCD初期化 (8ビットモード) // ----------------------------------- void LcdInit(void) { SelArea = 2; // E1,E2 delay(15); WriteCmd(0x38); // function set delay(5); WriteCmd(0x38); // delay(5); WriteCmd(0x38); // delay(5); WriteCmd(0x38); // delay(5); WriteCmd(0x01); // clear delay(5); WriteCmd(0x06); // entry mode set delay(5); WriteCmd(0x0C); // display on/off control delay(5); WriteCmd(0x1C); // cursor/display shift delay(5); WriteCmd(0x38); // function set delay(5); WriteCmd(0x02); // home delay(5); } // ----------------------------------- // LCDデータ ライト // ----------------------------------- void WriteData(byte dat) { RS_DATA; POut8bit(dat); E_Pulse(); } // ----------------------------------- // LCDコマンド ライト // ----------------------------------- void WriteCmd(byte dat) { RS_CMD; POut8bit(dat); E_Pulse(); } // ----------------------------------- // LCDデータポート 8ビット出力 // ----------------------------------- void POut8bit(byte dat) { byte reg; // LCDデータ8ビット出力 reg = PORTD & 0x03; // RD0, RD1以外をマスク reg |= (dat & 0xFC); // d7~d2をマージ PORTD = reg; // 書き戻し reg = PORTB & 0xFC; // RB7~RB2以外をマスク reg |= (dat & 0x03); // d1,d0をマージ PORTB = reg; // 書き戻し } // ----------------------------------- // Eパルス出力 // ----------------------------------- void E_Pulse(void) { E1_OFF; E2_OFF; delayMicroseconds(1); if(SelArea == 0) { // エリア0 E1_ON; } else if(SelArea == 1) { // エリア1 E2_ON; } else { // エリア0,1同時 E1_ON; E2_ON; } delayMicroseconds(1); E1_OFF; E2_OFF; delayMicroseconds(100); }
26~33行目はLCDの制御信号を切り替えるマクロです。
60~64行目で前回と同様、テスト表示切り替え用ジャンパ用にA3をディジタル入力ポートに再設定してプルアップを有効にしています。
67行目でI2Cスレーブに設定しています。スレーブアドレスは0×30としています。
68行目でI2Cでスレーブ受信したときに呼び出されるハンドラ関数を定義しています。
72~83行目は使用するディジタルポートを出力に設定しています。
90~116行目はジャンパがショートされていたときのテスト表示の処理です。エリア0、エリア1それぞれに文字列を表示し、最後に両エリア同時に文字列を表示させています。
144行目からの”writeCmd()”は前回から拡張されて、エリア設定用に0xFFのコマンドが追加されています。1バイト目(“Cmd”)が0xFFのときは、2バイト目(“Data”)はエリア番号となっています。このコマンドはグローバル変数の”SelArea”を書き換えます。
235行目のEパルスの処理がE1、E2、E1とE2同時の3通りの動作になっています。グローバル変数の”SelArea”で切り替わります。
●I2C化コントロール・プログラム ダウンロード
I2C化ファームウェア(40文字×4行専用) ZIPファイルI2CLcdCtrl404
●WSN318
このボードは40文字×4行のC-51849にも対応しています。ファームウェアは先に説明したI2CLcdCtrl404 がそのまま使えます。
●40文字×4行LCD 接続例
次の写真は40文字×4行のC-51849をWSN318に接続したときの様子です。WSN319とWSN283も接続してあります。I2C化のファームウェアを書き込んだ直後のもので、電源はWSN283のUSBバス電源で作動しています。赤い線はBL-とGNDを接続するもので、このようにすると、WSN318内部で5Vが抵抗器を通してBL+に接続されているため、LCDのバックライトが点灯します。
●電源投入時のテスト表示
JPをショートした状態で電源を入れるとテスト文字列が表示されます。基板単体で表示確認できます。画面をクリアすれば、そのまま通常使用ができます。
次回はLiquidCrystalとほぼ互換性のあるドライバ(ライブラリ)を説明し、そのあと、実際の使い方など説明します。
Arduinoを使ったLCDや7セグメントLEDのI2C化の記事は書籍「Arduino実験キットで楽ちんマイコン開発」でも取り扱っています。なお、同書籍では上記写真のように試作機をブレッドボードで製作しましたが、現在は次のような専用の小型基板を用意しています。それぞれ、Arduinoを専用コントローラとして使っていますが、プログラムは通常のArduinoとして作成し、そのまま作動します。
参考文献