2002. 1. 30
例えば、パソコンのアプリケーションでキー入力を処理するとき、キーボードインターフェースのハードウェアを意識することは無いですよね。キー入力はキーボードドライバがバックグランドで処理しているからです。それと同様に、1チップマイコンにおいてもキー入力処理とコマンド実行を切り離してコーディングするとプログラムの見通しが良くなります。
具体的には、キー入力処理はタイマー割り込みなどのバックグランド・タスクに処理させ、メインルーチンはその結果を受け取って実行するといった感じです。これによりメインルーチンはチャタリングやノイズがどうのこうのといったことから開放され、本来の作業に専念できるようになります。また、コマンドキューイングなどの処理も容易にインプリメントできるでしょう (ボタン入力にキューイングは要らないと思うが)。
スイッチが右の図のように接続されている場合の例です。
/* ボタン入力処理変数 */ volatile struct { u_char CMD; /* OFF→ON遷移のあったビットが立っている */ u_char STAT; /* ボタン状態:ONに対応するビットが立っている */ u_char FIL; /* ノイズフィルタ */ } BTN; /* バックグランド処理:タイマ割り込みプロセスから定期的に実行 */ void sample_btn() { u_char a, b; a = ~PA.PIN.BYTE & 0x1f; /* スイッチ読み込み(反転+有効ビットマスク) */ if (a == BTN.FIL) { /* ノイズ・フィルタ */ b = BTN.STAT; /* 前回値取り出し */ BTN.STAT = a; /* 今回値格納 */ b = (b ^ a) & a; /* ボタン押下エッジ抽出 */ if (b) BTN.CMD = b; /* ※必要に応じて、コード化、キューイング等 */ } BTN.FIL = a; } /* フォアグランド処理 */ void main() { u_char a; ------ 中略 ------ for(;;) { sleep(); /* 寝て待つ */ if(BTN.CMD == 0) continue; /* コマンドが無いときはまた寝る */ a = BTN.CMD | (BTN.STAT & 0x10); /* 押されたボタン+Shift状態 */ switch (a) { /* 対応するコマンドを実行 */ case 0x01: func_A(); break; case 0x02: func_B(); break; ------ 中略 ------ case 0x14: func_shift_C(); break; case 0x18: func_shift_D(); break; } BTN.CMD = 0; } ------ 中略 ------ }