今回は、PICマイコンの割込み処理の仕組みと必要な設定内容について説明します。
PICマイコンの割込みの仕組み
割込み処理の実装を行う前に、PICマイコンの割込み処理の内部の様子を理解しておきましょう。
割込み処理の説明の最初で、割込みにはいろいろな種類があることを説明しました。例えばピンの入力が変化した時や内部タイマーが設定した値に達した時などです。
割込み処理機能を追加するには、
- どの種類の割込みを有効にするか、という「割込み処理設定」
- 割込みが発生した場合にどのような処理をするか、という「割込み処理プログラム」
が必要です。以下、それぞれについて詳しく説明します。
1. どの種類の割込みを有効にするか「割込み処理の設定」
PICマイコンはデフォルトではすべての種類の割込みは無効になっています。割込み処理を行う場合、必要な割込みを有効化する必要がありますが、有効化する設定はちょっと複雑です。
厳密ではありませんが、PICマイコン内部の割込みの有効化設定は以下のようになっています。
例えば、ピンの入力値に変化があった場合に割込み処理を行いたい場合は、まずは「入力値の変化があったら割込みを有効にする」という設定を行います。ただ、これだけではピンの入力値変化があった場合でも割込みは発生しません。さらに、そもそも割込みを発生させるかどうか、という元栓となるような有効化設定がありますので、この設定を行います。
ここまでのことをまとめると、割込みを有効化するには、
- 割込み種類別の有効化の設定を行い、
- 割込み自体の有効化の設定を行う
という2つの設定が必要です。
さらに、ピンの入力値変化があった場合に割込みを行う場合、追加の設定が必要です。
ピンの入力値変化といっても、「0→1」の変化と「1→0」の変化があります。どちらの変化が起こったときに割込みを発生させるか、という設定が必要になります。
ここまでをまとめると、ピンの入力値変化があった場合に割込み処理を行いたい場合、結局以下の3つの設定が必要になります。
- ピンの入力値変化の種類の設定を行い、
- 割込み種類別の有効化の設定を行い、
- 割込み自体の有効化の設定を行う
それでは、これら3つの設定をどのレジスタで行うか説明します。今回はRA3ピンの値が「1→0」になったときに割込みを発生する、というケースの設定レジスタになります。他の割込みについてはデータシートを参照いただければと思います。
これらのレジスタを1にすると有効、0にすると無効になります。「割込み処理の設定」について、プログラム表記でまとめると以下になります。
まず、RA3ピンが1→0に変化したときに割り込み発生を有効化する場合は以下のプログラムになります。
IOCAN3 = 1; IOCIE = 1; GIE = 1;
無効化する場合は以下のように記述します。
GIE = 0; IOCIE = 0; IOCAN3 = 0;
レジスタが3つも出てきてどれがどれだかわからなくなってきましたよね。それぞれのレジスタ名は以下の略になっています。
- GIE
Global Interrput Enableの略で、英語交じりの日本語では「グローバルな割り込み処理許可」です。もう少し噛み砕くと「全体の割り込み処理許可」という意味で、割り込み処理自体を有効にするか無効にするかの元栓の設定になります。 - IOCIE
Interrupt-On-Change Interrupt Enableの略で、「ピンの状態変化による割り込み許可」という意味になります。ピンの状態が変化した時の割り込みを有効にするか無効にするかの元栓の設定になります。 - IOCAN
Interrupt-On-Change port-A Negative edgeの略で、「PortAのピンの状態変化による割り込みのうち、1から0に変化した時の割り込み許可」というような意味になります。Negativeとは、1から0に変化することで、反対は0から1に変化する場合のPositiveです。実際に「IOCAP」というレジスタもあります。スイッチを押した時に0から1に変化する場合はIOCAPのレジスタを使用することになります。
2.「割込み処理プログラム」
割込みが発生した場合に行う処理のプログラムも記述する必要があります。
割込み処理プログラムの記述フォーマットは決まっています。以下のようになります。
void __interrupt() isr(void) { // 割込み処理プログラム内容を記述する // 割込み処理の最後に割り込みフラグをクリアする }
まず「void __interrupt() isr(void)」の部分ですが、割込み処理プログラムの書き方はこのように書く、と覚えてしまった方がよいでしょう。ちなみに関数名は「isr」としていますが、他の名称でも構いません。ただ、PICマイコンプログラムの割込み処理関数は一般的に「isr」としているようです。「isr」は「interrupt service routine」で割込み処理プログラムの意味です。
割込み処理プログラムの中身は当然ながら割込み処理の内容を記述します。なお、割込み処理が終わったら、最後に割込み処理フラグをクリアします。
「割込み処理フラグ」???という感じですよね。この「割込み処理フラグ」について簡単に説明します。
「ピンの入力値変化」などの割込みが発生した場合、割込み処理プログラムが実行されますが、その際、どの割込みが発生したか「フラグ」と呼ばれるレジスタ値が1にセットされます。例えばRA3ピンの入力値変化により割込みが発生した場合は、IOCAF3というレジスタが1にセットされます。
「フラグ」とは「旗」の意味です。つまりレジスタのビットを旗に見立てて、0が旗が降りている状態、1が旗が上がっている状態で、フラグが1か0か、つまり旗が上がっているのか降りているのかでどの割込み処理が発生したかわかるようになっています。ネットでたまに「何とかフラグが立った」という表現を見かけますが、おそらくここからきているのではないかと思っています。
また、フラグに0あるいは1をセットすることを、一般的にはそれぞれ「フラグをクリアする」「フラグをセットする」と呼んでいます。
割込み処理プログラムでは、最後にこの割込み処理が発生したフラグをクリアする必要があります。もしこのフラグをクリアしないと、割込み処理が終わっても、再度割込み処理プログラムが呼ばれてしまいます。
割込み処理プログラム例
前回、LEDを1秒ごとに10回点滅させるプログラムを作成しました。このプログラムの「LEDを1秒ごとに10回点滅する」という処理部分は変更せずに、RA3ピンのスイッチが押されたら、高速にLEDを点滅する、という割込み処理を追加したプログラムを作成してみます。
繰り返しになりますが、割込み処理の追加は以下の内容を追加する必要があります。
- 割込み処理の有効化
- 割込み処理が必要ない場合は無効化
- 割込み処理プログラム
- 3-1. 割込み処理プログラム本体
- 3-2. 割込みフラグクリア
これらの内容を追加したプログラムを以下に示します。なお、プログラム内に上の番号も記載しましたので参考にしてみてください。
なお、XC8コンパイラVersion2.00以降では、割り込み関数の書き方が変わっています。以下のプログラムはXC8コンパイラVersion2.00以降のものです。Version2.00より前のバージョンをお使いの場合は以下の変更をお願いいたします。
void __interrupt() isr(void)
を
void interrupt isr(void)
に変更。
/* * File: main.c * 割り込み処理の基本形 */ #include <xc.h> // PIC12F1822 Configuration Bit Settings // CONFIG1 #pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled) #pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config PLLEN = OFF // PLL Enable (4x PLL disabled) #pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) // クロック周波数指定 // __delay_ms()関数が使用する #define _XTAL_FREQ 1000000 // // メイン関数 // void main(void) { // PICマイコン設定 OSCCON = 0b01011010; // 内部クロック周波数を1MHzに設定 ANSELA = 0b00000000; // 全てのピンをデジタルに設定 TRISA = 0b00001000; // RA3を入力、それ以外は出力に設定 // ブザーをOFFにする LATA4 = 0; // LEDを点灯する LATA5 = 1; // (1) RA3割り込み有効化 IOCIE = 1; IOCAN3 = 1; GIE = 1; // 点滅開始 for(unsigned char i=0; i<10; i++) { LATA5 = 0; __delay_ms(1000); LATA5 = 1; __delay_ms(1000); } // (2) 割り込み無効化 GIE = 0; IOCIE = 0; IOCAN3 = 0; // ブザーをONにする LATA4 = 1; // ブザーを鳴らしたままにする while (1); } // (3) 割り込み処理プログラム void __interrupt() isr(void) { // (3-1) 割込み処理プログラム // 割り込み処理が実行されたことを表現するために // LEDを点滅させる for( unsigned char i=0; i<2; i++) { RA5 = 0; __delay_ms(100); RA5 = 1; __delay_ms(100); } // (3-2) 割込みフラグクリア IOCAF3 = 0; }
更新履歴
日付 | 内容 |
---|---|
2017.9.3 | 新規投稿 |
2018.12.2 | レジスタ名の補足説明追加 プログラムテンプレートをMPLABX IDE v5.10のものに変更 |
2019.2.8 | 割り込み処理関数宣言をXC8コンパイラVersion2.00以降の書式に変更 |