表示編


サンプルプログラムは動いた。H8のプログラムが開発できるようになったわけだが、何から作ればいいかわからない。簡易OSから作るのもいいが、どうも性に合わない。

C言語で一番最初に作るプログラムといえば、画面に「Hello,world」と表示するだけのプログラム。AKI−H8のマザーボードにも液晶ディスプレイ(LCD)がついている(別売だけど)。サンプルプログラムがLCDの表示もしているので、これを改造すれば簡単に「Hello,world」を表示できる(文字データを変えるだけやね)。

ところで、このサンプル。間違えている箇所がある。

TIME10:	PUSH.L	ER0
	MOV.L	#H'AA,ER0    ;450nS TIMER
TIME11:	SUB.L	#1,ER0
	BNE	TIME11
	POP.L	ER0
	RTS
これは、空ループで450ナノ秒のウェイトを作るルーチン。このルーチンのウェイト時間を計算すると100マイクロ秒くらい。うーん。ナノとマイクロを間違えた?1文字表示するごとに4つくらい実行しているから・・・。

それは置いといて、サンプルプログラムの方法では困ることがある。LCDの制御方法の基本は、文字データを1文字ずつ送信すると、画面に表示されてカーソルが移動していく。この通りの方法で使うのならば問題ないのだが、画面をスクロールしたり点滅させようとした途端、制御が複雑になってしまう。サンプルは1バイトずつ一所懸命に送信しているのだが、送信にはウェイトが必要で、メインルーチンで送信していたのでは無駄に実行時間を食ってしまう。

そこでLCD表示用モジュールを作ることにした。

以下の内容はかなりテキトー。


LCD表示用モジュールにはどのような機能をもたせればいいのだろうか?

その1.ブラックボックスにする。

個人的にはブラックボックスは嫌い。しかし、自分の作ったブラックボックスなら安心して使える。それってブラックボックスと言わないのかもしれないけど、形だけでもブラックボックスの考えを導入するのは重要なこと・・・だと思う(って今まで無視してきた自分)。
ブラックボックスの考えはオブジェクト指向に繋がる。C++を使う訳じゃないけど、アセンブラや普通のC言語でもオブジェクト指向っぽいことはできるでしょう。

その2.すべてを含む。

LCD表示用モジュールなのだから、中ではLCDに対していろいろデータを送る。しかし、どんな信号を送っているかはモジュールを使う側は知らない。ブラックボックスなのだから。信号を作って送る処理はすべてモジュールがやってくれる。LCDのデータシートなんていらない。しかしだ。便利な機能を提供しておきながら「LCDの初期化は自分でやってください」って仕様だったら困るだろう。データシートを調べ、モジュール内の送信ルーチンを引っぱり出す。これではブラックボックスになっていない。

その3.無駄なものを含まない。

「LCDに表示する」というだけで考えても、たくさんの機能が思い浮かぶ。C言語のライブラリを見ればわかるだろう。すべてを入れてしまうと、膨大な量になって、作る側も使う側も大変になってしまう。「表示する」という機能をもっと細かく区切らなくてはいけない。そこで、

その4.主従関係を作る。

「LCDに表示」という機能を、低レベルと高レベルに分ける。高レベルの方は、さらに上のレベル(アプリケーションとしておこう)からのデータを受け取り、加工して低レベルの方に渡す。低レベルの方はLCDに直接データを送る。
高レベルの方が低レベルを無視して、LCDにデータを送ってはいけない。送ってしまっては分けた意味がない。しかし、アプリケーションが高レベルの方を無視して低レベルの方にデータを送ったり、直接LCDにデータを送るのは許すことにする(普通は許されないが俺が許す)。あまりぎちぎちに固めてしまうと、WINDOWSのプログラミングと同じになってしまう。オブジェクト指向だと、継承がどーたらこーたらって話になるだろうけど、そこらへんは適当にやることにする。


話の進め方が逆かもしれないが、モジュール作成のメリットについて。

その1.作るのが楽。

いきなり大きいのを作ろうとすると失敗する。モジュールに分割して小さいことからこつこつと。

その2.バグを少なくできる?

モジュールに分割して作る場合、それをテストするプログラムも併せて作る必要がある。ここで、モジュールにどんなデータを入力しても正常に動くようにしておく。あり得ない入力だとしても、エラーチェックではじくようにしておく。そうしておくと、モジュールを組み合わせていってもバグは発生しない(はず)。

その3.モジュール内では自由。

モジュールの使い方と入出力データを決めておいて、それを実現するように作れば、後はどうでも構わない。それがブラックボックスの利点でもあり、怖いところでもある。モジュールのソースに注釈が全くなくても構わない。アクロバティックなコーディングで他の人には理解不能でも構わない。保守性が最悪でも構わない(ちゃんと動けばね)。最適化バリバリして理解不能なソースでもOKなのだ。ブラックボックスだから外からは見えない。
でも、モジュールを組み立てる側は美しくしとかないとね。

その4.保守が楽。

たぶん、これが2番目くらいに重要でしょう。モジュールごとに分担して共同開発ができる。担当者がモジュールの保守の責任を持つ。

その5.再利用ができる。

たぶん、世間ではこれが一番重要でしょう。これから新しいものを作ろうとしたとき、過去に作ったモジュールから使えそうなものを集めればよい。新しく作ればバグが発生する。作らなければバグは発生しない(はず)。ただし、適当にモジュールを作っていたのでは再利用率はなかなか上がらない。


で、今回作ることにしたモジュールは、

「適当なRAM/ROM領域を指定して、その内容をLCDに表示する」
とした。

あるメモリ空間をテキストRAMのようなものにして、そこを書き換えればLCDの表示も変わる。書き換えは、割り込み処理で勝手にやってくれるようにする。LCDの機能に、カーソル表示やブリンクがあるけど、それらはすべて無視する。

このモジュールで用意する関数は3つ。
「LCD_INIT」と「LCD_SET_ADDRESS」と「LCD_TIMER」。

まず、LCD_INITを呼び出す。引数は何もない。次に、LCD_SET_ADDRESSを呼ぶ。引数はテキストRAMのアドレス。んで、あとは定期的にLCD_TIMERを呼ぶだけ。一度呼ぶ度に1文字表示するようにしてある。推奨は1ms間隔のタイマ割り込みを発生させて呼び出す。これだと、1000÷80で1秒間に12.5回、画面を更新することになる。そうそう、20*4文字のLCD専用。


モジュールを作成するときのコツを。

その1.仕様を考えておく。

使用する言語に関わらず、プログラムに取りかかる前に、関数の呼び出し方や入出力のデータ構造を考えて文書化しておく。今回は構造が簡単なので、上に書いてある程度でよいだろう。

その2.ソースを分割する。

モジュールごとにソースを分ける。アセンブルは別々に行いリンクで結合する。作ったモジュールを他のソースから使えるようにするのがインクルードファイルで、ブラックボックスの公開している部分のみを記述する。LCD表示用モジュールでは、3つの関数のみimportで宣言しておく。それ以外は記述してはいけない。
アセンブルしてできたオブジェクトファイルとインクルードファイルだけ残し、ソースファイルは消して(!)しまえば、名実ともにブラックボックスになる。

その3.テスト用プログラムを作る。

モジュールにいろんなデータを与えるテスト用のプログラムを作り動作確認する。ここでは、想定外の使い方もして、ハングしないか確認する(想定外なのだから普通に動くはずは無いのだが、止まってしまっては呼び出す側に問題があるのか呼び出される側に問題があるのかわからなくなってしまう)。

その4.テスト用プログラムは残しておく。

モジュールの動作を確認する最小限に近いサンプルとして残しておく。モジュールを実際に使うときに必ず役に立つ。仕様書に自信がないのならなおさら。

その5.仕様書を文書化して残す。

作った後でもいいから、後から見てわかるように残しておく。記憶力が完璧で、再利用する気がなく、他人に使ってもらう気もないのなら必要ない。


続く
ご意見などは kumon@sam.hi-ho.ne.jp までどうぞ。

戻る