LCD1602Aを使っていろいろ遊んでみます。
ユーザ定義文字を使う
LiquidCrystal.h に実装されていない機能として、ユーザ定義文字を実験してみます。
文字定義の方法
コマンドとして(RS=LOWで)、二進数で01xxxxxxを送信すると、アドレスカウンタにCG RAM内のアドレスがセットされます。これに続いてデータ(RS=HIGHで)文字パターンを送信すればユーザ定義文字を定義することができます。
文字パターン

この図のように、1バイトが横1行分のパターンを表しています。一番右のドットが第0ビット、左に向かって第1ビット、第2ビット…となり、一番左のドットは第4ビットです。図の黒マスで表現されているドットを1、白マスで表現されているドットを0とした2進数値が、その行の値です。ただし文字は5×7ドットのため、各行の第5~第7ビットは常に0となります。1文字は8バイトで構成されますが、最下行はカーソルが使用するため、使用しない(データ=0x00とする)ことが推奨されています。
CG RAMアドレス
ユーザ定義文字のための記憶領域 CG RAM は、1文字あたり8バイト×8文字=64バイト確保されています。また文字コードは0~7が使用可能です。文字コードとアドレスの対応は以下の通りです。
文字コード(16進数) | アドレス(16進数) |
---|---|
0x00 | 0x00 |
0x01 | 0x08 |
0x02 | 0x10 |
0x03 | 0x18 |
0x04 | 0x20 |
0x05 | 0x28 |
0x06 | 0x30 |
0x07 | 0x38 |
プログラム
それでは、ユーザ定義文字を試してみましょう。トランプの『♡♢♤♧』を定義・表示するプログラムです。
int rsPin = 2, enPin = 3;
int dataPin[4] = {4, 5, 6, 7};
uint8_t chrPattern[4][8]={
{0B00000,0B00000,0B01010,0B11111,0B11111,0B01110,0B00100,0B00000},
{0B00000,0B00000,0B00100,0B01110,0B11111,0B01110,0B00100,0B00000},
{0B00000,0B00100,0B01110,0B11111,0B11111,0B00100,0B01110,0B00000},
{0B00000,0B01110,0B01110,0B11111,0B11111,0B00100,0B01110,0B00000}
};
// 4bitデータを送信
void send4bits(int value){
digitalWrite(enPin, HIGH); // あらかじめ EN を HIGH にしておく
// 4bitをデータバスにセット
for(int i=0; i<4; i++){
digitalWrite(dataPin[i], (value >> i) & 0x01);
}
delayMicroseconds(4);
digitalWrite(enPin, LOW); // EN の立ち下がりでデータが取り込まれる
delayMicroseconds(1);
}
// 8bitデータをコマンドとして送信
void sendCommand(int value){
digitalWrite(rsPin, LOW); // コマンドとして送信するときは RS=LOW
send4bits(value >> 4); // 上位4bitを先に送る
send4bits(value & 0x0f); // 下位4bitを後に送る
delayMicroseconds(40);
}
// 8bitデータをデータとして送信
void sendData(int value){
digitalWrite(rsPin, HIGH); // データとして送信するときは RS=HIGH
send4bits(value >> 4); // 上位4bitを先に送る
send4bits(value & 0x0f); // 下位4bitを後に送る
}
// ユーザ定義文字の定義
void defChar(uint8_t *pattern,int code){
sendCommand(0x40 | (code*8)&0x3f);
for(int i=0; i<8; i++){
sendData(pattern[i]);
}
}
// LCDの初期設定
void lcdInit(){
digitalWrite(rsPin, LOW); // あらかじめ RS を LOW にセットしておく
delay(50); // 仕様だと『VCCが4.5Vに達してから40ms待つ』だがVCCの監視ができないので余裕を見て50ms待つ
send4bits(0x3); // 0b0011を出力
delayMicroseconds(4100); // 4.1ms待つ
send4bits(0x3); // 0b0011を出力
delayMicroseconds(100); // 100μs待つ
send4bits(0x3); // 0b0011を出力
delayMicroseconds(40); // 40μs待つ
send4bits(0x2); // 4bit出力モードに切り替え
delayMicroseconds(40); // 40μs待つ
sendCommand(0x28); // ファンクションセット、4bitモード、2行LCD
sendCommand(0x08); // 表示オフコマンド、カーソルもブリンクもオフ
sendCommand(0x01); // 表示クリアコマンド
delayMicroseconds(1640); // 表示クリアには1.64msほど時間がかかる
sendCommand(0x06); // エントリーモードセット、AC++、シフトなし
sendCommand(0x0c); // 表示オンコマンド
}
void setup() {
// LCDに接続されている端子をすべて出力に設定
pinMode(rsPin, OUTPUT);
pinMode(enPin, OUTPUT);
for(int i=0; i<4; i++){
pinMode(dataPin[i], OUTPUT);
}
// LCDに初期化コマンドを送信する
lcdInit();
for(int i=0; i<4; i++){
defChar(chrPattern[i],i);
}
// 文字列表示テスト
sendCommand(0x0|0x80);
sendData(0);
sendData(1);
sendData(2);
sendData(3);
}
void loop() {
}
プログラムの解説
文字パターンの定義
uint8_t chrPattern[4][8]={
{0B00000,0B00000,0B01010,0B11111,0B11111,0B01110,0B00100,0B00000},
{0B00000,0B00000,0B00100,0B01110,0B11111,0B01110,0B00100,0B00000},
{0B00000,0B00100,0B01110,0B11111,0B11111,0B00100,0B01110,0B00000},
{0B00000,0B01110,0B01110,0B11111,0B11111,0B00100,0B01110,0B00000}
};
四文字の文字パターンを定義する配列変数 chrPattern[4][8] を宣言しています。順にハート、ダイヤ、スペード、クラブを表しています。なお、0Bxxxxxというのは2進数表記です。
コマンド送信関数 sendCommand()
// 8bitデータをコマンドとして送信
void sendCommand(int value){
digitalWrite(rsPin, LOW); // コマンドとして送信するときは RS=LOW
send4bits(value >> 4); // 上位4bitを先に送る
send4bits(value & 0x0f); // 下位4bitを後に送る
delayMicroseconds(40);
}
LCDにコマンドを送信する関数を作りました。RS=LOWにしてから、引数で与えられた値を上位4bit/下位4bitの2回にわけて送信しています。送信後はコマンド実行時間40μsだけウェイトを入れています。
画面クリアなど一部の実行時間の長いコマンドについては、別にウェイトを入れる必要があります。
データ送信関数 sendData()
// 8bitデータをデータとして送信
void sendData(int value){
digitalWrite(rsPin, HIGH); // データとして送信するときは RS=HIGH
send4bits(value >> 4); // 上位4bitを先に送る
send4bits(value & 0x0f); // 下位4bitを後に送る
}
LCDにデータを送信する関数を作りました。RS=HIGHにしてから、引数で与えられた値を上位4bit/下位4bitの2回にわけて送信しています。
ユーザ定義文字 defChar()
// ユーザ定義文字の定義
void defChar(uint8_t *pattern,int code){
sendCommand(0x40 | (code*8)&0x3f);
for(int i=0; i<8; i++){
sendData(pattern[i]);
}
}
引数の *pattern は1文字分のパターンの配列、codeは文字コードです。
まず文字コードから計算した CG RAM のアドレスを設定するコマンドを送信し、その後8バイトのパターンデータを送信します。
初期設定 lcdInit()
// LCDの初期設定
void lcdInit(){
digitalWrite(rsPin, LOW); // あらかじめ RS を LOW にセットしておく
delay(50); // 仕様だと『VCCが4.5Vに達してから40ms待つ』だがVCCの監視ができないので余裕を見て50ms待つ
send4bits(0x3); // 0b0011を出力
delayMicroseconds(4100); // 4.1ms待つ
send4bits(0x3); // 0b0011を出力
delayMicroseconds(100); // 100μs待つ
send4bits(0x3); // 0b0011を出力
delayMicroseconds(40); // 40μs待つ
send4bits(0x2); // 4bit出力モードに切り替え
delayMicroseconds(40); // 40μs待つ
sendCommand(0x28); // ファンクションセット、4bitモード、2行LCD
sendCommand(0x08); // 表示オフコマンド、カーソルもブリンクもオフ
sendCommand(0x01); // 表示クリアコマンド
delayMicroseconds(1640); // 表示クリアには1.64msほど時間がかかる
sendCommand(0x06); // エントリーモードセット、AC++、シフトなし
sendCommand(0x0c); // 表示オンコマンド
}
処理内容は前回のものと同じですが、今回作成した sendCommand() 関数を使って書き換えました。後半の行数がだいぶ減ってスッキリしています。
ユーザ定義文字の定義および表示
void setup() {
// LCDに接続されている端子をすべて出力に設定
pinMode(rsPin, OUTPUT);
pinMode(enPin, OUTPUT);
for(int i=0; i<4; i++){
pinMode(dataPin[i], OUTPUT);
}
// LCDに初期化コマンドを送信する
lcdInit();
for(int i=0; i<4; i++){
defChar(chrPattern[i],i);
}
// 文字列表示テスト
sendCommand(0x0|0x80);
sendData(0);
sendData(1);
sendData(2);
sendData(3);
}
pinMode()関数でArduinoの端子を出力に設定するところは同じですが、その後defChar()を呼び出してユーザ定義文字のデータをLCDに送信しています。
setCommand(0x0|0x80) は画面左上隅を表す DD RAM アドレスをアドレスカウンタにセットするコマンドの送信です。それに続く sendData(0) ~ sendData(3) が、それぞれ文字コード0~3の表示です。アドレスカウンタは自動的にインクリメントされるので、先頭位置のアドレスをセットした後は sendData()コマンドを文字数分くりかえせば自動的に文字が並んで表示されます。
実行

このとおり自分で定義した文字が表示されています。さすがに5×7ドットではスペードとクラブが難しいですね…。
まとめ
- HD44780は、8文字のユーザ文字を定義することが出来る。
コメント