PIC の外部割り込みを利用して、スリープ状態から復帰するプログラムの習作。メインループで入力ポートをずっとポーリングするよりも、ボタンの入力待ちになったらマイコンをスリープし、ボタン入力をトリガに割り込みを掛ける方が、ずっと低消費電力でチップを駆動することができるので、是非とも習得しておきたいテクニックです。
#include <htc.h> __CONFIG ( FOSC_INTOSCIO // 内蔵オシレータ & WDTE_OFF // WDT 無効 & PWRTE_OFF // PWRT 無効 & MCLRE_OFF // MCLR 使用しない & BOREN_OFF // BOD 無効 & LVP_OFF // Low-Voltage Programming 使用しない & CPD_OFF // Data memory code protection 無効 & DEBUG_OFF // In-Circuit Debugger 使用しない & CP_OFF // Program Memory code protection 無効 ); // メインルーチン void main () { // RB<7:1> をデジタル出力に設定 // RB0/INT はデジタル入力 TRISB = 0b00000001; // 割り込み許可 OPTION_REGbits.INTEDG = 1; // RB0ポートのL→Hのエッジを検出する INTCONbits.INTE = 0b1; // RB0/INT 割り込みを許可 INTCONbits.GIE = 0b1; // グローバル割り込み許可 // ポート初期化、最初 LED は点灯している PORTB = 0b11110000; // メインループではなにもせずにスリープするだけ while (1) { SLEEP(); NOP(); // SLEEP から復帰すると次の1命令は実行される } } // 割り込みルーチン static void interrupt isr (void) { if (INTCONbits.INTF) { INTCONbits.INTF = 0; // 割り込みフラグをクリアするのはソフトウェアの仕事 PORTB = ~PORTB; // ポートのオンオフを反転する } }
プログラムはタイマ割り込みの例よりも、タイマの動作に関する設定が無い分だけ簡単になっています。また、割り込みが発生した際に、割り込み処理ルーチン(isr
)の中で、割り込み要因を調べて処理を行うのも同じです。
メインループは実際には何の処理も行わず、ただ SLEEP
を繰り返すだけになっています。メインループ内でボタンの押下をポーリングし続ける場合、ずっと CPU が動作し続けますが、SLEEP 中は CPU が休止状態になり、割り込みを待つだけの状態になるため、チップの消費電力が劇的に下げることができます。
#include <htc.h> __CONFIG ( FOSC_INTOSCIO // 内蔵オシレータ & WDTE_OFF // WDT 無効 & PWRTE_OFF // PWRT 無効 & MCLRE_OFF // MCLR 使用しない & BOREN_OFF // BOD 無効 & LVP_OFF // Low-Voltage Programming 使用しない & CPD_OFF // Data memory code protection 無効 & DEBUG_OFF // In-Circuit Debugger 使用しない & CP_OFF // Program Memory code protection 無効 ); // メインルーチン void main () { // RB<7:1> をデジタル出力に設定 // RB0/INT はデジタル入力 TRISB = 0b00000001; // 割り込み許可 OPTION_REGbits.INTEDG = 1; // RB0ポートのL→Hのエッジを検出する INTCONbits.INTE = 0b1; // RB0/INT 割り込みを許可 // ポート初期化、最初 LED は点灯している PORTB = 0b11110000; // メインループではスリープして割り込みを待つ while (1) { SLEEP(); NOP(); // SLEEP から復帰すると次の1命令は実行される INTCONbits.INTF = 0; // 割り込みフラグをクリアするのはソフトウェアの仕事 PORTB = ~PORTB; // ポートのオンオフを反転する } }
ソースコード その2は、非常に簡潔になりましたが動作は先と同じです。注目すべきは、INTCONbits.GIE
ビットを立てていないため、外部割込みが発生した際に、SLEEP から復帰した後、割り込み関数に飛ばずに、そのまま処理が継続されるという点です。すなわち、SLEEP
は、実質、外部からの割り込みをポーリングしていると見なしてプログラムを書くことができるようになります。