チャタリングを防止して、スイッチ入力を完成させようイチから作って丸ごと学ぶ! H8マイコン道(9)(2/3 ページ)

» 2009年12月16日 00時00分 公開

スイッチの状態の変化を調べるプログラム

――せっかくコンパイルまで完了したのに、プログラムが思うように動きません……。どうやら晴子さんは、ガッカリする健一君の姿を予想していたようですね。さて、今回も晴子さんのペースにすっかり翻弄(ほんろう)されている健一君。彼のプログラムのどこがいけなかったのでしょうか?


晴子さんからの宿題(2)

SW1を押した回数を、7セグメントLEDに表示するプログラムを作ってね。ただし、カウンタの初期値は「0」よ。それと、「9」の次のカウントで最初の「0」に戻ること!



 それでは、謎を解明していきましょう。まずは、先ほどの健一君のプログラム(ソースコード1)を逆フローしていきます(図2)。

健一君のプログラムのフローチャート 図2 健一君のプログラムのフローチャート

 健一君のプログラムでは、「SW1」が押されている間、7セグメントLEDに「8」が表示されます。図2が、そのフローチャートです。

 「SW1」が押されているときの処理の流れを赤線で示しました。このように、「SW1」が押されている間、「0」から「9」までのカウントが繰り返されます。しかし、マイコンの処理速度というのは大変高速なので、7セグメントLEDには「0」から「9」までが高速表示され、結果的に「8」と表示されているように見えていたのです。

 どうやら健一君は、「SW1が押されているときにカウント処理する」と考えたようですが、そこに誤りがあったのです!

 それでは、スイッチが押された回数を数えるプログラムとは、どんな処理になるのでしょうか?

 実はこの処理には、2つのとらえ方があります。

 それは、

  • ①スイッチが押されていない状態から、押されたときにカウントする
  • ②スイッチが押された状態から、離れたときにカウントする

です。

 分かりやすいように、タイミングチャートで示してみましょう(図3)。

スイッチのON/OFF変化とカウント処理 図3 スイッチのON/OFF変化とカウント処理

 健一君のプログラムの場合、図3のピンク色で示した時間に、カウントを繰り返し実行するようになっていました。前回の宿題(2)では、図3の赤色で示した①か②のいずれかの時点、つまり、「スイッチのON/OFFが、変化したときにカウントする」プログラムを作ればよいのです。

 ここでは、図3①のスイッチ操作をとらえるものとして、フローチャートを作ってみました(図4)。

スイッチが押された時点をとらえるプログラムのフローチャート 図4 スイッチが押された時点をとらえるプログラムのフローチャート

 スイッチが押されていない間、図4①のループでスイッチが押されるのを待ちます。スイッチが押されたならば、カウント処理し、さらに図4②のループでスイッチが押されている間待機します。

 これでプログラムはうまく動きますが、CPUの処理能力はほとんど入力待ちループに費やされることが分かります。

 それでは、ここまでの解説を基にしたC言語のプログラムを確認してみましょう(ソースコード2)。

/* SW1が押された回数を表示する。
 *
 */
#define PCR1 (*((volatile unsigned char *)0xffe4))
#define PDR1 (*((volatile unsigned char *)0xffd4))
#define PCR5 (*((volatile unsigned char *)0xffe8))
#define PDR5 (*((volatile unsigned char *)0xffd8))
#define PCR8 (*((volatile unsigned char *)0xffeb))
#define PDR8 (*((volatile unsigned char *)0xffdb))
 
#define SW1 0x01
#define SW2 0x02
#define SW3 0x04
 
int main(void)
{
    unsigned char LED[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
    int count;
 
    PCR1 = 0x0;
    PDR5 = 0xfe;
    PCR5 = 0x03;
    PDR8 = 0xff;
    PCR8 = 0xff;
 
    count = 0;
    PDR8 = LED[count];
    for (;;) {
        while ((PDR1 & SW1) != 0);/* SW1が押されていないとき待機 */
        if (count < 9)
            count++;
        else
            count = 0;
        PDR8 = LED[count];
        while ((PDR1 & SW1) == 0);/* SW1が押されているとき待機 */
    }
    return 0;
}
ソースコード2 健一君のプログラムを修正


photo

わー!! プログラムが動いた。


見て、見て、晴子さん!


ちゃんとカウント処理してる〜。


photo

よかったわねー。


さすが、健一君。


photo

うん? 晴子さん、何だか妙に優しいなー。


photo

おっ! するどい!


じゃあ、もう少しだけスイッチを押してみて。


photo

はい……。


えっ、何! いまの?


カウントが飛んだ!

※画像2を参照のこと。


photo

そう、それが第2の“ワナ”よ。


いまのプログラムには、「チャタリング」の配慮がなされていないの。


分かる?


photo

えっ、チャタリングって?


ってことは、まだプログラムは完成していないの?


あーあ。今日は早く帰ってゲームしたかったのに……。


photo

まったく!



ソースコード2の実行結果 画像2 ソースコード2の実行結果

Copyright © ITmedia, Inc. All Rights Reserved.