割り込み処理の扱い
サンプルプログラムの中身を解説していきましょう。
まずは、main.cです。見ての通り、t1msec_int、tnmsec_int、mainの三つです。それぞれ、
1 msec タイマ割り込み用、n msec タイマ割り込み用、メインといたってシンプルです。
製作するマイコンシステムの機能は、前回も記載しましたように
1 msecごとにシステムタイマ値(4バイト)を更新する。
LED0を2msec周期で点滅させる。(1msec点灯、1msec消灯)
LED1を2×n msec周期で点滅させる。(n msec点灯、n msec消灯)
n msecごとにRS232C経由でシステムタイマ値を送信する。
です。
t1msec_int には1と2の機能を、tnmsec_intには3の機能を割り当ててあります。
tnmsec_int に4の機能を割り当ててもよいのですが、ここでは、main の無限ループ処理内に4の機能を割り当ててます。
短いプログラムですし、コメントも書いてありますから、これ以上の説明は要らないと思いますが、それでは、解説にならないので一応、解説していきます。
まず、t1msec_int、tnmsec_intはそれぞれ、割り込み用としていますが、このままでは、割り込み処理として使えません。割り込み処理にするには、ルネサスのR8C開発環境では
#pragma INTERRUPT t1msec_int #pragma INTERRUPT tnmsec_int
と宣言する必要があります。これが、例えば、NECの78Kシリーズだと、関数の実装のところで
__interrupt void t1msec_int(void) { … } __interrupt void tnmsec_int(void) { … }
とする必要があります。この程度ですから、書き替えるか、#if文を使えばよいのですが、「main.cは、機種依存無しで考えます。」と標榜していますので別な方法をとって割り込み処理用に割り当てます。見ればわかる様に、割り込みに設定する関数を用意し、それを使って設定します。
4の機能をメインルーチンで行っていますが、これは、tnmsec_intに割り当てても同じです。逆にいえば、割り当てルーチンは、フラグを立てるだけにして、1~4の処理を全てメインルーチンで行うこともできます。そうすれば、簡単に「main.cは、機種依存無しで考えます。」を実現できます。
ただそうしなかったのは、処理には、メインルーチンでやれるものとメインルーチンとは別に実行したいものがあると考えているからです。どちらだけでもプログラムはかけます。しかし、「それぞれのシステムで何が最適か?」を考えた上で実装する必要があるということを考えてほしいからです。
例えば、緊急停止ボタンを実装するとしたら、その割り込みが入ったらその場で処理する必要があるでしょう。メインルーチンに戻っても他の処理をしていては、フラグは見られません。それでは、「緊急」の意味がなくなります。でも、普通のボタン操作なら、人がイライラを感じない程度の待ち時間があったとしても問題ないはずです。それよりも、誤動作の判定や、その割り込みで他の処理を中断されない方が重要な場合もあるはずです。
くどいようですが、「main.cは、機種依存無しで考えます。」というのは、割り込みルーチンを隠して、割り込みルーチンで立てたフラグを見てメインルーチンで実行するようにすれば、簡単に実装できます。でも、実際の実装を考えた場合は、前述のようにどうしても割り込み処理内で処理したい内容が出てくるはずです。
どちらにしても、「このマイコンシステムでは何が行われているのか」がわかるように、システムとして実装すべき項目は全てmain.cに入れておいたほうが良いでしょう。その実装例として、割り込み処理もマイコン機種に依存しない形でmain.cに入れてあります。(あまりいい例でなかったらごめんなさい)
次回は、system.cの説明をします。