サブルーチンの使い方について少し勉強しました。サンプルはLEDの点灯個数が1個ずつ増えていくプログラムですが、点灯個数が増える際にいったんすべて消灯するという動作が加わります。点灯のようすを下の図に示します。これくらいならわざわざサブルーチンを使うまでもないでしょうが、サブルーチンの書式に慣れるため、あえて簡単な例でやってみました。マイコン回路は「LED点滅テスト用回路」を使用します。
時間 | LED7 | LED6 | LED5 | LED4 | LED3 | LED2 | LED1 | LED0 |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 | ||||||||
5 | ||||||||
6 | ||||||||
7 | ||||||||
8 | ||||||||
9 | ||||||||
10 | ||||||||
11 | ||||||||
12 | ||||||||
13 | ||||||||
14 | ||||||||
15 |
まず、サブルーチンを使わないプログラムで上記の動作をさせてみます。BASCOM-AVRがインストールされたパソコンで下記リンクをクリックしてファイルをダウンロードすると、BASCOM-AVR IDEが自動的に立ち上がって画面内にプログラムが表示されます。
プログラムファイル sub1a.bas
1 | $regfile = "at26def.dat" | ATtiny26Lを使用する。 | |
2 | $crystal = 1000000 | クロック周波数を1MHzに設定。 | |
3 | Config Porta = Output | ポートAを出力に設定する。 | |
4 | Porta = 1 | ポートAの出力を「1」にする。LED0が点灯。 | |
5 | Waitms 500 | 0.5秒間そのまま。 | |
6 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
7 | Waitms 500 | 0.5秒間そのまま。 | |
8 | Porta = 3 | ポートAの出力を「3」にする。LED0〜1が点灯。 | |
9 | Waitms 500 | 0.5秒間そのまま。 | |
10 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
11 | Waitms 500 | 0.5秒間そのまま。 | |
12 | Porta = 7 | ポートAの出力を「7」にする。LED0〜2が点灯。 | |
13 | Waitms 500 | 0.5秒間そのまま。 | |
14 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
15 | Waitms 500 | 0.5秒間そのまま。 | |
16 | Porta = 15 | ポートAの出力を「15」にする。LED0〜3が点灯。 | |
17 | Waitms 500 | 0.5秒間そのまま。 | |
18 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
19 | Waitms 500 | 0.5秒間そのまま。 | |
20 | Porta = 31 | ポートAの出力を「31」にする。LED0〜4が点灯。 | |
21 | Waitms 500 | 0.5秒間そのまま。 | |
22 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
23 | Waitms 500 | 0.5秒間そのまま。 | |
24 | Porta = 63 | ポートAの出力を「63」にする。LED0〜5が点灯。 | |
25 | Waitms 500 | 0.5秒間そのまま。 | |
26 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
27 | Waitms 500 | 0.5秒間そのまま。 | |
28 | Porta = 127 | ポートAの出力を「127」にする。LED0〜6が点灯。 | |
29 | Waitms 500 | 0.5秒間そのまま。 | |
30 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
31 | Waitms 500 | 0.5秒間そのまま。 | |
32 | Porta = 255 | ポートAの出力を「255」にする。LED0〜7が点灯。 | |
33 | Waitms 500 | 0.5秒間そのまま。 | |
34 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
35 | End | 終わり。 |
上のプログラムを見ると、同じ命令が繰り返し出てきます。「Waitms 500 : Porta = 0 : Waitms 500」の部分(5〜7行目など)です。こういう場合、この部分だけを別の場所において名前(ラベル)をつけ、メインプログラムから繰り返し呼び出して使う方法があります。これがサブルーチンです。プログラム本文の方はメインルーチンとよばれることもあります。
プログラムファイル sub1b.bas
1 | $regfile = "at26def.dat" | ATtiny26Lを使用する。 | |
2 | $crystal = 1000000 | クロック周波数を1MHzに設定。 | |
3 | Config Porta = Output | ポートAを出力に設定する。 | |
4 | Porta = 1 | ポートAの出力を「1」にする。LED0が点灯。 | |
5 | Gosub Routine | 22行目のサブルーチン「Routine」へ飛ぶ。 | |
6 | Porta = 3 | ポートAの出力を「3」にする。LED0〜1が点灯。 | |
7 | Gosub Routine | 22行目のサブルーチン「Routine」へ飛ぶ。 | |
8 | Porta = 7 | ポートAの出力を「7」にする。LED0〜2が点灯。 | |
9 | Gosub Routine | 22行目のサブルーチン「Routine」へ飛ぶ。 | |
10 | Porta = 15 | ポートAの出力を「15」にする。LED0〜3が点灯。 | |
11 | Gosub Routine | 22行目のサブルーチン「Routine」へ飛ぶ。 | |
12 | Porta = 31 | ポートAの出力を「31」にする。LED0〜4が点灯。 | |
13 | Gosub Routine | 22行目のサブルーチン「Routine」へ飛ぶ。 | |
14 | Porta = 63 | ポートAの出力を「63」にする。LED0〜5が点灯。 | |
15 | Gosub Routine | 22行目のサブルーチン「Routine」へ飛ぶ。 | |
16 | Porta = 127 | ポートAの出力を「127」にする。LED0〜6が点灯。 | |
17 | Gosub Routine | 22行目のサブルーチン「Routine」へ飛ぶ。 | |
18 | Porta = 255 | ポートAの出力を「255」にする。LED0〜7が点灯。 | |
19 | Waitms 500 | 0.5秒間そのまま。 | |
20 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
21 | End | メインプログラム終わり。 | |
22 | Routine: | 「Routine」という名前のサブルーチンここから。 | |
23 | Waitms 500 | 0.5秒間そのまま。 | |
24 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
25 | Waitms 500 | 0.5秒間そのまま。 | |
26 | Return | サブルーチン終わり。呼ばれた場所へ戻る。 |
22行目から26行目までがサブルーチンのプログラムです。まず最初(22行目)にサブルーチンの名前を書きます。ここではそのまま「Routine」という名前にしましたが、予約語以外ならなんでもOKです。語尾に「:」(コロン)を付けます。23〜25行目がサブルーチン内で実行するプログラムです。最後(26行目)に「Return」命令を書きます。サブルーチンプログラムはメインプログラムの「End」のあとに書きます。
メインプログラムでは、まず4行目「Porta = 1」でLED0が点灯します。次行「Gosub Routine」はサブルーチンを呼び出す命令です。「Gosub」のあとにサブルーチンの名前を記述します。これによりプログラムは22行目「Routine:」へ飛び、サブルーチン内のプログラムを実行します。23〜25行目の仕事が終わると、26行目「Return」によってさっき呼び出された場所へ戻り、次の行(6行目)から引き続きメインプログラムを実行します。
プログラム中に同じ命令が繰り返し登場するときは、その部分をサブルーチンにすると、プログラムが簡単で見やすくなります。複数のサブルーチンを記述することも可能です。
サブルーチンを呼び出すのにもうひとつ別のやり方があります。「Call」命令を使う方法です。「Gosub」を使うときとは少し書式が違います。
プログラムファイル sub1c.bas
1 | $regfile = "at26def.dat" | ATtiny26Lを使用する。 | |
2 | $crystal = 1000000 | クロック周波数を1MHzに設定。 | |
3 | Config Porta = Output | ポートAを出力に設定する。 | |
4 | Declare Sub Routine | サブルーチン「Routine」の使用を宣言する。 | |
5 | Porta = 1 | ポートAの出力を「1」にする。LED0が点灯。 | |
6 | Call Routine | 23行目のサブルーチン「Routine」へ飛ぶ。 | |
7 | Porta = 3 | ポートAの出力を「3」にする。LED0〜1が点灯。 | |
8 | Call Routine | 23行目のサブルーチン「Routine」へ飛ぶ。 | |
9 | Porta = 7 | ポートAの出力を「7」にする。LED0〜2が点灯。 | |
10 | Call Routine | 23行目のサブルーチン「Routine」へ飛ぶ。 | |
11 | Porta = 15 | ポートAの出力を「15」にする。LED0〜3が点灯。 | |
12 | Call Routine | 23行目のサブルーチン「Routine」へ飛ぶ。 | |
13 | Porta = 31 | ポートAの出力を「31」にする。LED0〜4が点灯。 | |
14 | Call Routine | 23行目のサブルーチン「Routine」へ飛ぶ。 | |
15 | Porta = 63 | ポートAの出力を「63」にする。LED0〜5が点灯。 | |
16 | Call Routine | 23行目のサブルーチン「Routine」へ飛ぶ。 | |
17 | Porta = 127 | ポートAの出力を「127」にする。LED0〜6が点灯。 | |
18 | Call Routine | 23行目のサブルーチン「Routine」へ飛ぶ。 | |
19 | Porta = 255 | ポートAの出力を「255」にする。LED0〜7が点灯。 | |
20 | Waitms 500 | 0.5秒間そのまま。 | |
21 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
22 | End | メインプログラム終わり。 | |
23 | Sub Routine | 「Routine」という名前のサブルーチンここから。 | |
24 | Waitms 500 | 0.5秒間そのまま。 | |
25 | Porta = 0 | ポートAの出力を「0」にする。すべてのLEDが消灯。 | |
26 | Waitms 500 | 0.5秒間そのまま。 | |
27 | End Sub | サブルーチン終わり。呼ばれた場所へ戻る。 |
メインプログラムに入る前にサブルーチンを使うことを宣言します。4行目「Declare Sub Routine」がそれです。「Declare Sub (サブルーチンの名前)」という書き方になります。繰り返しますが、「Routine」は私が付けた名前(ラベル)です。サブルーチンだから「Declare Sub Routine」なのではありません (違う名前にすればよかった)。
サブルーチンの部分はまず「Sub」に続いてサブルーチンの名前を書きます(23行目)。今回の例では「Sub Routine」となります (これも誤解を招く)。この場合末尾の「:」(コロン)はいらないようです。サブルーチン内のプログラムを書いたあと、最後に「End Sub」と書きます。メインプログラム中でサブルーチンを呼び出すときは「Call (サブルーチンの名前)」と書きます。このプログラムは、前の「Gosub」の例とまったく同じように動きます。