第18回 割込み処理(3) 〜割込み処理プログラムテンプレ〜

今回は、PICマイコンの割込み処理の仕組みと必要な設定内容について説明します。

目次

PICマイコンの割込みの仕組み

割込み処理の実装を行う前に、PICマイコンの割込み処理の内部の様子を理解しておきましょう。

割込み処理の説明の最初で、割込みにはいろいろな種類があることを説明しました。例えばピンの入力が変化した時や内部タイマーが設定した値に達した時などです。

割込み処理機能を追加するには、

  1. どの種類の割込みを有効にするか、という「割込み処理設定」
  2. 割込みが発生した場合にどのような処理をするか、という「割込み処理プログラム」

が必要です。以下、それぞれについて詳しく説明します。

1. どの種類の割込みを有効にするか「割込み処理の設定」

PICマイコンはデフォルトではすべての種類の割込みは無効になっています。割込み処理を行う場合、必要な割込みを有効化する必要がありますが、有効化する設定はちょっと複雑です。

厳密ではありませんが、PICマイコン内部の割込みの有効化設定は以下のようになっています。

Pic app 18 interrupt enable switch

例えば、ピンの入力値に変化があった場合に割込み処理を行いたい場合は、まずは「入力値の変化があったら割込みを有効にする」という設定を行います。ただ、これだけではピンの入力値変化があった場合でも割込みは発生しません。さらに、そもそも割込みを発生させるかどうか、という元栓となるような有効化設定がありますので、この設定を行います。

ここまでのことをまとめると、割込みを有効化するには、

  • 割込み種類別の有効化の設定を行い、
  • 割込み自体の有効化の設定を行う

という2つの設定が必要です。

さらに、ピンの入力値変化があった場合に割込みを行う場合、追加の設定が必要です。

ピンの入力値変化といっても、「0→1」の変化と「1→0」の変化があります。どちらの変化が起こったときに割込みを発生させるか、という設定が必要になります。

ここまでをまとめると、ピンの入力値変化があった場合に割込み処理を行いたい場合、結局以下の3つの設定が必要になります。

  • ピンの入力値変化の種類の設定を行い、
  • 割込み種類別の有効化の設定を行い、
  • 割込み自体の有効化の設定を行う

それでは、これら3つの設定をどのレジスタで行うか説明します。今回はRA3ピンの値が「1→0」になったときに割込みを発生する、というケースの設定レジスタになります。他の割込みについてはデータシートを参照いただければと思います。

Pic app 18 ioc3 interrupt

これらのレジスタを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を点滅する、という割込み処理を追加したプログラムを作成してみます。

繰り返しになりますが、割込み処理の追加は以下の内容を追加する必要があります。

  1. 割込み処理の有効化
  2. 割込み処理が必要ない場合は無効化
  3. 割込み処理プログラム
    • 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以降の書式に変更
通知の設定
通知タイミング
guest
17 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
kazu
kazu
1 年 前

お世話になります。割り込み処理で質問があります。
ピンへの入力がhigh(5V)の時に割り込みさせたい場合は、IOCAP1=1とかにすればいいと思っていたのですが、IOCAP1=1の設定で、ピンへの入力がないのに割り込み処理が走ります。ピンをGNDに接続すると割り込みは起きなくなります。
何かTRISA以外の設定も必要なのでしょうか?

kazu
kazu
返信  管理者
1 年 前

早々の返信ありがとうございます。
もっと後の記事に出ていたんですね。
プルダウン抵抗入れて、うまく動作しました。
ありがとうございます。

gonta
gonta
3 年 前

大変やさしくて詳しい解説を有り難う御座います。

割り込み処理をしっかりと理解しようと第16回からプリントアウトして読んでいます。

この回のサンプルプログラムを手打ちで入力して,作動させたましたが、
RA3スイッチを押すと、カウントは止まりますが割り込み関数の高速点滅をしません。
プログラムリストとにらめっこして点検しましたが,間違いは無いはずでした。
サンプルプログラムをコピペして作動させると、しっかりと割り込み関数の点滅をします。

両方のリストをプリントアウトしてつき合わせてみました。
有りました。 コンフィギュレー設定で、「VLP」設定が、「ON」になっていました。まさか思いながら、OFFに変更して、割り込み関数が多々しく動作する様になりました。

ゴチャゴチャ書きましたが、このコンフィギュレーション設定が、割り込み関数に関係ストは思えないのですが、如何でしょうか。

よろしくお願い致します。

gonta
gonta
返信  管理者
3 年 前

早速の回答頂き、有り難う御座います。

割り込み処理関数とコンフィギュレーション設定には特に関係ないとのことで,
一安心です。 改めて基礎編のコンフィギュ項目を読み返しました。

マイクロチップ社のIDEや無料コンパイラーは可成り癖があるとも聞きます。
又、私のパソコンもどうも勝手な動きをしている気配が感じられます。

PIC User
PIC User
返信  管理者
2 年 前

本件、LVP = ONにすると、MCRLEの設定に関係なくRA3はMCLR機能に固定されるからです。

iwa
iwa
4 年 前

お世話になっています。
このプログラムの割り込みフラグをクリアは
IOCAF = 0;
となっていますが、
IOCAF3 = 0;
ではないでしょうか。
それとも番号を付けないとAポート全体を意味するのでしょうか。

iwa
iwa
返信  iwa
4 年 前

すみません。投稿先を間違いました。19回の内容です。

iwa
iwa
返信  iwa
4 年 前

IOCAFのレジスタ内容をデーターシートで確認し、自己解決しました。
割り込みスイッチを複数付けてどれが押されたなど便利そうですね。

管理者
管理者
返信  iwa
4 年 前

ご連絡が遅くなりすみませんでした。
すでに解決されたとのことでよかったです。

ご指摘どうもありがとうございました。第19回の「IOCAF = 0;」は「IOCAF3 = 0;」にしたほうがいいです。すみませんでした。後ほど訂正しておきます。

なお、コメントいただいている通り、IOCAFフラグは入力設定可能なピンを個別に判定できますので、押されたスイッチに応じて処理を変える、ということができます。スイッチ処理は割り込みで処理すると楽ですので、何かご自身で作られるときに活用してみてください。

sho
sho
5 年 前

初めまして,
最近PICをいじりはじめたものです.

示されたものをコピペして,XC8(v2.05)でコンパイルすると
つぎの3ヵ所でエラーになってしまいます.

#include
for(unsigned char i=0; i<10; i++) {
for( unsigned char i=0; i<2; i++) {

forのところは i<10 などとすればよいことがわかったのですが,
調べてみると普通のc言語では説明に出て来るので,picで使えないと言うことでしょうね.
の意味が分かりません.これを削除するとOKのようです.
作りたいのは,よくクリスマスイルミネーションで,ボタンを押すごとに異なるパターンで
LEDが点滅するものです.
こちらを応用すればできるような気がしたのですが…
よろしくご教授お願いいたします.

管理者
管理者
返信  sho
5 年 前

shoさま、
コメントどうもありがとうございました!

ご指摘いただいた部分は間違ってます。修正しました。すみませんでした。
実は、この記事の原稿では正しいコードになっているのですが、このサイトで使用しているWordPressに記事を投稿するときに「<」などが変換されてしまうようです(「はhtmlタグと判断されて、勝手に「でクローズされてしまうようです…意味不明です…)。そのため、他の記事でも同様のことが発生していると思いますので、もしコードをビルドしてもエラーになる、ということがありましたらこれが原因と思われます。これから全部の記事のコードを修正していこうと思いますが、、、ちょっと時間かかりそうです。

PICマイコンは普通のC言語を使用できますので、普通のC言語の書籍を参考にしていただけれぱ大丈夫です。

クリスマスイルミネーションを製作されるということで、自分で仕様を決められるのはとても楽しいですよね。色々な光り方をプログラムして、それをボタンで選択するのは面白いですよね。

・パターン選択
 書かれている通り、割り込み処理でボタンを検知してパターンを変えるのがいいと思います。PICマイコンの普段の処理はイルミネーション点灯パターンの制御をしていますので、ボタンの検知をするのはちょっと大変です。そこで、IOCの割り込み検知を使うのがスマートだと思います。また、ボタンも複数用意して、点滅のパターンを変えるボタン、スピードを変えるボタンなどかあると色々と細かい制御ができそうですよね。世界一細かい制御ができるクリスマスイルミネーション、っていうのも面白いと思います!

・使用するLED
 クリスマスイルミネーションですと、LEDの数が多い方がいいと思います。普通のLEDをPICマイコンに接続しても10個〜20個ぐらいが回路的にも限界ですが、「WS2812B」というLEDを使用したテープLEDがオススメです。amazonで「WS2812」で検索すると色々出てきますが、300灯(LED300個)で3500円程度です。数が多くてちょっと高めですが、好きなところでハサミで切って使うことができます。またPICマイコンの1本の信号線で、1個1個、個別に1677万色の指定ができます。「WS2812」を使った制御の様子はYoutubeで動画などもありますので探してみてください。

他に不明点ありましたらご質問いただければと思います。

sho
sho
返信  管理者
5 年 前

庄司です.

お忙しい中(多分,この分野のお仕事?),すみやかな回答をいただき,恐縮しております.
そういうことがあるのですね.
全部を直すのは骨だと思います.
なにか,指摘があったらでよろしいかと思います.
どうもありがとうございます.

その他の記事も,大変参考になりますし,
原理を詳しく解説して頂いているので,本当に助かっています.
70歳で始めたPICです.
また,なにかありましたらご支援よろしくお願いいたします.

ありがとうございました.

目次