プログラムを読んでみよう⑥ ―― led.c
sound.cと同様に、11行目から19行目にハードウェア資源に関する定義がしてあります。led.cには3つの関数があって、31行目からのLed()は、特定のLEDを点灯または消灯する関数、66行目からのAllLed()は全LEDの消灯または点灯です。また93行目からのDispError()は、タイムアウト時にLEDを点滅させるためのエラー表示関数です。どれもシンプルな内容なので説明は要らないと思います。
プログラムを読んでみよう⑦ ―― timer_user.c
このファイルはAppliletでタイマを使うよう設定すると自動的に生成されるものです。タイマに関して必要な処理を追記するために用意されています。
冒頭、いきなり
#pragma interrupt INTTM000 MD_INTTM000 #pragma interrupt INTTM80 MD_INTTM80
という謎の記述が登場して面食らってしまうと思います。これらと、47行目、53行目の
__interrupt void MD_INTTM000( ) { } __interrupt void MD_INTTM80( ) { }
は、Appliletが自動的に生成してくれます。
これは何かといいますと、「割り込み」というマイコンの動作に関する記述です。タイマを例に説明します。まずはキッチンタイマを思い浮かべてください。時間を設定して、スタートボタンを押して、タイマが動作している間におなべの様子を見たり別の仕事をしますね。そして規定の時間がくると、電子音が鳴って時間が来たことを知らせます。すると料理していた人は、そのとき何をしていたかにかかわらず、タイマで知らされた時間にやらねばならない仕事に移ります。
マイコンのタイマも、これとまったく同じ動作をします。待ち時間を設定して、スタートをかけます。その後マイコンはなにかしらの処理を実行し続けます。時間がくると、(キッチンタイマでは電子音で知らせましたが)マイコンのタイマは特別な信号を出して知らせます。マイコンはこの特別な信号を受け取ると、あらかじめ決めておいた関数へジャンプします。そしてそこでの仕事を終えると、再びもといた処理に自動的に復帰するのです。この「特別な信号」のことを割り込み信号といいます。文字通り、「割り込む」仕組みです。また、それによって飛んでいく先の処理プログラムを割り込みハンドラといいます。そして、これら一連の動作を「割り込み」といいます。英語ではinterrupt(インターラプト)です。
で、先の謎の記述ですが、
#pragma interrupt INTTM000 MD_INTTM000 #pragma interrupt INTTM80 MD_INTTM80
は、使用する各タイマの割り込みハンドラはこの関数ですよとCコンパイラに指示するためのものです。たとえば1行目はタイマTM000の割り込みが発生したらMD_INTTM000という関数を呼ぶようにコードを生成しなさいという指示です(2行目も同様)。
そしてそれら割り込みハンドラの処理を書くための関数の外形だけ用意されたものが
__interrupt void MD_INTTM000( ) { } __interrupt void MD_INTTM80( ) { }
であるわけです。
つまり、TM000というタイマを使って、時間が来たときにさせたい仕事を、関数MD_INTTM000( )の中に記述しておけばよいという仕組みです。
という前置きをして、実際の関数群をみていきましょう。まずは8行目9行目で変数を宣言しています。第11回で説明しましたファイル内スタティック変数です。このファイルの中だけで使用し、なおかつ値が保持され続ける変数です。今回は2つのタイマを使っているので、それぞれ用に2個用意しています。
11行目からのStatTimer()はタイマTM00をスタートさせる処理です。直接ここにハードウェアを制御するプログラムを書いた方が効率がよいのですが、簡単にするためにAppliletが用意してくれた関数TM00_Start()を呼び出すだけにしています。
また、TM00用の変数Timer00を0に初期化しています。Timer00は、47行目にある割り込みハンドラMD_INTTM000( )の中で+1しています。TM00は1ミリ秒ごとに割り込みを発生するように設定していますので(別途5rules.prxをAppliletで読み込んで設定を参照してください)、タイマをスタートすると、変数Timer00は0に初期化されたあと1ミリ秒ごとに1ずつ増えていきます。
20行目のStopTimer()はタイマの停止、25行目のReadTimer()は、変数Timer00の値を返すことで、タイマ開始からの時間を知らせる関数です。
31行目からは、別のタイマであるTM80を使った時間待ち処理です。これも単位時間は1ミリ秒にしています。33行目で念のためタイマの停止を行い、34行目でカウント用変数を初期化、35行目でTM80をスタートします。37行目のwhile文が時間待ち処理の本体です。1ミリ秒ごとの割り込みで変数Timer80が増加していき、条件(Timer80 <= count)が成立しなくなるまで待ちます。