今回は、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以降の書式に変更 |
お世話になります。割り込み処理で質問があります。
ピンへの入力がhigh(5V)の時に割り込みさせたい場合は、IOCAP1=1とかにすればいいと思っていたのですが、IOCAP1=1の設定で、ピンへの入力がないのに割り込み処理が走ります。ピンをGNDに接続すると割り込みは起きなくなります。
何かTRISA以外の設定も必要なのでしょうか?
ご質問どうもありがとうございます。
ピンの入力が 0→1 に変化した時に割り込みを発生させたい場合は、IOCAP1レジスタを1に設定すれば動作するはずです。設定としては以下のようになります。
TRISA1 = 1 : RA1ピンを入力ピンに設定
IOCAP1 = 1 : RA1ピンが0→1に変化した時に割り込み発生するように設定
IOCIE = 1 : ピンの変化による割り込みを許可する
GIE = 1 : 割り込みを許可する
「GNDに接続すると割り込みは起きなくなる」とのことですので、「入力がないのに割り込み処理が走る」というのはおそらくRA1ピンに何も接続されていないことが原因のように思います。
RA1ピンを入力ピンにした場合、ピンに何も接続されていない状態では、RA1ピンの入力は0か1か確定しません。「入力ピンに何も接続しない」というのは「入力が0」ということではありませんのでご注意ください。
RA1ピンにスイッチを接続して、0→1に変化した時に割り込みを発生させたい場合、RA1ピンにプルダウン抵抗を入れる必要があります。なお、プルダウン抵抗の入れ方がわからないようでしたら以下の記事もご参考にいただければと思います。
https://tool-lab.com/pic-basic-24/
早々の返信ありがとうございます。
もっと後の記事に出ていたんですね。
プルダウン抵抗入れて、うまく動作しました。
ありがとうございます。
動作したようでよかったです!
ところで、先ほどのコメント欄でご案内した記事は「基礎編」の第24回の記事になります。
現在お読みいただいている割り込み処理などの記事は「応用編」の記事になります。応用編は基礎編の内容を前提として書いていますので、もし基礎編をお読みでない場合、一度基礎編をご確認いただけると応用編の理解が深まると思います。
大変やさしくて詳しい解説を有り難う御座います。
割り込み処理をしっかりと理解しようと第16回からプリントアウトして読んでいます。
この回のサンプルプログラムを手打ちで入力して,作動させたましたが、
RA3スイッチを押すと、カウントは止まりますが割り込み関数の高速点滅をしません。
プログラムリストとにらめっこして点検しましたが,間違いは無いはずでした。
サンプルプログラムをコピペして作動させると、しっかりと割り込み関数の点滅をします。
両方のリストをプリントアウトしてつき合わせてみました。
有りました。 コンフィギュレー設定で、「VLP」設定が、「ON」になっていました。まさか思いながら、OFFに変更して、割り込み関数が多々しく動作する様になりました。
ゴチャゴチャ書きましたが、このコンフィギュレーション設定が、割り込み関数に関係ストは思えないのですが、如何でしょうか。
よろしくお願い致します。
コメントいただきどうもありがとうございます。
申し訳ございません、英語系のサイトを含めて検索してみたのですが、
LVPと割り込み処理の関係についての記事は見つかりませんでした。
原因を考えてみたのですが、なかなか思い当たらない、というのが現状です。
LVPについてわかりづらいかもしれませんが簡単にご説明します。
LVPはLow Voltage Programming = 低電圧プログラミング(書き込み)の略です。
PICKitを使ってPICマイコンにプログラムを書き込む際、PICKitはVppピンに
高い電圧(9V以上)をかけて書き込みをしています。ただ、プログラム書き込み器を
自作する場合など、高い電圧を発生する回路を作るのは面倒ですので、
最近のPICマイコンにはLVP機能が搭載され、PICマイコンの電源電圧で
プログラムの書き込みができるようになっています。例えば3.3V動作のPICマイコンでは、
Vppの電圧は3.3Vで書き込みができるようになっています。
PICマイコン側のLVP設定のデフォルトはONになっています。
このようにLVPの設定は、単にプログラムの書き込みの時の話ですので、
割り込みに関係する点はなさそうです。
ただ、LVPをOFFに変更する、つまり高い電圧で書き込みをすることで
動作した、というのは、LVPがONの場合、何かの書き込みができない、
あるいは失敗しているのかもしれません。
調べた範囲、考えた範囲ではここまでの情報になってしまいます。
申し訳ございません…
早速の回答頂き、有り難う御座います。
割り込み処理関数とコンフィギュレーション設定には特に関係ないとのことで,
一安心です。 改めて基礎編のコンフィギュ項目を読み返しました。
マイクロチップ社のIDEや無料コンパイラーは可成り癖があるとも聞きます。
又、私のパソコンもどうも勝手な動きをしている気配が感じられます。
今回の件は不思議ですが、今後また状況が変わるかもしれませんので、PICマイコンを使うときは頭の片隅に置いておこうと思います。
コメントいただきどうもありがとうございました。
本件、LVP = ONにすると、MCRLEの設定に関係なくRA3はMCLR機能に固定されるからです。
コメントいただきどうもありがとうございました。
LVP=ONにする
↓
プログラム書込みモードに移行するための高電圧印加は使わない
↓
MCLR信号を使ってプログラム書込みモードに移行するしかない
↓
LVP=ONの場合は強制的にRA3はMCLR機能に固定される
という感じでしょうかね。
情報いただきどうもありがとうござまいした!
勉強になります!
お世話になっています。
このプログラムの割り込みフラグをクリアは
IOCAF = 0;
となっていますが、
IOCAF3 = 0;
ではないでしょうか。
それとも番号を付けないとAポート全体を意味するのでしょうか。
すみません。投稿先を間違いました。19回の内容です。
IOCAFのレジスタ内容をデーターシートで確認し、自己解決しました。
割り込みスイッチを複数付けてどれが押されたなど便利そうですね。
ご連絡が遅くなりすみませんでした。
すでに解決されたとのことでよかったです。
ご指摘どうもありがとうございました。第19回の「IOCAF = 0;」は「IOCAF3 = 0;」にしたほうがいいです。すみませんでした。後ほど訂正しておきます。
なお、コメントいただいている通り、IOCAFフラグは入力設定可能なピンを個別に判定できますので、押されたスイッチに応じて処理を変える、ということができます。スイッチ処理は割り込みで処理すると楽ですので、何かご自身で作られるときに活用してみてください。
初めまして,
最近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さま、
コメントどうもありがとうございました!
ご指摘いただいた部分は間違ってます。修正しました。すみませんでした。はhtmlタグと判断されて、勝手に「 でクローズされてしまうようです…意味不明です…)。そのため、他の記事でも同様のことが発生していると思いますので、もしコードをビルドしてもエラーになる、ということがありましたらこれが原因と思われます。これから全部の記事のコードを修正していこうと思いますが、、、ちょっと時間かかりそうです。
実は、この記事の原稿では正しいコードになっているのですが、このサイトで使用しているWordPressに記事を投稿するときに「<」などが変換されてしまうようです(「
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で動画などもありますので探してみてください。
他に不明点ありましたらご質問いただければと思います。
庄司です.
お忙しい中(多分,この分野のお仕事?),すみやかな回答をいただき,恐縮しております.
そういうことがあるのですね.
全部を直すのは骨だと思います.
なにか,指摘があったらでよろしいかと思います.
どうもありがとうございます.
その他の記事も,大変参考になりますし,
原理を詳しく解説して頂いているので,本当に助かっています.
70歳で始めたPICです.
また,なにかありましたらご支援よろしくお願いいたします.
ありがとうございました.