#norelated
#contents
* LCDサンプル [#bd9e4555]

** 回路図 [#n4dd3742]
まずは配線に悩む。~
4bitモードを使うか、8bitモードを使うかだ。~
やはり、ポートを節約するためには、4bitだろうか。~

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

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

#ref(LCDTest.png,left,nowrap,LCDサンプル)

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

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

#ref(LCDTestP.png,left,nowrap,LCDサンプル)

** ソースコード [#t2834105]

まずは、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箇所に苦労してるっぽい。~
ご多分に漏れず、結構な難関でした。~

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

#ref(コマンド.png,left,nowrap,コマンド)

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

#ref(タイミング.png,left,nowrap,タイミング)

この表では、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経過しているので、イネーブルサイクルも仕様を満たしており、ウェイトを置いたりする必要はないと思う。~
(実際問題なかった)~

では、8MHz駆動の場合は、どれくらい待てばいいのか。~
1命令は1MHzの時の8倍の速度になるので、1μs/8で125ns。~
イネーブルパルス幅を確保するのに2命令、イネーブルサイクルを満たすためには、EをHighにして2命令待ちEをLowにする4命令で500nsを消費するので、残りは700nsで6命令は必要なはず。~
なんだけど、これくらいの指定だと、全然まともに動いてくれない。~
何が悪いんだ……。~
イネーブルパルス幅に20命令、イネーブルサイクルを満たすために、もう20〜40命令分入れてやって、ようやく安定するレベル。~
1MHzの時より待ち時間多いじゃん……。~
とりあえずは安定している1MHz駆動で進めていきます……。~
そのうち謎が解ければ書く。~

ちなみにこれは、コマンド発行のタイミングの話であって、実際にコマンドが処理される時間の話ではないはず。~
コマンド実行時間は、上記コマンド表の右側に書いてあり、Busyフラグとアクセスカウンタの読み出し以外には、それなりに時間がかかるようだ。~
とはいえ、ライトモードはなんとなくわかるけど、リードモードの処理時間がよくわからない。~
色々なサイトを巡ってみても、あまりリードに関して触れているところがない。~

ライトモードであれば、EのHigh→Low→Highの間のデータをLCDがその瞬間に読み取って、実際にそれを処理する間Busyとなるというイメージなんだけど、あってるんだろうか?~
だとすると、リードモードはEのHigh→Low→Highの間にデータが読めないとダメなわけだから、Busyの読み出しは0μsだからいいとして(?)、Read Data From RAMの43μsは、どこにかかるんだろう?~
なんかまだ勘違いしているところがあるのかもしれない。~

Lcd_initという初期化関数を作成し、この中でLCDの初期化シーケンスを実行。~
この初期化シーケンスは、LCDのデータシートに書いてある。~
今回買った、SD1602HULB-XAの初期化シーケンスは、以下のように書かれている。~

#ref(初期化シーケンス.png,left,nowrap,初期化シーケンス)

今回は4bitモードなので、下の方。~
画像が汚くて読みにくいか。~

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