市販の液晶キャラクタディスプレイ(LCD)はマイコンから使いやすい表示器ですが,基本は8bitデータのパラレル入力です。
そのため出力ピンの少ない小さなマイコンでは接続しにくいので,自分なりに使いやすくしようとパラレル入力のLCDにI2CやUARTからの変換モジュールをATtiny1604を使って自作してきました。
今まで作ったモジュールは使ってしまったので,メモリは少ないですがピン数の同じATtiny404でまずはUART対応版から作ってみました。
UARTモジュール付きのLCDです。100均の名刺入れに入れてみました,
LCDはバックライト付きのSC1602BSLB(3.3V)で,表示データはATtiny202から送っています(^^)。

LCDとモジュールの構成です
モジュールはほぼATtiny404だけみたいですね(^^;;;;;。

モジュールは接続コネクタだけで固定しています,,,。

配線の概略図です。
LCDはHD44780(互換)コントローラで8bitパラレル入力です。
4bitモードで接続するので下位4bitの入力ピンは使用しません。
・レジスタセレクタ(RS):コマンドと表示データのレジスタを切り替えます
・リード/ライト(R/W):LOW固定で書き込みオンリーにしています
・データイネーブル(E):入力データをラッチします
・データ (DB4-DB7):8bitのデータを上位4bit,下位4bitの順に入力します

自作のモジュールなので複雑なことはせず,9600bps固定,また受信データは「どこ」に「何」を表示するかにしぼっています。
・カーソル位置の指定やコマンド:Serial.write()
・ASCII文字(7bit):Serial.print()またはSerial.write()
を使って普通に書き込めます。
というか,複雑なコマンドは覚えきれないので(^^;;;;;;。
上の写真の表示データを送信したATtiny202側のプログラムです。
モジュール側のATtiny404のプログラムです。
下に記したリンク先のATtiny1604用のものをそのまま持ってきただけで,まだまだ改良する点は多いと思いますが,まぁ動いてはいます(^^;;;;;;;;;;。
☆ LCDを扱う時に気を付けている事
・setupのLCDの初期化では何をやってるのか,という繰り返しがありますが,LCDコントローラを確実に8bitモードにセットしてから4bitモードにする定石となっています,,,,。
・コマンドを送った後のdelayはデータシートの数値通りきっちりとっておかないと動作しなかったり,不安定だったりしますね。
上のプログラムはプログラムメモリが4KBのATtiny404でも十分余裕があります。
データを受け取るところをI2C版にすればI2C入力で使えるので,次の1台はそうしてみようと思っています(^^)。
8ピンのマイコンでI2Cのセンサをつなぐ時などはディスプレイもI2Cだと助かりますよね。
また,自作のモジュールだとライブラリのインクルードもいらないのでメモリも助かる?気はします(^^)。
ま,市販でもI2Cでのシリアル入力機能を追加したものが多くみられます。ただインクルードしたライブラリでも最終的な動作はレジェンドICである日立のHD44780(互換)LCDコントローラ(パラレル入力)の様式で制御されているものが多いようですね。
制作記事のページとのリンクです。
・ライブラリなしでI2Cシリアル接続のキャラクタディスプレイを使う時のメモ
・ATtiny1604でパラレル接続のキャラクタLCDをUART通信化するモジュールを試作してみた
・安価なパラレル接続の16x2液晶キャラクタディスプレイに自作のI2Cモジュールを実装してみた
そのため出力ピンの少ない小さなマイコンでは接続しにくいので,自分なりに使いやすくしようとパラレル入力のLCDにI2CやUARTからの変換モジュールをATtiny1604を使って自作してきました。
今まで作ったモジュールは使ってしまったので,メモリは少ないですがピン数の同じATtiny404でまずはUART対応版から作ってみました。
UARTモジュール付きのLCDです。100均の名刺入れに入れてみました,
LCDはバックライト付きのSC1602BSLB(3.3V)で,表示データはATtiny202から送っています(^^)。

LCDとモジュールの構成です
モジュールはほぼATtiny404だけみたいですね(^^;;;;;。

モジュールは接続コネクタだけで固定しています,,,。

配線の概略図です。
LCDはHD44780(互換)コントローラで8bitパラレル入力です。
4bitモードで接続するので下位4bitの入力ピンは使用しません。
・レジスタセレクタ(RS):コマンドと表示データのレジスタを切り替えます
・リード/ライト(R/W):LOW固定で書き込みオンリーにしています
・データイネーブル(E):入力データをラッチします
・データ (DB4-DB7):8bitのデータを上位4bit,下位4bitの順に入力します

自作のモジュールなので複雑なことはせず,9600bps固定,また受信データは「どこ」に「何」を表示するかにしぼっています。
・カーソル位置の指定やコマンド:Serial.write()
・ASCII文字(7bit):Serial.print()またはSerial.write()
を使って普通に書き込めます。
というか,複雑なコマンドは覚えきれないので(^^;;;;;;。
上の写真の表示データを送信したATtiny202側のプログラムです。
// ATTiny 202 Serial test for ATtiny404 UART module for LCD
void setup(){
delay(1000); // waiting for LCD start
Serial.begin(9600); // UART 9600bps
Serial.write(0x80);Serial.write(0x01); // Clear Screen
delay(2);
Serial.write(0);Serial.write(3); // locate 0,3
Serial.print("ATtiny 404"); // disp data
Serial.write(1);Serial.write(1); // locate 1,1
Serial.print("UART LCD Test"); // disp data
}
void loop() {
// put your main code here, to run repeatedly:
}
モジュール側のATtiny404のプログラムです。
下に記したリンク先のATtiny1604用のものをそのまま持ってきただけで,まだまだ改良する点は多いと思いますが,まぁ動いてはいます(^^;;;;;;;;;;。
☆ LCDを扱う時に気を付けている事
・setupのLCDの初期化では何をやってるのか,という繰り返しがありますが,LCDコントローラを確実に8bitモードにセットしてから4bitモードにする定石となっています,,,,。
・コマンドを送った後のdelayはデータシートの数値通りきっちりとっておかないと動作しなかったり,不安定だったりしますね。
// LCD1602 Controll test Pro., ATtiny404 UART
#define DB7 A7
#define DB6 A6
#define DB5 A5
#define DB4 A4
#define _E A2
#define _RS A1
void setup() {
pinMode(DB7, OUTPUT );
pinMode(DB6, OUTPUT );
pinMode(DB5, OUTPUT );
pinMode(DB4, OUTPUT );
pinMode(_E, OUTPUT );
pinMode(_RS, OUTPUT );
delay (40); // Init. LCD
sendU4bit(0, 0x30); // Function Set 8bit mode, 1st
delayMicroseconds(38);
sendU4bit(0, 0x30); // Function Set 8bit mode, 2nd
delayMicroseconds(38);
sendU4bit(0, 0x30); // Function Set 8bit mode, 3rd
delayMicroseconds(38);
sendU4bit(0, 0x20); // Function Set 4bit mode
delayMicroseconds(38);
sendCommand(0x28); // 4bit mode & 2line=1, font=0
sendCommand(0x06); // Cursor move increment, Shift off
sendCommand(0x01); // Clear Display
delay (2);
sendCommand(0x0C); // Display On, Cursor off, Blink off
Serial.begin(9600);
}
void loop() {
byte recieveData1,recieveData2;
recieveData1=getOnebyte(); // Recieve One Byte
if (recieveData1<0x04){ // Locate Row Number
recieveData2=getOnebyte(); // Column Number
locate(recieveData1,recieveData2); // Set Locate
}else if (recieveData1>0x1F && recieveData1<0x80){ // Ascii
sendDisplay(recieveData1);
}else if (recieveData1==0x80){ // Command
recieveData2=getOnebyte();
sendCommand(recieveData2);
}else if (recieveData1==0xC0){ // Disp
recieveData2=getOnebyte();
sendDisplay(recieveData2);
}
}
byte getOnebyte(){
byte oneByte;
while (Serial.available() == 0){
}
oneByte=Serial.read();
return oneByte;
}
void locate(byte rowNumber, byte columnNumber){
byte ddramAddress;
switch (rowNumber) {
case 0:
ddramAddress=0;
break;
case 1:
ddramAddress=0x40;
break;
case 2:
ddramAddress=0x14;
break;
case 3:
ddramAddress=0x54;
break;
}
ddramAddress=(ddramAddress+columnNumber) | 0x80;
sendCommand(ddramAddress);
}
void sendCommand(byte cdData){
send8bit(0, cdData); // Resistor Select =0
delayMicroseconds(38);
}
void sendDisplay(byte cdData){
send8bit(1, cdData); // Resistor Select =1
delayMicroseconds(38);
}
void send8bit(byte RS, byte cdData){
sendU4bit(RS, cdData);
sendU4bit(RS, cdData*16);
}
void sendU4bit(byte RS, byte upper4bit){
digitalWrite(_RS, RS);
digitalWrite(_E, HIGH);
digitalWrite(DB7, bitRead(upper4bit,7));
digitalWrite(DB6, bitRead(upper4bit,6));
digitalWrite(DB5, bitRead(upper4bit,5));
digitalWrite(DB4, bitRead(upper4bit,4));
digitalWrite(_E, LOW);
}
上のプログラムはプログラムメモリが4KBのATtiny404でも十分余裕があります。
データを受け取るところをI2C版にすればI2C入力で使えるので,次の1台はそうしてみようと思っています(^^)。
8ピンのマイコンでI2Cのセンサをつなぐ時などはディスプレイもI2Cだと助かりますよね。
また,自作のモジュールだとライブラリのインクルードもいらないのでメモリも助かる?気はします(^^)。
ま,市販でもI2Cでのシリアル入力機能を追加したものが多くみられます。ただインクルードしたライブラリでも最終的な動作はレジェンドICである日立のHD44780(互換)LCDコントローラ(パラレル入力)の様式で制御されているものが多いようですね。
制作記事のページとのリンクです。
・ライブラリなしでI2Cシリアル接続のキャラクタディスプレイを使う時のメモ
・ATtiny1604でパラレル接続のキャラクタLCDをUART通信化するモジュールを試作してみた
・安価なパラレル接続の16x2液晶キャラクタディスプレイに自作のI2Cモジュールを実装してみた