汎用キャラクタLCDのI2C化(3) 40文字×4行LCD、WSN318

今回は、40文字×4行LCD C-51849NFJをI2C化します。

●ブレッドボード試作回路

この回路もarduinoでLCDを点灯させるだけの単純なものです。回路的には「40文字×4行LCDモジュールを使ってみる」でブレッドボードで製作したものとほとんど同じです。

lcd404-6

次の写真は「40文字×4行 LCDモジュールを使ってみる」で掲載したものですが、これにジャンパとI2C信号を接続すれば、同等となります。

lcd404-1

●エリア設定コマンドの追加

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のバックライトが点灯します。

img_318_319_283-2

●電源投入時のテスト表示

JPをショートした状態で電源を入れるとテスト文字列が表示されます。基板単体で表示確認できます。画面をクリアすれば、そのまま通常使用ができます。

img_318_319_283-3

次回はLiquidCrystalとほぼ互換性のあるドライバ(ライブラリ)を説明し、そのあと、実際の使い方など説明します。


Arduinoを使ったLCDや7セグメントLEDのI2C化の記事は書籍「Arduino実験キットで楽ちんマイコン開発」でも取り扱っています。なお、同書籍では上記写真のように試作機をブレッドボードで製作しましたが、現在は次のような専用の小型基板を用意しています。それぞれ、Arduinoを専用コントローラとして使っていますが、プログラムは通常のArduinoとして作成し、そのまま作動します。

参考文献

コメントは受け付けていません。