I2CインターフェースLCDモジュール用のライブラリを作る(4)ライブラリ化(3)
■複数のLCDに対応できるように
ライブラリ内で各モジュールを区別するために、次の変数を利用します。
◆_addr i2cインターフェースのデバイス・アドレス
第一の引数としてi2cインターフェースのデバイス・アドレスとしてACM1602の場合0x50を、AQM1602およびAQM0802の場合0x3Eを設定します。
◆v5or33 電源電圧の設定
AQM0802、AQM1602は5V電源のときBON=0、3.3V電源のときBON=1に拡張命令で設定します。
◆_br 輝度の設定値
AQM0802、AQM1602はLCDモジュールの輝度をこの変数に設定します。デフォルトでは5V電源のときは0x13に、電源電圧が3.3Vときは0x23に設定しています。コンストラクタ関数の引数として任意の値を設定することもできます。
ACM1602の使い方は本Webの次のページに詳しく説明していますので、そちらも参照してください。
http://www.denshi.club/make/2016/05/arduinolcd8.html
●コマンドおよびデータの書き込み方法
データ、コマンドの書き込みは、次に示すように、
スレーブ・アドレス 制御バイト データ・バイト |
原則このパターンを繰り返してコマンド、データをLCDモジュールに書き込みます。書き込み処理だけでLCDモジュールの読み込みはできません。
制御バイトは、次に書き込むデータがコマンドかデータかを示すビット(RS)が用意されています。そのビットが0の場合は次に送信されるデータはLCDモジュールに対するコマンドとなります。RSビットが1の場合、次のデータはLCDモジュールに表示するデータ、新たなフォントを作成するためのデータです。
●制御バイトはACM1602とAQMシリーズでは少し異なる
ACM1602のRSビットはD7に割り当てられていて、コマンドのときは0x00、データのときは0x80となります。
AQMシリーズではRSビットはD6に割り当てられ、コマンドのときは0x00、データのときは0x40となります。D7ビットはCoビットとなります。このビットが1のときは続けて制御バイト、データ・バイトを送信します。今回はこの機能は使用しません。Coは常時0で運用します。
データ送信の制御バイトは変数 _cltdataとして、
- ACM1602の場合 _cltdataに0x80をセット
- AQMシリーズの場合 _cltdataに0x40をセット
この処理を行う関数を次に示すように作りました。
byte i2clcd::chkcltdata(byte adr) {
if (adr == 0x50) {
return 0x80;
}
else {
return 0x40;
}
この関数は、I2CインターフェースのLCDモジュールのデバイス・アドレスを引数として、それぞれのデバイスに対応したデータ書き込みの制御コードを関数値として戻します
ライブラリ内で共通に参照できるデータ書き込み用の変数 _cltdataにこの関数値を代入します。以後このデータ書き込み用の変数を用いてデータを書き込みます。
_cltdata = chkcltdata(i2cadr);
●コンストラクタの中でデバイスに応じた変数の設定を行う
◆引数のないコンストラクタ
モジュールはACM1602で、デバイスのアドレスは0x50、データ書き込みの制御データは0x80、あとの輝度_br、電源は設定の必要はないがAQMシリーズの3V電源に設定してあります。Wireライブラリをスタートします。
i2clcd::i2clcd() {
_addr = 0x50;
_cltdata = 0x80;
_br =0x13;
_v5or33 = 3;
Wire.begin();
}
◆アドレスを指定したコンストラクタ
アドレスを設定し、アドレスから_cltdataに適切な制御データを設定し、輝度、電圧はデフォルト値を設定します。
i2clcd::i2clcd(byte i2cadr) {
_addr = i2cadr;
_cltdata = chkcltdata(i2cadr);
_br = 0x13;
_v5or33 = 3;
Wire.begin();
}
◆アドレスと電圧を指定したコンストラクタ
前項と同様に、アドレスとデータ書き込みの制御コードを設定し、電源電圧に応じた輝度を設定します。
i2clcd::i2clcd(byte i2cadr,byte v5or33) {
_addr = i2cadr;
_cltdata = chkcltdata(i2cadr);
_v5or33 = v5or33;
if (_v5or33 == 5) {
_br = 0x23;
}
else {
_br =0x13;
}
Wire.begin();
}
◆アドレス、電圧、輝度を指定したコンストラクタ
引数で指定されたアドレス、輝度、電圧とアドレスにより選択された書き込み制御データが設定されます。
i2clcd::i2clcd(byte i2cadr,byte v5or33,byte lbr){
_addr = i2cadr;
_cltdata = chkcltdata(i2cadr);
_br = lbr;
_v5or33 = v5or33;
Wire.begin();
}
●データの書き込み関数
_cltdataには、そのとき利用されているモジュールに応じた適切なデータ書き込み制御コードがセットされているので、この関数でACM1602、AQMシリーズともにデータの書き込みが行われます。
int i2clcd::i2cwritedata(byte data){
Wire.beginTransmission(_addr);
Wire.write(_cltdata);
Wire.write(data);
return Wire.endTransmission();
}
◆初期化処理
拡張コマンドで輝度と電圧、クロックに関する設定を行う以外は、初期化のコマンドは同じとなります。そのため、基本設定を行った後、AQMシリーズのアドレス0x3Eの場合拡張コマンドで必要な設定を行います。その後クリア、表示をONにして初期化を終えます。
void i2clcd::init_lcd() {
byte bon = 0x04;
byte powercmd = 0;
delay(145);
i2cwritecmd(0x38); delay(1); // データを8ビット単位で受け渡し2行表示
i2cwritecmd(0x38); delay(1); // 念のための同じ設定を繰り返す
if (_addr == 0x3E) { // AQMシリーズの拡張コマンドの設定
byte contrast = (0x70 | (_br & 0x0F));
if (_v5or33 == 5) {
bon = 0x00;
}
else {
bon = 0x04;
}
powercmd = (0x50 | (bon | (_br >> 4)));
i2cwritecmd(0x39); delay(1);
i2cwritecmd(0x14); delay(1);
i2cwritecmd(contrast); delay(1);
i2cwritecmd(powercmd); delay(2);
i2cwritecmd(0x6C); delay(300);
i2cwritecmd(0x38); delay(1);
}
i2cwritecmd(0x01); delay(2);
i2cwritecmd(0x0C); delay(2);
}
●文字列の表示
今までのi2cprint( String pdata)関数は、LCDモジュールへの書き込みの関数はRSビットの指定のバイトと表示データを指定していました。この処理ではコマンドを書き込む必要はないので、i2cwritedata( )関数を利用しました。
void i2clcd::i2cprint( String pdata) {
int n = pdata.length();
for (int i = 0; i < n; i = i + 1) {
i2cwritedata( pdata.charAt(i));
delay(1);
}
}
●テスト・プログラム
テスト・プログラムは、ACM1602のためのインスタンスはalcdを作り、AQM1602用にはqlcdのインスタンスを作りました。ACM1602とAQM1602が異なったI2Cのデバイス・アドレスを持っているので、複数のインスタンスを作成することができます。各モジュールは同じアドレスとなるので、同じタイプの複数のモジュールを接続することはできません。
このテスト・プログラムの実行結果は、次のようになります。
今回使用したi2clcd.hとi2clcd.cppを次に示します。
●i2clcd.h
#ifndef i2clcd_h
#define i2clcd_h
#include "Arduino.h"
#define CMD 0x00
class i2clcd
{
public:
i2clcd();
i2clcd(byte i2cadr);
i2clcd(byte lbr, byte i2cadr);
i2clcd(byte v5or33, byte lbr, byte i2cadr);
int i2cwritecmd(byte cmd);
int i2cwritedata(byte data);
int i2cwritedsd(byte cltd, byte data);
void lcdcu_set(int x, int y);
void lcdclear();
void lcdhome();
void dsift_l();
void dsift_r();
void init_lcd();
void init_lcd2();
void i2cprint( String pdata);
private:
byte _addr;
byte _v5or33;
byte _br;
byte _cltdata;
byte chkcltdata(byte adr);
};
#endif
次回、ライブラリの修正方法、テスト方法の様子を示します。
●i2clcd.cpp
#include "i2clcd.h"
#include "Arduino.h"
#include "Wire.h"
i2clcd::i2clcd() {
_addr = 0x50;
_cltdata = 0x80;
_br =0x13;
_v5or33 = 3;
Wire.begin();
}
i2clcd::i2clcd(byte i2cadr) {
_addr = i2cadr;
_cltdata = chkcltdata(i2cadr);
_br = 0x13;
_v5or33 = 3;
Wire.begin();
}
i2clcd::i2clcd(byte i2cadr,byte v5or33) {
_addr = i2cadr;
_cltdata = chkcltdata(i2cadr);
_v5or33 = v5or33;
if (_v5or33 == 5) {
_br = 0x23;
}
else {
_br =0x13;
}
Wire.begin();
}
i2clcd::i2clcd(byte i2cadr,byte v5or33,byte lbr){
_addr = i2cadr;
_cltdata = chkcltdata(i2cadr);
_br = lbr;
_v5or33 = v5or33;
Wire.begin();
}
byte i2clcd::chkcltdata(byte adr) {
if (adr == 0x50) {
return 0x80;
}
else {
return 0x40;
}
}
int i2clcd::i2cwritecmd(byte cmd){
Wire.beginTransmission(_addr);
Wire.write((byte)0x00);
Wire.write(cmd);
return Wire.endTransmission();
}
int i2clcd::i2cwritedata(byte data){
Wire.beginTransmission(_addr);
Wire.write(_cltdata);
Wire.write(data);
return Wire.endTransmission();
}
void i2clcd::lcdcu_set(int x, int y) {
byte ca = (x + y * 0x40) | (0x80); i2cwritecmd(ca);
}
void i2clcd::lcdclear() {
i2cwritecmd(0x01); delay(1);
}
void i2clcd::lcdhome() {
i2cwritecmd(0x02); delay(1);
}
void i2clcd::dsift_l() {
i2cwritecmd(0x1C);
}
void i2clcd::dsift_r() {
i2cwritecmd(0x18);
}
void i2clcd::init_lcd() {
byte bon = 0x04;
byte powercmd = 0;
delay(145);
i2cwritecmd(0x38); delay(1); // バイト・データを8ビット単位で受け渡しする設定
i2cwritecmd(0x38); delay(1); // 念のための同じ設定を繰り返す
if (_addr == 0x3E) {
byte contrast = (0x70 | (_br & 0x0F));
if (_v5or33 == 5) {
bon = 0x00;
}
else {
bon = 0x04;
}
powercmd = (0x50 | (bon | (_br >> 4)));
i2cwritecmd(0x39); delay(1);
i2cwritecmd(0x14); delay(1);
i2cwritecmd(contrast); delay(1);
i2cwritecmd(powercmd); delay(2);
i2cwritecmd(0x6C); delay(300);
i2cwritecmd(0x38); delay(1);
}
i2cwritecmd(0x01); delay(2);
i2cwritecmd(0x0C); delay(2);
}
void i2clcd::i2cprint( String pdata) {
int n = pdata.length();
for (int i = 0; i < n; i = i + 1) {
i2cwritedata( pdata.charAt(i));
delay(1);
}
}
(2017/10/15 V1.0)
<神崎康宏>