LCDサンプル

回路図

まずは配線に悩む。
4bitモードを使うか、8bitモードを使うかだ。
やはり、ポートを節約するためには、4bitだろうか。

あとは、busyフラグをチェックするかどうか。
busyかどうかをチェックせずに、ウェイトでコマンド完了を待つ方式だと、R/WをGNDに落としてWrite固定でいいらしいけど、ここは正攻法でbusyフラグはチェックするようにしたいな。

となると、必要なピンは、RS、R/W、E、DB4〜DB7で、全部で7ピンか。
回路図はこんな感じで。
見にくいかも……あってるよな?

LCDサンプル

4bitモードでは、DB0〜DB3は使用しないので、オープンにしておく。
このあたりは、このページを参考に。
Eはプルダウンするべきらしい。
ちなみに、プルダウンしなかったら、起動時に行頭に一つスペースが入ったりしたけど、なんでだろう?
PD5が不定でも確実にLowであるべきということかな?
他はプルアップ抵抗が内蔵されているから問題ないとかいうのもぴんとこない。
もっとデジタル回路を勉強しないとダメか……。

Voは液晶の濃度調整を分圧でやってて、Vcc5Vの1/(10+1)の、約0.45Vがかかる。
これでちょうどいい濃度っぽい。
とりあえず配線はこれでOK。
動いた後の動作写真も載せておく。

LCDサンプル

ソースコード

まずは、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(Register Select)はコマンドモード(0)/データモード(1)の切り替えに使用し、R/Wはライトモード(0)/リードモード(1)の切り替えに。
D4〜D7は、ライトモードのコマンドモードではコマンドパラメータ、データモードでは文字コードやユーザ定義文字のパターンをセットする。
リードモードでのコマンドモードでは、Busyフラグとアドレスカウンタ(データを読み書きするアドレス)の取得、データモードではデータ読み出しが出来る。
アドレスの設定は、ライトモードのコマンドモードのコマンドパラメータで指定できる。
これら各種命令の一覧は、以下。

コマンド

これらコマンド通りに、出力/入力ポートの設定をして、その状態でE(Enable Signal)をLow→High→Lowとすることにより、コマンドが実行される。
この時、LCDの仕様によって、まずEをLowからHighにする前にRSとR/Wを設定してから数ns(ナノ秒)(セットアップ時間)以上待ち、Highの維持を数ns(イネーブルパルス幅)以上行い、HighからLowにしてからRSとR/W、データの変更を行わない時間(ホールド時間)を数ns以上待つ必要があるらしい。
あと、前のEの立ち上がりから、次のEの立ち上がりまでも、一定以上の時間(イネーブルサイクル)以上置く必要がある。
この時間は、データシートに定義されているんだけど、正直、今回買ったやつに関しては、全く当てにできない気がする。
なぜなら、上の図と下の表の、シンボルがほとんど一致してないんだもの……。
読み方を間違っているのかしら……?

タイミング

この表では、RSとR/Wのセットアップ時間が0nsとなっているため、基本的に待つ必要はないらしい。
本当か……?
そして、EをHighにしてからLowにするまで、140ns(イネーブルパルス幅)の維持。
実際にはEのRise時間、Fall時間の各最大25nsが含まれるので、190nsの維持か。
ライトモードでのデータのセットアップに40nsとあるが、これはこのイネーブルパルス幅に含まれているのでOK。
EをLowにしてから、RSとR/W、データのホールド時間が10ns。
EをHighにしてから、次のEをHighにするタイミングまでのイネーブルサイクルは、1200ns(1.2μs)以上。

で、これをプログラムで実際にどれくらい意識する必要があるのかということだが。
msどころの話じゃなく、μsでもなく、さらにその下のnsというのは、普段意識しないレベルなので、なかなかわかりにくい。

AVRは、基本的に1MHz/1MIPSであり、1クロックサイクルで1命令が実行される。
今回は、ATmega168Pを、1MHz駆動させている。(8MHzの内蔵RCで、CKDIV8ヒューズにより、8分周)
ということは、1秒間に実行できる命令は1000000個であり、1命令は1秒の100万分の1で、1μsとなる。
この程度であれば、EをHighにして次の命令ですぐにLowにしたとしても、その間は1μsなので、190ns以上のイネーブルパルス幅を確保しており、さらに次の命令を実行しようとした時には、最初のHighから2μs経過しているので、イネーブルサイクルも仕様を満たしているので、ウェイトを置いたりする必要はないと思う。


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS