必修技術:タスク制御とチャタリング対策:T-Engineプログラミング入門(3)(4/5 ページ)
今回は基本中の基本であるタスク制御と、「チャタリング」という組み込みならではの問題への対処法を解説する
回転速度の制御とチャタリング防止
ここまででリスト1の動作は理解できたと思います。これからは、「簡易版」で省略した2つの機能を実装して、スロットマシンをより完全にしましょう。
ドラムの回転を少しずつ遅くして止める
まず「ドラムの回転を少しずつ遅くして止める」ようにしましょう。これは、リスト1のように待ち時間を30ミリ秒からいきなり無限大(TMO_FEVR)にするのではなく、
30→40→50→60→70→80→90→100→TMO_FEVR
というように、待ち時間を少しずつ長くしていけばよいでしょう。これを実装したのが以下のコードです。
/* 左ドラムの処理タスク */ void task_left( INT stacd, VP exinf ) { ER er; int count_left; time_left = 30; count_left = 0; for (;;) { /* スリープ */ er = tk_slp_tsk( time_left ); /* タイムアウトの場合 */ if (er == E_TMOUT) { /* 左ドラムを次へ進める */ count_left++; if (count_left >= 6) count_left = 0; /* 左7セグメントLEDに表示する */ out_h( 0x16100002, p[count_left] ); /* 左ドラムの減速時 */ if (time_left > 30) { /* 左ドラムの回転をさらに遅くする */ time_left += 10; /* 左ドラムを停止する */ if (time_left > 100) time_left=TMO_FEVR; } /* 割り込みハンドラから起床された場合 */ } else if (er == E_OK) { /* 左ドラムの減速開始 */ if (time_left == 30) time_left += 10; /* 左ドラムを最高速に戻す */ else if (time_left == TMO_FEVR) time_left = 30; } } }
スイッチのチャタリング防止
次にスイッチのチャタリング防止です。リスト1では、割り込みでHighからLowへの立ち下がりのエッジ検出をしているので、どうしてもチャタリングを拾ってしまいます。そこで、割り込みハンドラを使わずに、チャタリングの継続時間よりも長い間隔でスイッチの状態を監視して、「前回がHigh、今回がLow」であるかどうかで判定するように変更しましょう(図6)。
トグルスイッチの状態は、割り込みを使わなくても、
in_w( 0x0021c224 ) & (1 << 22)
のようにアドレス0x0021c224を32bit幅で読み出してbit 22を見れば分かります。
さて、「一定周期で状態を監視」するにはどうすればよいでしょうか? 前回説明したように、単純なビジーループで監視すると、その間CPUはほかの処理ができません。そこで、今回説明したように「タスク内でスリープしながらループして監視する」という方法が考えられます。タスクがスリープしている間は、CPUはほかのタスクを実行できるのでCPU時間の無駄にはなりません。
ということで「タスク内でスリープしながらループして監視する」という方法でもいいのですが、しかしT-Kernelにはさらに便利な「周期ハンドラ」という機能があります。今回はこれを使ってみましょう。割り込みハンドラは割り込みが発生するたびに呼ばれるのに対して、周期ハンドラは一定間隔ごとに呼ばれるハンドラです。
main関数では、次のように10ミリ秒間隔で呼ばれる周期ハンドラを生成、起動します。
ID cid_toggle; (中略) ER main( INT ac, UB **av ) { (中略) T_CCYC cc_toggle = { NULL, TA_HLNG, cyc_toggle, 10, 0 }; (中略) /* トグルスイッチ(SW7)を監視する周期ハンドラを生成, 起動 */ cid_toggle = tk_cre_cyc( &cc_toggle ); tk_sta_cyc( cid_toggle );
周期ハンドラ内では、次のようにトグルスイッチの状態を監視します。
/* トグルスイッチ(SW7)を監視する周期ハンドラ */ void cyc_toggle( VP exinf ) { /* 前回の状態を保存しておく変数 */ static int t1 = 0; int t2; /* 現在のスイッチの状態を取得 */ t2 = in_w( 0x0021c224 ) & (1 << 22); /* 前回が High で, 今回が Low の場合 */ if (t1 != 0 && t2 == 0) { /* 左ドラムの処理タスクを起床 */ if (time_left == TMO_FEVR) tk_wup_tsk( tid_left ); /* 右ドラムの処理タスクを起床 */ if (time_right == TMO_FEVR) tk_wup_tsk( tid_right ); } /* 今回の状態を保存して次回に備える */ t1 = t2; }
なお、チャタリングはトグルスイッチだけでなくプッシュボタンでも発生する可能性があります。ただ、今回のスロットマシンの例では、プッシュボタンでチャタリングが発生してもスロットマシンの動作に影響はないので、プッシュボタンについては周期ハンドラによる監視は行っていません。
以上でスロットマシンプログラムの完成です。完成版のソースコードは、リスト3を参照してください。
今回はタスクとハンドラの連携を説明し、Teaboard上で動作するスロットマシンのプログラムを作りました。
次回は、T-Engineの大きな特色である「ミドルウェアの流通」に焦点を合わせて、ミドルウェアを組み合わせてシステムを構築するプログラミングを紹介する予定です。(次回に続く)
Copyright © ITmedia, Inc. All Rights Reserved.