「天文屋のためのマイコン入門」サブルーチンの導入
プログラムの7セグメントLEDを表示する部分ですが、長いですね。また7セグメントLEDを表示する処理は、今後、プログラム中で、いくつも出てきそうです。その度にこの長い処理を記述していたのでは大変です。またプログラムもわかり難くなります。
それにGOTO命令が多いと、プログラムを読み解くのも大変です。
もし、7セグメントLEDを表示する部分をメインの処理から切り離し、プログラムの端っこに記述しておいて、1命令でこの処理を代用できたら、便利そうです。
7セグメントLEDを表示する処理が必要な場合は、この一命令を記述すればよいのです。そうすればプログラムのメイン処理部分はすっきりとするでしょう。
このプログラムの一部分を切り離し別の処理とすることを、処理を「サブルーチン化する」といいます。そしてこの分離した処理を「サブルーチン」といいます。
サブルーチンの処理を実際に行いたいときは次の一命令を実行すればよいです。
CALL サブルーチンの番地
サブルーチンの番地にはラベルが使えますので、実際には次の一行になります。
CALL サブルーチン先頭のラベル
この命令の名称からわかるように、サブルーチン処理を要求することを、「サブルーチンを呼ぶ」といいます。
次に、サブルーチン本体の記述です。本体はどこかに記述しなければなりません。普通はプログラムのメイン処理の後に記述します。サブルーチンだからといって特別なことはありませんが、次の2点は必ず守ってください。
1 先頭にラベルを定義する
これによりサブルーチンをラベルで呼ぶことができます。
2 サブルーチンの処理が終わり、呼ばれた場所に戻るには、
RETURN命令を記述する
以上の決まり図示してみました。
それでは、このサブルーチンの決まりにしたがって、前のプログラムで7セグメントLEDを表示する部分をサブルーチン化してみましょう。
サブルーチンのラベルはDisp7Segとします。またサブルーチン本体ですが、GOTO LOOPのところをRETURNに変えます。
前半
後半
いかがでしょうか? プログラムのメインの処理の部分がすっきりしたのがわかります。
ところで、サブルーチンにすべき処理はどのような処理でしょうか? この例では、処理が長いのサブルーチンにしました。一般にサブルーチンにするべき処理は以下のような場合です。
●処理が長い
●使用頻度が高い(何回も同じことを繰り返す)
●汎用性がある(他のプログラムでも利用できる)
●回路などハードに依存している
このプログラムの例では、スイッチの状態を入力する次のたった2行もサブルーチン化してよさそうです。
MOVF 5h,W ;ポートAをワーキングレジスタに格納
ANDLW B'00001111' ;下位4ビットをマスク
たった2行ですが、これもサブルーチン化するとメリットがあります。もし、スイッチに関する回路が変更になった場合、このサブルーチンだけ変更すれば良いのです。メイン処理は変更する必要がありません。このようにハードに依存する部分をサブルーチン化し、メイン処理から分離することはよく行われます。
この2行をInputSWとしてサブルーチン化した例を示します。(後半部分は省略)
さて、InputSWと、Disp7Segの2つのサブルーチンを紹介しましたが、この2つのサブルーチンは次の特徴があります。
1 InputSWは、スイッチからデータを入力し、メイン処理側に値を返している。
2 Disp7Segは、メイン処理から値を20hに格納してもらい、呼ばれている。
InputSWはメインに値を返しています。これを戻り値といいます。InputSWは戻り値を持っているといいます。
Disp7Segは逆にメインから値をもらっています。これを引数またはパラメーターといいます。Disp7Segには引数があると言います。
もちろん、戻り値も、引数も両方あるサブルーチンもありますし、両方ないサブルーチンもあります。
引数も戻り値もその受け渡しにワーキングレジスタ(W)を使うのが理想です。
Disp7Segは引数に20hの汎用レジスタを使っていますが、これはあまり良くありません。汎用レジスタは番地があるので、その番地を覚えていなければなりませんし、番地が変われば、サブルーチンを書き直さないといけません。それになにより、汎用レジスタはバンクが異なれば同じ番地でも実体が異なりますから、違うバンクで使うことができません。(もちろろん全バンク共通の汎用レジスタを使う手もありますが)
次回はもうちょっとサブルーチンに関して考えてみたいと思います。
| 固定リンク
コメント