mcu_init関数から、スイッチのGPIO初期化部分で不要なものを取り除き、KBIの初期化部分を追加します(リスト3)。
割り込み処理の関数がchk_key_statです(リスト4)。 KBIはKBI1とKBI2の2つがあります。そのため、どちらのKBIで割り込みが起きたのかをKBFフラグで調べ、それぞれのKBIで制御しているスイッチを判定しています。
割り込み処理は関数の中から呼び出されるわけではなく、独立した処理として割り込み時に呼び出されます。そのため、通常の関数のように引数と返却値をつかってデータの受け渡しができません。そこで、両方の処理からアクセスできる共有メモリにデータを格納することになります。では、C言語ではどう書けばよいのでしょうか?
関数を抜けても記憶場所が解放されずに、どの関数からも自由にアクセスできるもの……。あるじゃないですか。外部変数が。ということで、判定結果を格納するstepは外部変数として定義します。
chk_key_statの関数定義には、見慣れないキーワード「interrupt」とマクロ定義「VectorNumber_Vkeyboard」があります。「interrupt」はその関数が割り込み処理であることを示します。Cソースでは通常の関数と違わないように見えますが、機械語レベルでは復帰の方法が異なります。
「VectorNumber_Vkeyboard」は数字の18の別名として定義されています。この番号はベクター・テーブルのKBI割り込みのエントリー番号です。つまり、この方法を使えば割り込み処理とベクター・テーブルの登録が両方一度にできてしまうのです。CodeWarriorでは、何通りかの方法で割り込み処理を記述できるのですが、ここで使っているのが一番簡単な方法です。プログラムをビルドして動かしてみてください。機敏に反応するようになりましたね。
S08CPUのCCRレジスタには、割り込みマスク・ビット(I)というフラグがあります。このフラグが1の時には、ほとんどの割り込みが禁止されます。この仕組みを利用して、割り込み処理の最中には別の割り込みが掛からない仕組みになっています。CodeWarriorが生成したひな型プロジェクトのmain関数には、EnableInterruptsというマクロが呼ばれていますが、これは、割り込みマスク・ビットをクリアして割り込みが掛かる状態を作るものです。
LEDを見やすくするために作ったwait関数ですが、その待ち時間は適当でしたが、実際どの程度の待ち時間なのでしょうか? それは、wait関数がどのような機械語に変換されたのかを確認すれば分かります。各アセンブリ命令の実行時間は規定されているので計算をしてみましょう。
CodeWarriorでは、Cソースをコンパイルし、その結果を逆アセンブル表示する機能があります。
各アセンブリ命令の前に[ ]で数字が書かれています。これは、その命令の実行時間(バス・クロック数)です。例えば、CPUクロックが20MHzだった場合、バス・クロックはその半分の10MHz。1クロック・サイクルは、0.1μsになります。つまり、PSHXは0.2μsで動作します。アセンブリ命令を読みプログラムの流れを理解し、繰り返しの回数を考慮してwait関数の待ち時間を計算してみてください。
これを一般にソフトウェア・タイマーと呼んでいます。微妙な時間調整にNOP命令を使うなどの工夫で最適化の影響のないインライン・アセンブラが正確にできます。ただし、処理中に割り込みがかかった場合などは考慮されていません。
Copyright © ITmedia, Inc. All Rights Reserved.