タクトスイッチのうち,ポートBにつながっている赤色タクトスイッチと緑色タクトスイッチは,端子状態変化による割込みを行えるようになっています.ここでは,その機能を使ってタクトスイッチが押されたら割込みを行うプログラムを作成しましょう.

  1. 動作原理

    PIC16F1936のポートBは状態変化割込みを行える機能を有しています.この機能はポートBの端子のうち,いずれかが立ち上がる,立ち下がるもしくは両方の場合,割込みを発生してくれます.
    下の図はそのブロック図です.立ち下がりを検知するにはIOCBNxレジスタを用います.例えばポートBビット3が立ち下がったとき割込ませたかったらIOCBN3=1とします.また,立ち上がりを検知するにはIOCBPxレジスタを用います.
    いずれかの端子の状態が変化したら,IOCBFxレジスタが変化します.例えばポートBビット4が変化したのなら,IOCBF4が1となります.ただし,IOCBN4もしくはIOCBP4のいずれか一方もしくは両方が1でなければ,IOCBF4は変化しません.なお,IOCBFxレジスタは手動でクリアする必要があります.
    CPUに対して割込みを発生させるには,IOCIEレジスタを1にします.なお,この割込みにより,IOCIFレジスタも1になりますので,手動でクリアしてください.
    ChangeStatusBlockDiagram
    (出典: PIC16F193X/LF193X データシート)


  2. Interrupt.c

    割込みに関係するプログラムをこのファイルに書きます.タイマの割込みと同様,コールバック関数として_tactSwitchCallback変数を用意し,割込み発生時にその関数を呼び出すようにします.割込み要因となるのはIOCIFレジスタです.このレジスタが立っているとともにコールバック関数が定義されていたら,コールバックし,加えてIOCIFレジスタをクリアします.

    1. スタティックな変数


      タクトスイッチの割込みが発生した時に呼び出されるコールバック関数_tactSwitchCallbackをスタティックな変数として宣言します.
      /* タクトスイッチの割込みが発生したときに呼び出されるコールバック関数 */
      static void (*_tactSwitchCallback)(void) = NULL;

       

    2. Interrupt_setTactSwitchCallback関数

      _tactSwitchCallbackを設定する関数です.下図のように作成してください.
      Interrupt setTactSwitchCallback

    3. Interrupt_interrupt関数

      既に書かれているTimer0の割込み処理よりも前に,タクトスイッチに関する割込み処理を書いてください.行うことはTimer0とほぼ一緒です.下図にその流れを示します.IOCIFレジスタが立っており,コールバック関数が設定されていたら,コールバックします.
      Interrupt interrupt
  3. TactSwitch.c

    このファイルには,タクトスイッチに関する処理を書きます.
    1. スタティックな変数および定数

      スタティックな変数として,赤色タクトスイッチが押された時のコールバック関数_pressedRedButtonCallback,緑色タクトスイッチが押された時のコールバック関数_pressedGreenButtonCallbackを設定します.
      /* 赤色タクトスイッチが押されたときにコールバック関数 */
      static void (*_pressedRedButtonCallback)(void);
      /* 緑色タクトスイッチが押されたときにコールバック関数 */
      static void (*_pressedGreenButtonCallback)(void);

      また,_pressedButton変数内で使用する__delay_us関数を使用するために,_XTAL_FREQ定数を定義します.__delay_us関数内は,マイコンの周波数にもとづきウェイトをしています._XTAL_FREQ定数にはマイコンの周波数を書いておきます.今回,4000000[Hz]でマイコンを動作させていますので,次のようになります.

      #define _XTAL_FREQ (4000000)

       

    2. TactSwitch_initialize関数

      以前書いた初期化のプログラムを変更します.大きな違いとしては,青色タクトスイッチが接続されているポートが異なります.以前まで使っていたプログラムでは,青色タクトスイッチはポートBビット1に接続されていましたが,その端子をDMDが使うため,新たにポートAビット0に青色タクトスイッチが接続されています.従いまして,基本的には下のアクティビティ図をもとにプログラムを書き直した方が良です.この変更に加えてポートBビット3と4が立ち上がり時に割込みを発生させるためのプログラムを記述します.また,ポートBの状態変化が起きたときに呼び出す_pressedButton関数を設定しておきます.
      TactSwitch initialize
    3. TactSwitch_setPressedRedButtonCallback関数とTactSwitch_setPressedGreenButtonCallback関数

      赤色タクトスイッチが押された時に呼び出すコールバック関数を設定するためにTactSwitch_setPressedRedButtonCallback関数を使用するようにします.TactSwitch_setPressedGreenButtonCallback関数も同様です.
      TactSwitch setPressedRedButtonCallback
      TactSwitch setPressedGreenButtonCallback
    4. _pressedButton関数

      この関数は,赤色もしくは緑色のタクトスイッチが押された時に呼ばれるコールバック関数です.前半が赤色タクトスイッチに関して,後半が緑色タクトスイッチに関して書いてあります.
      この中で注目すべきことは2つあります.1つはチャタリング防止のためのウェイトです.タクトスイッチにはどうしてもチャタリングが起こる可能性があります.今回のタクトスイッチは離しているときにはHigh,押しているときにはLowをマイコンに伝えます.このため,押せばLowになるのですが,押した直後にはHighとLowを行ったり来たりしてしまいます.これがチャタリングです.そのため,立ち上がりのときだけ割り込むように設定してあったとしても,押した直後に立ち上がり信号が存在してしまうのです.そこで,チャタリングが起こっているであろう時間を待ちます.この時使用するウェイトタイマが__delay_ms関数です.この関数に与えた引数だけウェイトしてくれます.今回のプログラムでは2[ms]待たせるようにしてください.
      もう一つ注目すべきは,押されていないことを確認することです.チャタリングの影響で,押した直後にはHighとLowを繰り返します.その後,信号が安定しましたらタクトスイッチが離されていることを確認します.
      以上の処理を表した図を下に示します.
       pressedButton
  4. Main.c

    1. スタティックな変数

      今回,スタティックな変数としてunsigned char 型の_valueを用意します.この変数をドットマトリクスディスプレイに表示します.
      static uint8_t _value = 0;

       

    2. _pressedRedButton関数

      赤色タクトスイッチが押された時のコールバック関数です.まず,ドットマトリクスディスプレイの表示を非表示にした後,表示する値を求めて表示し,再び表示可能状態にします.赤色タクトスイッチが押された時には,値をカウントアップしますが,99以上にならぬよう,処理を付加してあります.
       pressedRedButton
    3. _pressedGreenButton関数

      緑色タクトスイッチが押された時のコールバック関数です.緑色タクトスイッチが押されたら,値を1減らすようにしてあります.
       pressedGreenButton
    4. main関数

      メイン関数では,下記のようにプログラムを書きます.
      main

      演習

      上記のアクティビティ図をもとにプログラムを実装してください.