今回は秋月H8マイコンマザーボードに良く使われている16文字x2行の液晶(LCD)表示器 SC1602BSLB を使って文字を表示させるための関数をご紹介します。この表示器はH8/3052Fのパラレルポートと接続することによって、簡単に利用することができます。英数字やカタカナ以外にも各種の記号を表示させることができ、マンマシンインターフェイスとして利用することにより、少し上のシステムを作り上げることができますので是非使ってみましょう。現在では様々なWebサイトでその利用方法が紹介されています。細かなことはそれらのサイトにお任せして、ここではとにかく動かして見ることにしましょう。 1.SC1602BSLB液晶表示器 SC1602BSLCは、7x5dotの英数カタカナおよび記号文字を16文字x2行分表示できる液晶表示器です。外部とのインターフェイスには、データバスが8BIT幅のモードと、4BIT幅のモードが選べます。表示領域は16文字x2行分だけですが、DDRAM(Display Data RAM)には40文字x2行分の合計80文字が記録でき、表示をシフトすることでスクロール表示をさせることができます。その他、カーソルを表示させたり、カーソルの位置を設定して、そこから新たな文字を表示させたり、またカーソル位置の文字を黒反転による点滅表示にしたり、といったことができます。これらの基本機能を使うことにより、様々なアプリケーションに対応させることが出来るでしょう。
上記の回路図はAKI-H8/302FマイコンボードのPort3とSC1602BSLBを接続したものです。データ線はD4〜D7の4BITだけで接続されているため、この回路では4BIT幅モードで動作させます。データ線が4BIT分しか接続されていない場合一度に8BIT分のデータを送れないため、4BIT幅モードでは上位4BIT分と下位4BIT分の2回に分けてデータを送ります。その他にE端子、RS端子が接続されています。E端子はD4〜D7から送られるデータを書き込むためのパルスを与えます。RS端子はD4〜D7から送られるデータの意味づけを指定するもので、"1"の場合は表示させる文字データとして認識し、"0"の場合はSC1602BSLBの動作モードを指定するためのコマンドとして認識します。なお、上記の回路図ではRW端子を使っていません。RW端子はSC1602BSLBからBusy信号や表示中のデータなどを読み込む場合に使う端子ですが、今回は未使用としています。 SC1602BSLBのコマンドには以下のようなものがあり、イニシャル処理や表示処理として利用します。これらはコマンド扱いなので、RS端子は全て"0"にしておきます。 ■Clear Display 表示を全てクリアして、カーソル位置も先頭位置に戻します。
■Cursor At Home カーソルを先頭位置に戻します。表示はクリアされません。
■Entry Mode Set 1文字分の文字データが入力された時の挙動を指定します。
I/D :"1"の時は新たな文字表示が右側に追加され、"0"の時は左側に追加される S :"1"の時は新たな文字追加に伴って画面表示全体もシフト ■Display On/Off Control 文字表示のON/OFF、カーソル表示のON/OFF、カーソル位置の文字のブリンクON/OFFを指定します。
D :"1"の時は文字表示ON、"0"の時は文字表示OFF C :"1"の時はカーソル表示ON、"0"の時はカーソル表示OFF B :"1"の時はカーソル位置の文字がブリンク表示ON、"0"の時はOFF ■Cursor/Display Shift カーソル位置や、表示全体をシフトさせます。
S/C :"1"の時は表示全体をシフト、"0"の時はカーソル位置だけをシフト R/L :"1"の時は右側にシフト、"0"の時は左側シフト ■Function Set データ幅、表示行数、表示フォントをイニシャル指定します。
DL :"1"の時は8BIT幅モード、"0"の時は4BIT幅モードによる通信 N :"1"の時は2行表示、"0"の時は1行表示 F :"1"の時は5x10dotフォント、"0"の時は5x7dotフォント ■DDRAM Address Set 文字の表示位置、カーソル位置のアドレスを設定します。
SC1602BSLBでは上段1行目と下段2行目のそれぞれに40文字ずつ、合計80文字の表示が可能です。この表示位置を決めるDDRAMアドレスは以下のようになっています。
初期状態の表示エリアでは、1行目に0〜15、2行目に64〜79のアドレスが表示されます。ここでDisplay Shiftコマンドを使うと、表示領域を左右にずらしていくことができます。1行目の16〜39、2行目の80〜103が、Display Shiftコマンドにより表示させることができるエリアになります。そして1行目の40〜63と2行目の104〜127が未使用エリアです。表示座標として1行目の40〜63を指定すると、2行目の64が指定されたものとして動作し、2行目の104〜127を指定すると、1行目の0が指定されたものとして動作します。 2.SC1602BSLB液晶表示器プログラム それでは、SC1602BSLB液晶表示器を使ったプログラムの事例をご紹介します。今回はPIOのPort3を使って動作させています。このプログラムはHEW4の環境でビルドできます。なお、今回作成した関数は汎用的に利用するため、myfunc.hというヘッダファイルに収めました。プロジェクトのフォルダにコピーして、HEW4のメニューバーから「プロジェクト」→「ファイルの追加」でプロジェクトに追加してください。 【ダウンロード】 lcddisp_test1.c 右クリックで「対象をファイルに保存」 【ダウンロード】 myfunc.h 右クリックで「対象をファイルに保存」
それでは、プログラムの中身について見てみましょう。 #include "iodefine.h" はH8/3052Fマイコンのハードウェアレジスタを操作するための構造体変数が宣言されたヘッダファイルです。 #include "myfunc.h" は、このあと説明しますが、TekuRoboで作っていく関数のうち、他のプログラムでも汎用的に使えるものを集めるヘッダファイルで、今回はここにSC1602BSLB液晶表示器を動作させるための関数を追加しています。 main関数では、myfunc.hに追加した液晶表示器を動作させるための各種の関数を用いて、一通りの液晶表示の動きをさせています。先ず、Port2の8ビット分をプルアップ付きの入力ポートに設定し、itu0_wait_init( ); により待機タイマーを初期化し(H8/3052F ITUで時間かせぎを参照)、続いてlcd_init( ); により液晶表示器を初期化します。続いて、液晶表示器が正常に動作していることを確認するため、「TekuRobo Ready GO!」の文字を表示させます。文字の表示はlcd_locate( ); で先頭文字の表示場所を指定し、lcd_print( ); で直接表示文字を指定しています。 続いて、while(1) { } の無限ループ内でPort2から入力された情報に基づいてswitch文により分岐処理を行い、各種の表示操作を行っています。無限ループの中は、while(1){ } 内の一番最後にある itu0_wait(500); によって500mS(0.5秒)のインターバルを経て繰り返し処理されます。例えば、Port2を0x40の値 (8ビットのディップスイッチに接続すると、例えば左から2番目のスイッチだけONになると 0100 0000 で0x40 )のままとすると、lcd_shift_disp('r'); が繰り返し実行され、液晶画面の表示が0.5秒ごとに右にシフトします。ところで、switch文の分岐で実行される各関数は、液晶表示器を制御するために今回作った関数で、次にご紹介するmyfunc.hに記述しています。 ※ここで、switch文の分岐条件ですが、Port2にディップスイッチが接続されていることを前提としています。そして、各ビットのスイッチがひとつだけONになったら、そのスイッチに割り当てられた機能が動作するようにしています。また、ハードウェア上の接続が、スイッチONでレベル0、スイッチOFFでレベル1になるようになっているため、sw = ~P2.DR.BYTE と ~(にょろ)を付けてビットを反転させて認識しています。ここで、変数swを1BYTEとするため変数宣言で char sw; としているのですが、値が0x80としたい時だけ0xFF80と2BYTEのデータを返してきます。原因がわかりませんが、ここは一先ずそのままにしています。
次に、ヘッダファイルmyfunc.hの中身について見てみましょう。 myfunc.hの中には、標準的に使うその他の関数も含まれていますが、ここではSC1602BSLB液晶表示器を動作させるための関数だけ抜粋しています。それでは、各々の関数について見ていきましょう。 ■プリプロセッサ 今回の液晶表示器の制御は、冒頭の回路図の通りPort3を使うことを前提としました。なので、RS端子、E端子、DATAバスに相当する各端子ポートを、#defineでPort3に指定しておきます。ポートのモードを設定するために、DDRも#defineでLCD_PORT_DDRという名称にしています。ハードウェアの接続上、別のPortに変更したい場合は、この#defineで別のPortを指定してあげれば良いでしょう。 ■lcd_init( );関数 SC1602BSLB液晶表示器の初期化を行うための関数です。関数の中でitu0_wait( );関数を使っているので、main( );関数の中でこの関数を実行する前に、必ずitu0_wait_init( );関数を実行して下さい。この関数ではSC1602BSLBのマニュアルに記載されている4BIT幅モード時の手順に従った初期化を行っています。処理については主にlcd_write8( );関数とlcd_write4( );関数を使って、SC1602BSLBにデータやモードを書き込んでいます。これらの関数についてはこの後ご紹介しますが、lcd_write8( );関数はSC1602BSLBに接続されている全端子を直接操作する関数で、lcd_write4( );関数は8ビット長のデータを上位4ビットと下位4ビットの2回に分けて書き込む関数です。lcd_write8( );関数での最後の書き込みであるlcd_write8(0x02);によって4BIT幅モードに設定されるため、その後のデータの書き込みは、lcd_write4( );関数を使っています。lcd_write4( );関数での書き込みによって、以下の動作モードに設定しています。 ・4BIT幅データ、2行表示、5x7ドットフォント ・新たな文字は右側に追加され、画面全体はシフトしない。 ■lcd_write8( );関数 SC1602BSLB液晶表示器に接続されている全端子を直接操作する関数です。実際に書き込みたいデータは引数の下位4ビットで指定しておき、上位4ビットは0としておきます。書き込み制御端子であるE端子へのパルスは、LCD_E = 1; → itu0_wait(1); → LCD_E = 0; → itu0_wait(1); によって発生させており、これにより1mSのパルス幅となります。この関数は初期化用のlcd_init( );内でしか使っていません。 ■lcd_write4( );関数 SC1602BSLB液晶表示器を4BIT幅モードにした時に、8ビット長のデータを上位4ビットと下位4ビットの2回に分けて書き込む関数です。引数としてはデータ受け渡しのためのchar str と str を文字データとして扱うか、モードとして扱うかを指定するための char rs の2つがあります。先ず初めにLCD_E = 0; によって強制的にE端子を0にしておきます。次にrs が文字データを示すか、モードを示すかの識別をswitch文で判定し、文字データ( rs = 1)の場合はLCD_RS = 1;によってRS端子を1にします。モード( rs = 0 )の場合にはLCD_RS = 0;によりRS端子を0にします。rs に1か0以外の情報が指定されていた場合は、default により文字データとして扱います。 次にstr に受け渡された8ビットのデータのうち、上位4ビット(D7〜D4)をSC1602BSLB液晶表示器に書き込みます。先ず、あらかじめ dummy = str; によって変数dummyには、strと同じデータが格納されています。dummy = dummy>>4;によって上位4ビットのデータは下位4ビットに移動し、更にdummy &= 0x0F;によって、上位4ビットが強制的に0にマスクされます。次に、status = LCD_DATA & 0xF0; によって、現在のLCD_DATA (Port3のデータ)の下位4ビットだけを0にマスクし(RS端子のデータを現状のままとしておき)、LCD_DATA = status | dummy; によって、先ほど作った上位4ビットデータを下位4ビットに移したデータdummyとORで結合させます。この時点で LCD_DATAの値は、下位4ビットが書き込みたいデータ、上位のRS端子が設定済みの状態、E端子は0になっています。その後、LCD_E = 1; → itu0_wait(1); → LCD_E = 0; → itu0_wait(1); によってE端子に1mSのパルスを発生させて、SC1602BSLB液晶表示器に4ビットデータ(ここではdummyで指定したデータ)を書き込みます。 次にstr に受け渡された8ビットのデータのうち、下位4ビット(D3〜D0)をSC1602BSLB液晶表示器に書き込みます。ここでは、dummy = str; を実行しておき、そのままdummy &= 0x0F;によって上位4ビットを0にマスクします。つまり、下位4ビットをそのまま残して使います。後の処理は先ほどの説明と同じで、下位4ビットだけがSC1602BSLB液晶表示器に書き込まれます。 ■lcd_locate( );関数 SC1602BSLB液晶表示器に文字データを書き込む際の、先頭文字の座標を指定します。座標は先にご紹介しているDDRAMのアドレスを元にして、char x と char y の x , y 座標で表すことにしています。 x は横方向の座標で、y は1行目か2行目かを指定する座標です。いずれも0始まりの数値で指定します。関数の中身は、lcd_write4( );関数を使っており、0x80+x+y*0x40 で座標計算を行います。lcd_write4( );関数への2つ目の引数は、文字データではなく、DDRAMのアドレス値を指定するためのモード情報なので0にします。 座標の計算式は単純です。 0x80はDDRAMのアドレスを指定するコマンドを意味しています。次の x は単純に横方向の座標を文字数で表しています。y は0なら1行目、1なら2表目に表示したいので、2行目の先頭アドレス0x40とyの値を掛け合わせています。したがって、x+y*0x40の部分は、表示させたいDDRAMのアドレスを示すことになります。 ■lcd_print( );関数 この関数は、引数として *str という変数を受け渡しています。頭に * が付いている今回の *str のような変数の場合、str は受け渡されるデータの先頭アドレスを示しポインタと呼ばれ、 *str はそのアドレスに格納されているデータ値を示します。このような使い方は文字列を操作するときに良く使われる方法です。while(*str != 0){ } では、*strで示されるデータが0でなければ{ }内の処理を繰り返します。{ }内では,、lcd_write4( );関数によって*strで示される文字データをSC1602BSLB液晶表示器に1文字だけ書き込みます。その後、str++; を実行します。 str はデータの先頭アドレスだったので、受け渡された文字列の1文字目が格納されているアドレスを示します。str++; は、 str = str + 1; と同じことなので、str++; によって、アドレスがひとつ増え、str は文字列の2文字目を格納するアドレス値に更新されたことになります。したがって、while文の2回目のループでは、SC1602BSLB液晶表示器には2文字目のデータが書き込まれることになります。この調子で、順次アドレスが更新されて、文字列のデータが順番に書き込まれることになります。つまり、指定の文字列が一気に表示されることになります。 ■lcd_clear( );関数 この関数には引数はありません。lcd_clear( );を実行すると、SC1602BSLB液晶表示器の表示が、すべてクリアされ消されます。この関数内でもlcd_write4( );関数が使われており、単純にモード書き込みの設定で、表示クリアのコマンドを書き込んでいるだけです。 ■lcd_shift_disp( );関数 SC1602BSLB液晶表示器の表示全体を左右にシフトする関数です。引数として dir を受け渡し、dir が l (小文字のエル)か L の場合は表示全体を1文字分だけ左にシフトし、 r か R の場合は右にシフトします。dir の判定はswitch文で行い、左シフト、右シフトが判定された段階で lcd_write4( );関数を使って左シフト、右シフトのコマンドをSC1602BSLB液晶表示器に書き込んでいます。 ■lcd_shift_cursor( );関数 SC1602BSLB液晶表示器のカーソル位置を左右にシフトさせる関数です。引数として dir を受け渡し、dir が l (小文字のエル)か L の場合はカーソル位置を現在の位置から1文字分だけ左にシフトし、 r か R の場合は右にシフトします。dir の判定はswitch文で行い、左シフト、右シフトが判定された段階で lcd_write4( );関数を使って左シフト、右シフトのコマンドをSC1602BSLB液晶表示器に書き込んでいます。 3.lcddisp_test1.C の実行 【MOVIE】ダブルクリックすると再生します。
今回は、SC1602BSLB液晶表示器を操作するための関数を作ってみました。関数としては普通に良く使いそうなものだけにしておきましたが、カーソルをアンダーラインではなくて文字部をブリンクさせるようにしたり、文字列を左から右にではなく右から左に表示させたり、といったモードに変更させる関数なども作ることができます。プログラムの内容としては、SC1602BSLB液晶表示器のコマンド表に基づいて、H8/3052FのPIOによるプログラミングを応用したものになっています。周辺デバイスには、今回のようにPIOを使い、また時間稼ぎ関数と組み合わせてパルスを発生させて制御することでインターフェイスが可能になるものが少なくないと思います。制御したい周辺デバイスの仕様書を読み解くことも必要になりますが、是非色々とチャレンジしてみてください。 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||