LCDサンプル
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
#analog
#norelated
#contents
* LCDサンプル [#bd9e4555]
** 回路図 [#n4dd3742]
まずは配線に悩む。~
4bitモードを使うか、8bitモードを使うかだ。~
やはり、ポートを節約するためには、4bitだろうか。~
あとは、busyフラグをチェックするかどうか。~
busyかどうかをチェックせずに、ウェイトでコマンド完了を待...
となると、必要なピンは、RS、R/W、E、DB4〜DB7で、全部で7ピ...
回路図はこんな感じで。~
見にくいかも……あってるよな?~
#ref(LCDTest.png,left,nowrap,LCDサンプル)
4bitモードでは、DB0〜DB3は使用しないので、オープンにして...
このあたりは、[[このページ:http://www.oct.zaq.ne.jp/i-gar...
Eはプルダウンするべきらしい。~
ちなみに、プルダウンしなかったら、起動時に行頭に一つスペ...
PD5が不定でも確実にLowであるべきということかな?~
他はプルアップ抵抗が内蔵されているから問題ないとかいうの...
もっとデジタル回路を勉強しないとダメか……。~
Voは液晶の濃度調整を分圧でやってて、Vcc5Vの1/(10+1)の、約...
これでちょうどいい濃度っぽい。~
とりあえず配線はこれでOK。~
動いた後の動作写真も載せておく。~
#ref(LCDTestP.png,left,nowrap,LCDサンプル)
** ソースコード [#t2834105]
*** 定義とウェイト関数 [#w223beb7]
まずは、includeに各種定数定義と、LEDでも使った待ち関数。~
前回のLEDを取り外して、ポート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 // データビットマスク
// RSモード列挙型定義
typedef enum _tagRSMode{
RS_MODE_COMMAND, // コマンドモード
RS_MODE_DATA, // データモード
} RSMode;
void delay_ms( int time )
{
// 指定ms分ループ
while( time-- ){
_delay_ms( 1 );
}
}
*** 基本動作 [#c6396994]
で、まずはLCDを初期化しなければならないわけだ。~
色々なサイトを巡ってみても、初期化とBusyフラグチェックの2...
ご多分に漏れず、結構な難関でした。~
まず基本的な動作として、RS(Register Select)はコマンドモー...
D4〜D7は、ライトモードのコマンドモードではコマンドパラメ...
リードモードでのコマンドモードでは、Busyフラグとアドレス...
アドレスの設定は、ライトモードのコマンドモードのコマンド...
これら各種命令の一覧は、以下。~
#ref(コマンド.png,left,nowrap,コマンド)
これらコマンド通りに、出力/入力ポートの設定をして、その状...
この時、LCDの仕様によって、まずEをLowからHighにする前にRS...
あと、前のEの立ち上がりから、次のEの立ち上がりまでも、一...
この時間は、データシートに定義されているんだけど、正直、...
なぜなら、上の図と下の表の、シンボルがほとんど一致してな...
読み方を間違っているのかしら……?~
#ref(タイミング.png,left,nowrap,タイミング)
この表では、RSとR/Wのセットアップ時間が0nsとなっているた...
本当か……?~
そして、EをHighにしてからLowにするまで、140ns(イネーブル...
実際にはEのRise時間、Fall時間の各最大25nsが含まれるので、...
ライトモードでのデータのセットアップに40nsとあるが、これ...
EをLowにしてから、RSとR/W、データのホールド時間が10ns。~
EをHighにしてから、次のEをHighにするタイミングまでのイネ...
で、これをプログラムで実際にどれくらい意識する必要がある...
msどころの話じゃなく、μsでもなく、さらにその下のnsという...
AVRは、最速(レジスタ間計算等)で1MHz/1MIPSであり、この場合...
今回は、ATmega168Pを、1MHz駆動させている。(8MHzの内蔵RCで...
ということは、1秒間に実行できる命令は最大1000000個であり...
この程度であれば、EをHighにして次の命令ですぐにLowにした...
(実際問題なかった)~
では、8MHz駆動の場合は、どれくらい待てばいいのか。~
1命令は1MHzの時の8倍の速度になるので、1μs/8で125ns。~
イネーブルパルス幅を確保するのに2命令、イネーブルサイクル...
なんだけど、これくらいの指定だと、全然まともに動いてくれ...
何が悪いんだ……。~
イネーブルパルス幅に20命令、イネーブルサイクルを満たすた...
1MHzの時より待ち時間多いじゃん……。~
とりあえずは安定している1MHz駆動で進めていきます……。~
そのうち謎が解ければ書く。~
ちなみにこれは、コマンド発行のタイミングの話であって、実...
コマンド実行時間は、上記コマンド表の右側に書いてあり、Bus...
とはいえ、ライトモードはなんとなくわかるけど、リードモー...
色々なサイトを巡ってみても、あまりリードに関して触れてい...
ライトモードであれば、EのHigh→Low→Highの間のデータをLCDが...
だとすると、リードモードはEのHigh→Low→Highの間にデータが...
なんかまだ勘違いしているところがあるのかもしれない。~
*** 初期化シーケンス [#s4fe8ac2]
Lcd_initという初期化関数を作成し、この中でLCDの初期化シー...
この初期化シーケンスは、LCDのデータシートに書いてある。~
今回買った、SD1602HULB-XAの初期化シーケンスは、以下のよう...
#ref(初期化シーケンス.png,left,nowrap,初期化シーケンス)
今回は4bitモードなので、下の方。~
画像が汚くて読みにくいか。~
まず、PowerONして起動してから、15ms以上待つ。~
次にコマンド表にあるファンクションセットを使用し、DB4のビ...
印刷ではμが抜けて、100μsが100sになってしまっているという...
100秒も待ってらんねーYO!~
この4bitのコマンドを3回送ることで、元が何のモードだろうと...
確実に8bitモードになったところで、ここでまたファンクショ...
どこのページにも書いてあることだけど、ここまではBusyフラ...
そしてほとんどのページに、ここからBusyフラグが使えるとか...
(以下のデータシートの記述より)~
>BF cannot be checked after the following instructions.~
>When BF is not checked, the waiting time between instru...
なので、初期化シーケンスの一連の処理では、各コマンド送信...
あとは、これらのコマンドを4bit単位で送ってやるので、4bit...
これは後でデータモードの書き込みでも使えるため、引数でコ...
以下、初期化部分のソースコード。~
4bitコマンド送信関数の中身はこの後。~
void Lcd_init( void )
{
// 最初は全てのポートを出力に設定
LCD_DDR |= ( LCD_E | LCD_RW | LCD_RS | LCD_DATMASK );
// 信号もLowにしておく
LCD_PORT &= ~( LCD_E | LCD_RW | LCD_RS | LCD_DATMASK );
// 最初はBusyチェックが効かないので、時間待ちする
delay_ms( 15 ); // 15ms待ち
lcd_setcmd4( RS_MODE_COMMAND, 0x3 ); // 8bitモード設定
delay_ms( 5 ); // 4.1ms以上待ちなので、5ms待ち
lcd_setcmd4( RS_MODE_COMMAND, 0x3 ); // 8bitモード設定
delay_ms( 1 ); // 100μs以上待ちなので、とりあえず1ms待...
lcd_setcmd4( RS_MODE_COMMAND, 0x3 ); // 8bitモード設定
delay_ms( 1 ); // ファンクションセットは39μs以上待ちな...
// 初期化シーケンスに書いてある通り、4bitの設定は4bitの...
lcd_setcmd4( RS_MODE_COMMAND, 0x2 ); // 4bitモード設定
delay_ms( 1 ); // ファンクションセットは39μs以上待ちな...
// ここからは4bitモード動作なので、8bitの命令を4bitずつ...
lcd_setcmd4( RS_MODE_COMMAND, 0x2 ); // ファンクション...
lcd_setcmd4( RS_MODE_COMMAND, 0x8 ); // 2Line表示、5*8...
delay_ms( 1 ); // ファンクションセットは39μs以上待ちな...
lcd_setcmd4( RS_MODE_COMMAND, 0x0 ); // Display ON/OFF...
lcd_setcmd4( RS_MODE_COMMAND, 0xF ); // Display ON / Cu...
delay_ms( 1 ); // Display ON/OFF設定は39μs以上待ちなの...
lcd_setcmd4( RS_MODE_COMMAND, 0x0 ); // Clear Displayコ...
lcd_setcmd4( RS_MODE_COMMAND, 0x1 ); // スペースでDDRAM...
delay_ms( 2 ); // Clear Displayコマンドは1.53ms以上待...
lcd_setcmd4( RS_MODE_COMMAND, 0x0 ); // Entry Mode
lcd_setcmd4( RS_MODE_COMMAND, 0x6 ); // インクリメント...
delay_ms( 1 ); // Entry Modeコマンドは39μs以上待ちなの...
}
最初に、ポートが変な状態になっていないように、入出力状態...
そして、前述の初期化シーケンスを走らせて、4bitモードの2Li...
5*11ドットフォントを指定してみたけど、何も変わらなかった...
Entry Modeは、データを入出力すると、アドレスカウンタが増...
Entry Modeのシフトモードはよくわかってない。~
では次に、4bitコマンド送信関数lcd_setcmd4の中身。~
以下ソースコード。~
void lcd_setcmd4( RSMode mode, uint8_t data )
{
uint8_t tmpval = LCD_PORT; // ポート状態を一旦変数に入...
// 書き込むポートを一旦落とす
tmpval &= ~( LCD_RW | LCD_RS | LCD_DATMASK );
// RSビットコマンドモードであればクリアのまま
if( RS_MODE_DATA == mode ){
tmpval |= LCD_RS; // RSビットはデータモードであれば立...
}
// RWビットはクリアでWriteモードなのでそのまま
// データビットセット(下位4bitのみセットするのマスク)
tmpval |= ( LCD_DATMASK & data );
// ポートに書き込み
LCD_PORT = tmpval;
// イネーブルパルス出力
LCD_PORT |= LCD_E;
// 高速駆動時はここでイネーブルパルス幅以上待つ必要が...
LCD_PORT &= ~LCD_E;
// 高速駆動時はここでイネーブルサイクル時間を稼ぐ必要...
}
I/Oレジスタの中身を、一時変数(汎用レジスタ)内に持っている...
外部のピンに対する電圧が直接変わるI/Oレジスタには、直接頻...
イメージでそう思ってるだけなんだけど、実際はどうなんだろ...
とはいえ、この方法だと、変数に保存してから書き戻すまでに...
*** 文字表示 [#jf245d1a]
LCDには、以下のようにフォントテーブルが定義されている。~
基本的には[[ANKコード:http://www.technoveins.co.jp/techni...
#ref(フォントテーブル.png,left,nowrap,フォントテーブル)
というわけで、文字列を引数に取る関数と、文字を引数に取る...
今回からは、Busyフラグのチェックをしなければならないので...
void Lcd_setchar( char data )
{
// 上位4bit送信
lcd_setcmd4( RS_MODE_DATA, LCD_DATMASK & ( data >> 4 ));
// 下位4bit送信
lcd_setcmd4( RS_MODE_DATA, LCD_DATMASK & data );
// Busyチェック
lcd_busywait();
}
void Lcd_setstr( char *str )
{
// 終了(NULL文字までループ)
while( *str ){
// 1文字ずつ設定
Lcd_setchar( *str );
str++;
}
}
初期化の時はコマンドモードを設定したけど、今回は文字の出...
RS_MODE_DATAを指定する事により、RSビットが立てられるのは...
で、次にBusyチェック関数。~
この関数は、Busyフラグが立ってる間、ループで回り続ける。~
今回の設計では、LCDに対して何かしたら、Busyじゃなくなるま...
LCDにコマンドを送った後に、別の作業を無駄なくさせたいよう...
void lcd_busywait( void )
{
uint8_t bf = LCD_D7; // Busyフラグが立った状態の変数を...
// RSビットはクリアでコマンドモード
LCD_PORT &= ~( LCD_RS );
// ReadモードはRWビットを立てる
LCD_PORT |= ( LCD_RW );
// データビットを入力に設定
LCD_DDR &= ~( LCD_DATMASK );
// Busyフラグが落ちるまでループ
while( bf ){
// イネーブルパルス出力(上位4bit)
LCD_PORT |= LCD_E;
// 高速駆動時はここでイネーブルパルス幅以上待つ必要が...
bf = LCD_PIN & ( 1 << LCD_D7 ); // Busyフラグの読み出し
LCD_PORT &= ~LCD_E;
// 高速駆動時はここでイネーブルサイクル時間を稼ぐ必要...
// イネーブルパルス出力(下位4bit/4bitモードなので2回送...
LCD_PORT |= LCD_E;
// 高速駆動時はここでイネーブルパルス幅以上待つ必要が...
LCD_PORT &= ~LCD_E;
// 高速駆動時はここでイネーブルサイクル時間を稼ぐ必要...
}
// データビットを出力に戻す
LCD_DDR |= ( LCD_DATMASK );
}
とりあえず、以上で文字表示までは出来るようになった。~
ただし、改行を実装していないので、2行目にも表示できるよう...
*** 文字出力位置 [#nd83737d]
さっき、文字表示用に、1バイトの文字を4bitずつ2回に分けて...
void Lcd_setcmd( uint8_t cmd )
{
// 上位4bit送信
lcd_setcmd4( RS_MODE_COMMAND, LCD_DATMASK & ( cmd >> 4 ...
// 下位4bit送信
lcd_setcmd4( RS_MODE_COMMAND, LCD_DATMASK & cmd );
// Busyチェック
lcd_busywait();
}
この関数を使用して、表示位置を指定できる関数Lcd_setposを...
表示位置のアドレスは、以下のようになっているので、移動し...
#ref(DDRAMAddress.png,left,nowrap,DDRAMアドレス)
void Lcd_setpos( int8_t x, int8_t y )
{
int8_t val = 0x80; // コマンドコード設定
if( x ) val |= 0x40; // 行指定が0(1行目)じゃなかったら...
val |= ( y & 0x0f ); // 列指定の4bitを設定する
// コマンド送信
Lcd_setcmd( val );
}
*** メイン関数 [#i296cc22]
最後に、今までの関数を使用して、上の動作写真のように文字...
int main( void )
{
Lcd_init();
Lcd_setstr( "LCDサンプル" );
Lcd_setpos( 1, 0 ); // 2行目の1列目(0ベース)
Lcd_setstr( "ヒョウジテストチュウ" );
return 0;
}
まぁ、ここはもう説明する必要はないねw~
とりあえず、一通り文字を表示させるまでを纏めてみました。~
まだまだ謎なところもありますので、そのうち追記していきた...
終了行:
#analog
#norelated
#contents
* LCDサンプル [#bd9e4555]
** 回路図 [#n4dd3742]
まずは配線に悩む。~
4bitモードを使うか、8bitモードを使うかだ。~
やはり、ポートを節約するためには、4bitだろうか。~
あとは、busyフラグをチェックするかどうか。~
busyかどうかをチェックせずに、ウェイトでコマンド完了を待...
となると、必要なピンは、RS、R/W、E、DB4〜DB7で、全部で7ピ...
回路図はこんな感じで。~
見にくいかも……あってるよな?~
#ref(LCDTest.png,left,nowrap,LCDサンプル)
4bitモードでは、DB0〜DB3は使用しないので、オープンにして...
このあたりは、[[このページ:http://www.oct.zaq.ne.jp/i-gar...
Eはプルダウンするべきらしい。~
ちなみに、プルダウンしなかったら、起動時に行頭に一つスペ...
PD5が不定でも確実にLowであるべきということかな?~
他はプルアップ抵抗が内蔵されているから問題ないとかいうの...
もっとデジタル回路を勉強しないとダメか……。~
Voは液晶の濃度調整を分圧でやってて、Vcc5Vの1/(10+1)の、約...
これでちょうどいい濃度っぽい。~
とりあえず配線はこれでOK。~
動いた後の動作写真も載せておく。~
#ref(LCDTestP.png,left,nowrap,LCDサンプル)
** ソースコード [#t2834105]
*** 定義とウェイト関数 [#w223beb7]
まずは、includeに各種定数定義と、LEDでも使った待ち関数。~
前回のLEDを取り外して、ポート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 // データビットマスク
// RSモード列挙型定義
typedef enum _tagRSMode{
RS_MODE_COMMAND, // コマンドモード
RS_MODE_DATA, // データモード
} RSMode;
void delay_ms( int time )
{
// 指定ms分ループ
while( time-- ){
_delay_ms( 1 );
}
}
*** 基本動作 [#c6396994]
で、まずはLCDを初期化しなければならないわけだ。~
色々なサイトを巡ってみても、初期化とBusyフラグチェックの2...
ご多分に漏れず、結構な難関でした。~
まず基本的な動作として、RS(Register Select)はコマンドモー...
D4〜D7は、ライトモードのコマンドモードではコマンドパラメ...
リードモードでのコマンドモードでは、Busyフラグとアドレス...
アドレスの設定は、ライトモードのコマンドモードのコマンド...
これら各種命令の一覧は、以下。~
#ref(コマンド.png,left,nowrap,コマンド)
これらコマンド通りに、出力/入力ポートの設定をして、その状...
この時、LCDの仕様によって、まずEをLowからHighにする前にRS...
あと、前のEの立ち上がりから、次のEの立ち上がりまでも、一...
この時間は、データシートに定義されているんだけど、正直、...
なぜなら、上の図と下の表の、シンボルがほとんど一致してな...
読み方を間違っているのかしら……?~
#ref(タイミング.png,left,nowrap,タイミング)
この表では、RSとR/Wのセットアップ時間が0nsとなっているた...
本当か……?~
そして、EをHighにしてからLowにするまで、140ns(イネーブル...
実際にはEのRise時間、Fall時間の各最大25nsが含まれるので、...
ライトモードでのデータのセットアップに40nsとあるが、これ...
EをLowにしてから、RSとR/W、データのホールド時間が10ns。~
EをHighにしてから、次のEをHighにするタイミングまでのイネ...
で、これをプログラムで実際にどれくらい意識する必要がある...
msどころの話じゃなく、μsでもなく、さらにその下のnsという...
AVRは、最速(レジスタ間計算等)で1MHz/1MIPSであり、この場合...
今回は、ATmega168Pを、1MHz駆動させている。(8MHzの内蔵RCで...
ということは、1秒間に実行できる命令は最大1000000個であり...
この程度であれば、EをHighにして次の命令ですぐにLowにした...
(実際問題なかった)~
では、8MHz駆動の場合は、どれくらい待てばいいのか。~
1命令は1MHzの時の8倍の速度になるので、1μs/8で125ns。~
イネーブルパルス幅を確保するのに2命令、イネーブルサイクル...
なんだけど、これくらいの指定だと、全然まともに動いてくれ...
何が悪いんだ……。~
イネーブルパルス幅に20命令、イネーブルサイクルを満たすた...
1MHzの時より待ち時間多いじゃん……。~
とりあえずは安定している1MHz駆動で進めていきます……。~
そのうち謎が解ければ書く。~
ちなみにこれは、コマンド発行のタイミングの話であって、実...
コマンド実行時間は、上記コマンド表の右側に書いてあり、Bus...
とはいえ、ライトモードはなんとなくわかるけど、リードモー...
色々なサイトを巡ってみても、あまりリードに関して触れてい...
ライトモードであれば、EのHigh→Low→Highの間のデータをLCDが...
だとすると、リードモードはEのHigh→Low→Highの間にデータが...
なんかまだ勘違いしているところがあるのかもしれない。~
*** 初期化シーケンス [#s4fe8ac2]
Lcd_initという初期化関数を作成し、この中でLCDの初期化シー...
この初期化シーケンスは、LCDのデータシートに書いてある。~
今回買った、SD1602HULB-XAの初期化シーケンスは、以下のよう...
#ref(初期化シーケンス.png,left,nowrap,初期化シーケンス)
今回は4bitモードなので、下の方。~
画像が汚くて読みにくいか。~
まず、PowerONして起動してから、15ms以上待つ。~
次にコマンド表にあるファンクションセットを使用し、DB4のビ...
印刷ではμが抜けて、100μsが100sになってしまっているという...
100秒も待ってらんねーYO!~
この4bitのコマンドを3回送ることで、元が何のモードだろうと...
確実に8bitモードになったところで、ここでまたファンクショ...
どこのページにも書いてあることだけど、ここまではBusyフラ...
そしてほとんどのページに、ここからBusyフラグが使えるとか...
(以下のデータシートの記述より)~
>BF cannot be checked after the following instructions.~
>When BF is not checked, the waiting time between instru...
なので、初期化シーケンスの一連の処理では、各コマンド送信...
あとは、これらのコマンドを4bit単位で送ってやるので、4bit...
これは後でデータモードの書き込みでも使えるため、引数でコ...
以下、初期化部分のソースコード。~
4bitコマンド送信関数の中身はこの後。~
void Lcd_init( void )
{
// 最初は全てのポートを出力に設定
LCD_DDR |= ( LCD_E | LCD_RW | LCD_RS | LCD_DATMASK );
// 信号もLowにしておく
LCD_PORT &= ~( LCD_E | LCD_RW | LCD_RS | LCD_DATMASK );
// 最初はBusyチェックが効かないので、時間待ちする
delay_ms( 15 ); // 15ms待ち
lcd_setcmd4( RS_MODE_COMMAND, 0x3 ); // 8bitモード設定
delay_ms( 5 ); // 4.1ms以上待ちなので、5ms待ち
lcd_setcmd4( RS_MODE_COMMAND, 0x3 ); // 8bitモード設定
delay_ms( 1 ); // 100μs以上待ちなので、とりあえず1ms待...
lcd_setcmd4( RS_MODE_COMMAND, 0x3 ); // 8bitモード設定
delay_ms( 1 ); // ファンクションセットは39μs以上待ちな...
// 初期化シーケンスに書いてある通り、4bitの設定は4bitの...
lcd_setcmd4( RS_MODE_COMMAND, 0x2 ); // 4bitモード設定
delay_ms( 1 ); // ファンクションセットは39μs以上待ちな...
// ここからは4bitモード動作なので、8bitの命令を4bitずつ...
lcd_setcmd4( RS_MODE_COMMAND, 0x2 ); // ファンクション...
lcd_setcmd4( RS_MODE_COMMAND, 0x8 ); // 2Line表示、5*8...
delay_ms( 1 ); // ファンクションセットは39μs以上待ちな...
lcd_setcmd4( RS_MODE_COMMAND, 0x0 ); // Display ON/OFF...
lcd_setcmd4( RS_MODE_COMMAND, 0xF ); // Display ON / Cu...
delay_ms( 1 ); // Display ON/OFF設定は39μs以上待ちなの...
lcd_setcmd4( RS_MODE_COMMAND, 0x0 ); // Clear Displayコ...
lcd_setcmd4( RS_MODE_COMMAND, 0x1 ); // スペースでDDRAM...
delay_ms( 2 ); // Clear Displayコマンドは1.53ms以上待...
lcd_setcmd4( RS_MODE_COMMAND, 0x0 ); // Entry Mode
lcd_setcmd4( RS_MODE_COMMAND, 0x6 ); // インクリメント...
delay_ms( 1 ); // Entry Modeコマンドは39μs以上待ちなの...
}
最初に、ポートが変な状態になっていないように、入出力状態...
そして、前述の初期化シーケンスを走らせて、4bitモードの2Li...
5*11ドットフォントを指定してみたけど、何も変わらなかった...
Entry Modeは、データを入出力すると、アドレスカウンタが増...
Entry Modeのシフトモードはよくわかってない。~
では次に、4bitコマンド送信関数lcd_setcmd4の中身。~
以下ソースコード。~
void lcd_setcmd4( RSMode mode, uint8_t data )
{
uint8_t tmpval = LCD_PORT; // ポート状態を一旦変数に入...
// 書き込むポートを一旦落とす
tmpval &= ~( LCD_RW | LCD_RS | LCD_DATMASK );
// RSビットコマンドモードであればクリアのまま
if( RS_MODE_DATA == mode ){
tmpval |= LCD_RS; // RSビットはデータモードであれば立...
}
// RWビットはクリアでWriteモードなのでそのまま
// データビットセット(下位4bitのみセットするのマスク)
tmpval |= ( LCD_DATMASK & data );
// ポートに書き込み
LCD_PORT = tmpval;
// イネーブルパルス出力
LCD_PORT |= LCD_E;
// 高速駆動時はここでイネーブルパルス幅以上待つ必要が...
LCD_PORT &= ~LCD_E;
// 高速駆動時はここでイネーブルサイクル時間を稼ぐ必要...
}
I/Oレジスタの中身を、一時変数(汎用レジスタ)内に持っている...
外部のピンに対する電圧が直接変わるI/Oレジスタには、直接頻...
イメージでそう思ってるだけなんだけど、実際はどうなんだろ...
とはいえ、この方法だと、変数に保存してから書き戻すまでに...
*** 文字表示 [#jf245d1a]
LCDには、以下のようにフォントテーブルが定義されている。~
基本的には[[ANKコード:http://www.technoveins.co.jp/techni...
#ref(フォントテーブル.png,left,nowrap,フォントテーブル)
というわけで、文字列を引数に取る関数と、文字を引数に取る...
今回からは、Busyフラグのチェックをしなければならないので...
void Lcd_setchar( char data )
{
// 上位4bit送信
lcd_setcmd4( RS_MODE_DATA, LCD_DATMASK & ( data >> 4 ));
// 下位4bit送信
lcd_setcmd4( RS_MODE_DATA, LCD_DATMASK & data );
// Busyチェック
lcd_busywait();
}
void Lcd_setstr( char *str )
{
// 終了(NULL文字までループ)
while( *str ){
// 1文字ずつ設定
Lcd_setchar( *str );
str++;
}
}
初期化の時はコマンドモードを設定したけど、今回は文字の出...
RS_MODE_DATAを指定する事により、RSビットが立てられるのは...
で、次にBusyチェック関数。~
この関数は、Busyフラグが立ってる間、ループで回り続ける。~
今回の設計では、LCDに対して何かしたら、Busyじゃなくなるま...
LCDにコマンドを送った後に、別の作業を無駄なくさせたいよう...
void lcd_busywait( void )
{
uint8_t bf = LCD_D7; // Busyフラグが立った状態の変数を...
// RSビットはクリアでコマンドモード
LCD_PORT &= ~( LCD_RS );
// ReadモードはRWビットを立てる
LCD_PORT |= ( LCD_RW );
// データビットを入力に設定
LCD_DDR &= ~( LCD_DATMASK );
// Busyフラグが落ちるまでループ
while( bf ){
// イネーブルパルス出力(上位4bit)
LCD_PORT |= LCD_E;
// 高速駆動時はここでイネーブルパルス幅以上待つ必要が...
bf = LCD_PIN & ( 1 << LCD_D7 ); // Busyフラグの読み出し
LCD_PORT &= ~LCD_E;
// 高速駆動時はここでイネーブルサイクル時間を稼ぐ必要...
// イネーブルパルス出力(下位4bit/4bitモードなので2回送...
LCD_PORT |= LCD_E;
// 高速駆動時はここでイネーブルパルス幅以上待つ必要が...
LCD_PORT &= ~LCD_E;
// 高速駆動時はここでイネーブルサイクル時間を稼ぐ必要...
}
// データビットを出力に戻す
LCD_DDR |= ( LCD_DATMASK );
}
とりあえず、以上で文字表示までは出来るようになった。~
ただし、改行を実装していないので、2行目にも表示できるよう...
*** 文字出力位置 [#nd83737d]
さっき、文字表示用に、1バイトの文字を4bitずつ2回に分けて...
void Lcd_setcmd( uint8_t cmd )
{
// 上位4bit送信
lcd_setcmd4( RS_MODE_COMMAND, LCD_DATMASK & ( cmd >> 4 ...
// 下位4bit送信
lcd_setcmd4( RS_MODE_COMMAND, LCD_DATMASK & cmd );
// Busyチェック
lcd_busywait();
}
この関数を使用して、表示位置を指定できる関数Lcd_setposを...
表示位置のアドレスは、以下のようになっているので、移動し...
#ref(DDRAMAddress.png,left,nowrap,DDRAMアドレス)
void Lcd_setpos( int8_t x, int8_t y )
{
int8_t val = 0x80; // コマンドコード設定
if( x ) val |= 0x40; // 行指定が0(1行目)じゃなかったら...
val |= ( y & 0x0f ); // 列指定の4bitを設定する
// コマンド送信
Lcd_setcmd( val );
}
*** メイン関数 [#i296cc22]
最後に、今までの関数を使用して、上の動作写真のように文字...
int main( void )
{
Lcd_init();
Lcd_setstr( "LCDサンプル" );
Lcd_setpos( 1, 0 ); // 2行目の1列目(0ベース)
Lcd_setstr( "ヒョウジテストチュウ" );
return 0;
}
まぁ、ここはもう説明する必要はないねw~
とりあえず、一通り文字を表示させるまでを纏めてみました。~
まだまだ謎なところもありますので、そのうち追記していきた...
ページ名: