まずは配線に悩む。
4bitモードを使うか、8bitモードを使うかだ。
やはり、ポートを節約するためには、4bitだろうか。
あとは、busyフラグをチェックするかどうか。
busyかどうかをチェックせずに、ウェイトでコマンド完了を待つ方式だと、R/WをGNDに落としてWrite固定でいいらしいけど、ここは正攻法でbusyフラグはチェックするようにしたいな。
となると、必要なピンは、RS、R/W、E、DB4〜DB7で、全部で7ピンか。
回路図はこんな感じで。
見にくいかも……あってるよな?
4bitモードでは、DB0〜DB3は使用しないので、オープンにしておく。
このあたりは、このページを参考に。
Eはプルダウンするべきらしい。
ちなみに、プルダウンしなかったら、起動時に行頭に一つスペースが入ったりしたけど、なんでだろう?
PD5が不定でも確実にLowであるべきということかな?
他はプルアップ抵抗が内蔵されているから問題ないとかいうのもぴんとこない。
もっとデジタル回路を勉強しないとダメか……。
Voは液晶の濃度調整を分圧でやってて、Vcc5Vの1/(10+1)の、約0.45Vがかかる。
これでちょうどいい濃度っぽい。
とりあえず配線はこれでOK。
動いた後の動作写真も載せておく。
まずは、includeに各種定数定義と、LEDでも使った待ち関数。
前回のLEDを取り外して、ポートDのみで全てが済むように配線したので、定義もポートDのみです。
そして、ポートDにおけるLCD接続先のビット定義と、データ部分を一気にマスクするための定義。
#include <avr/io.h> #include <util/delay.h> #define LCD_PORT PORTD // LCD表示に使用する出力レジスタ #define LCD_PIN PIND // LCD表示に使用する入力レジスタ #define LCD_DDR DDRD // LCD表示に使用する方向レジスタ #define LCD_D4 (1<<0) // D4ビット位置 #define LCD_D5 (1<<1) // D5ビット位置 #define LCD_D6 (1<<2) // D6ビット位置 #define LCD_D7 (1<<3) // D7ビット位置 #define LCD_E (1<<5) // Eビット位置 #define LCD_RW (1<<6) // R/Wビット位置 #define LCD_RS (1<<7) // RSビット位置 #define LCD_DATMASK 0x0F // データビットマスク void delay_ms( int time ) { // 指定ms分ループ while( time-- ){ _delay_ms( 1 ); } }
で、まずはLCDを初期化しなければならないわけだ。
色々なサイトを巡ってみても、初期化とBusyフラグチェックの2箇所に苦労してるっぽい。
ご多分に漏れず、結構な難関でした。
Lcd_initという初期化関数を作成し、この中でLCDの初期化シーケンスを実行。
この初期化シーケンスは、LCDのデータシートに書いてある。
今回買った、SD1602HULB-XAの初期化シーケンスは、以下のように書かれている。
今回は4bitモードなので、下の方。
画像が汚くて読みにくいか。
まず基本的な動作として、RSはコマンドモード(0)/データモード(1)の切り替えに使用し、R/Wはライトモード(0)/リードモード(1)の切り替えに。
D4〜D7は、ライトモードのコマンドモードではコマンドパラメータ、データモードでは文字コードをセットする。
リードモードでのコマンドモードでは、Busyフラグとアドレスカウンタ(データを読み書きするアドレス)の取得、データモードではデータ読み出しが出来る。
アドレスの設定は、ライトモードのコマンドモードのコマンドパラメータで指定できる。
これら各種命令の一覧は、以下。
これらコマンド通りに、出力/入力ポートの設定をして、その状態でEをLow→High→Lowとすることにより、コマンドが実行される。