I2C接続AQMシリーズのキャラクタ表示LCDをMicro:bitで使う (2) AQM1602

広い表示エリアに情報をたくさん表示する

 前回のAQM0802とほぼ同じく使えるAQM1602は、1行に16文字、2行表示のキャラクタLCD表示器です。Micro:bitのI2Cインターフェースにつないで文字を表示します。Micro:bitのArduino IDE開発環境は前回の記事を参照ください。

 Micro:bitにはアナログ入力が6本あります。6か所の電圧を読み取り、LCDに表示するスケッチを作ります。

AQM1602の特徴

 I2C通信のスレーブ・アドレスは0x3eです。秋月電子通商でリード線のピッチ変換基板のボードは、潔く、4本しかピンが出ていません。動作電源電圧は3.1~5.5Vです。USBケーブルでPCとつないだとき、3V端子には3.15~3.19Vが出ていました。回路図を見ると3.3VのLDOレギュレータが使われています。

 Micro:bitとは、AQM0802と同様にI2Cは、SCLとSDAの二つの信号線と電源、合計4本の配線をします。

Micro:bitの端子 AQM1602の端子
3V VDD
0V GND
SCL SCL
SDA SDA

六個の電圧源を用意

 アナログからディジタルに変換するA-Dコンバータは、基準電圧を元に量子化します。マイコンのA-Dコンバータの入力上限は基準電圧です。Micro:bitはたぶん電源の3.3Vです。オリジナルのArduinoで基準電圧は、

  • 電源電圧(5V)
  • 内部の基準電圧1.1V
  • 外部入力

の3通りのうち一つを設定できました。Micro:bitに使われているマイコンはCortex-M0です。マイコン自体、基準電圧入力Vref端子をもっているようですが、外部バスには出ていないようです。

 そこで、内部基準電圧が使えるかどうかを確認しました。

analogReference(DEFAULT);
Serial.println(analogRead(A0)/1024.0*1.1);
analogReference(INTERNAL);
Serial.println(analogRead(A0)/1024.0*1.1);

 コンパイル時にエラーになったので、電源の3.3V以外、基準電圧が使えないようです。

 次の分圧回路で、任意の電圧を複数作りました。

 製作したボードです。

 中央上部に3.3VとGNDのピン、左から、抵抗分圧の三つの電圧、半固定抵抗の二つの電圧、ボリュームによる分圧された電圧、合計六つの電圧が出ています。このいろいろな電圧が出ている端子をMicro:bitのアナログ入力につなぎます。

 Micro:bitの説明書には、3.3Vという数字は出てきません。常に3Vという表記です。外部電池端子にはつながる乾電池が2個なので、3.0V前後の電圧が供給されます。エネループを使えば約2.4Vです。マイコンとしては動作しますが、基準電圧を3.3Vだと考えると、10%以上の誤差が出てしまいます。

テスト・プログラム

 まず、6か所からのディジタル値を読み出します。A-Dコンバータは、変換する場所は一つで、入力にマルチプレクサと呼ばれるアナログ切り替えスイッチが入っています。必要に応じて、チャネルを切り替えますが、切り替え時間が必要です。連続して、analogRead()できるかを確認したところ、問題ないことがわかりました。

 10ビットの内蔵A-Dコンバータなので、2^10-1=1023 2^10=1024で割って、基準電圧を掛けます。基準電圧用変数VrefはDMMで測った値を入れます。

(2020/05/07)1023は間違いなので、1024に変更した。下記のスケッチも修正したが、実行結果は変更していない

 このプログラムは、A5入力の読みを失敗しています。A0からA4までは、ピン番号0から4まで一致していますが、A5は10番ピンです。

float Vref = 3.19;

void setup() {
Serial.begin(9600);
}

void loop() {
Serial.println("start ");
int analogData[6];
int n=0;
while(n<6) {
analogData[n]=analogRead(n); // 0~5ピンのアナログ入力(0~1023のディジタル値)を配列に読み込む
n++;
}
n=0;
while (n<6) {
Serial.print(analogData[n]);Serial.print(" --> ");
Serial.print((float)analogData[n]/1024*Vref);Serial.print("V ,");
n++;
}
Serial.println(" ");
delay(2000);
}

LCDに表示

 前回のAQM0802と同じWireライブラリを使って、LCDへテスト・データ(ABC)を表示します。

#include <Wire.h>
unsigned char lcd_address = 0x3e;

int i2cwritecmd(byte cmd) {
Wire.beginTransmission(lcd_address);
Wire.write((byte)0x00);
Wire.write(cmd);
return Wire.endTransmission();delay(20);
}

int i2cwritedata(byte data) {
Wire.beginTransmission(lcd_address);
Wire.write(0x40);
Wire.write(data);
return Wire.endTransmission();delay(20);
}

void init_lcd() {
delay(145);
i2cwritecmd(0x38);delay(10);
i2cwritecmd(0x39);delay(10);
i2cwritecmd(0x14);delay(10);
i2cwritecmd(0x73);delay(10);
i2cwritecmd(0x56);delay(10); // 3.3V
i2cwritecmd(0x6c);delay(300);
i2cwritecmd(0x38);delay(10);
i2cwritecmd(0x0c);delay(20);
i2cwritecmd(0x01);delay(20);
}

void setup() {
Wire.begin();
init_lcd();
}

void loop() {
i2cwritedata(0x41); // A
i2cwritedata(0x42); // B
i2cwritedata(0x43); // C
delay(1000);
}

 6入力、LCDへ電圧を表示するスケッチです。シリアルモニタにも読み取ったデータと電圧を表示します。

#include <Wire.h>
unsigned char lcd_address = 0x3e;
float Vref = 3.19;

int i2cwritecmd(byte cmd) {
Wire.beginTransmission(lcd_address);
Wire.write((byte)0x00);
Wire.write(cmd);
return Wire.endTransmission();
}

int i2cwritedata(byte data) {
Wire.beginTransmission(lcd_address);
Wire.write(0x40);
Wire.write(data);
return Wire.endTransmission();
}

void lcdcu_set(int x, int y) { // xは桁数、0から16が指定できる。yは行数で0が1行目、1が2行目
byte ca = (x + y * 0x40) | (0x80); i2cwritecmd(ca);
}

void lcdclear() {
i2cwritecmd(0x01);delay(1);
}

void i2cprint( String pdata) {
int n = pdata.length();
for (int i = 0; i < n; i = i + 1) {
i2cwritedata(pdata.charAt(i));
delay(1);
}
}

void init_lcd() { // LCDの初期化
delay(145);
i2cwritecmd(0x38);delay(1);
i2cwritecmd(0x39);delay(1);
i2cwritecmd(0x14);delay(1);
i2cwritecmd(0x73);delay(1);
i2cwritecmd(0x56);delay(1); // 3.3V
i2cwritecmd(0x6c);delay(300);
i2cwritecmd(0x38);delay(1);
i2cwritecmd(0x0c);delay(2);
i2cwritecmd(0x01);delay(2);
}

void setup() {
Wire.begin();
init_lcd();
i2cprint(String("Start"));
Serial.begin(9600);
delay(1000);
}

void loop() {
Serial.println("start ");
int analogData[6];
int n=0;
while(n<5) {
analogData[n]=analogRead(n); // A0,A1,A2,A3,A4
n++;
}
analogData[5]=analogRead(A5); // P10=A5
n=0;
while (n<6) {
Serial.print(analogData[n]);Serial.print(" --> ");
Serial.print((float)analogData[n]/1024*Vref);Serial.print("V ,");
n++;
}
Serial.println(" ");
lcdclear();
lcdcu_set(0,0);i2cprint("0=");
i2cprint(String((float)analogData[0]/1024*Vref));
lcdcu_set(7,0);
i2cprint(String((float)analogData[1]/1024*Vref));
lcdcu_set(12,0);
i2cprint(String((float)analogData[2]/1024*Vref));
lcdcu_set(0,1);
i2cprint(String((float)analogData[3]/1024*Vref));
lcdcu_set(5,1);
i2cprint(String((float)analogData[4]/1024*Vref));
lcdcu_set(10,1);i2cprint("6=");
i2cprint(String((float)analogData[5]/1023*Vref));
delay(1000);
}

 シリアルプロッタの様子です。A5の入力はボリュームを付けたので、上げたり下げたりを繰り返しました。

 このときの電圧をDMMで測りました。差は約1%に収まっています。

入力ポート A0 A1 A2 A3 A4 A5
表示値 [V] 1.58 0.30 2.90 2.87 2.94 2.13
測定値 [V] 1.573 0.287 2.91 2.89 2.92 2.11