PICマイコン(PIC12F675)の割り込みの設定と使い方

組み込みエンジニア

こんにちは、ENGかぴです。

マイコンのソフトを開発していると割り込みをよく使用します。PIC12F675の割り込みは共通であり割り込み要因を判別して処理する必要があります。割り込みを使用するために必要なレジスタ設定などについて説明しています。

本記事の内容は、下記記事の内容を割り込みを使って実現する方法を説明しています。割り込みを使用せずに管理したい場合はこちらを参考にしてください。

PICマイコン(PIC12F675)のタイマー1の設定と使い方

割り込みの考え方と注意事項については下記を参考にしてください。

PICマイコン(PIC12F675)の割り込みの考え方と注意事項

PIC12F675を使ってマイコンの動きを勉強するためにPIC12F675の機能でできることについてまとめています。

PICマイコン(PIC12F675)で実現できる機能と解説リンクまとめ

TMR1割り込みの設定

PIC12F675の割り込みの設定について説明します。TMR1割り込みに関わるレジスタと割り込み全体に関わるレジスタを設定する必要があります。

INTCONレジスタの設定

引用:PIC12F675のデータシート(INTCONレジスタ)
引用:PIC12F675のデータシート(INTCONレジスタ)

bit0はポートチェンジ割り込みが発生した時のフラグです。GP0からGP5までのポートに変化が生じたときにGPIFに1をセットして割り込みが発生します。ユーザーで0をセットしてクリアする必要があります。

bit1はGP2/INTピンにおいての外部割込みが発生した場合にINTFに1をセットして割り込みを発生します。ユーザーで0をセットしてクリアする必要があります。

bit2はタイマー0のオーバーフローフラグでタイマー0がオーバフローしたときに1がセットされます。ユーザーで0をセットしてクリアする必要があります。

bit3はポートチェンジ割り込みを使用するかを選択してセットします。1をセットするとポートチェンジ割り込みが有効になります。0をセットすると無効になります。

bit4はGP2/INT外部割込みを使用するかを選択します。1をセットするとGP2/INT外部割込みが有効になります。0をセットすると無効になります。

bit5はタイマー0のオーバーフロー割り込みを使用するかを選択します。1をセットするとタイマー0のオーバーフロー割り込みが有効になります。0をセットすると無効になります。

bit6は、このレジスタ内に無い他の割り込みを使用するかを選択します。1を選択すると他のレジスタ(PIE1レジスタ)の割り込み設定を有効にします。0をセットすると無効になります。タイマー1オーバーフローやAD変換完了割り込みなどが他のレジスタで選択することになるので1をセットします。

bit7は割り込みのすべてを許可するかを選択します。1をセットすると割り込みが有効になります。0をセットするとすべての割り込みが禁止になります。割り込みを使用する場合はかならずセットする必要があります。

PIE1レジスタの設定

引用:PIC12F675のデータシート(PIEレジスタ)
引用:PIC12F675のデータシート(PIEレジスタ)

bit0はタイマー1のオーバーフロー割り込みを使用するかを選択します。タイマー1のオーバフロー割り込みを使用するので1をセットします。

bit2-1とbit5-4は使用しません。リードすると0となります。

bit3はコンパレータ割り込みを使用するかを選択します。1をセットするとコンパレータ割り込みが有効になります。0をセットすると無効になります。

bit6はADコンバータ変換完了割り込みを使用するかを選択します。1をセットするとコンパレータ割り込みが有効になります。0をセットすると無効になります。

bit7はEEPROM書き込み完了割り込みを使用するかを選択します。1をセットするとEEPROM書き込み完了割り込みが有効になります。0をセットすると無効になります。

PIRレジスタ(PIE1と連動)

引用:PIC12F675のデータシート(PIR1レジスタ)
引用:PIC12F675のデータシート(PIR1レジスタ)

bit0はタイマー1がオーバーフローした時に1をセットして割り込みを発生させます。割り込みを使用していない場合は1をセットしたままになります。割り込みの有無にかかわらず、ユーザーで0をセットしてクリアする必要があります。

bit2-1とbit5-4は使用しません。リードすると0となります。

bit6はAD変換完了が完了した時に1をセットして割り込みを発生させます。割り込みを使用していない場合は1をセットしたままになります。割り込みの有無にかかわらずユーザーで0をセットしてクリアする必要があります。

bit7はEEPROM書き込み完了時に1をセットして割り込みを発生させます。割り込みを使用していない場合は1をセットしたままになります。割り込みの有無にかかわらずユーザーで0をセットしてクリアする必要があります。

割り込み動作確認の回路図

割り込み動作確認の回路図
割り込み動作確認の回路図

GP0とGP2を操作してLED1とLED2が点灯/消灯するようにタイマを実装します。SW1を押すとLED3が点灯するようにします。

割り込みの設定と初期化

初期化を行うにあたってはTMR1の設定を行う前に割り込み処理を行います。順序はどちらでもいいのですが、TMR1をスタート(TMR1ON)する前に割り込みの設定をしておくとよいでしょう。

#include <xc.h>
//--------------変数定義----------------------------
char    cnt;

void main(void) {
    //各種初期化    
    ADCON0 = 0x00;  //ADC使用しない 
    ANSEL = 0x00;   //アナログモードは使用しない
    CMCON = 0x07;   //コンパレータ使用しない
    TRISIO = 0x08;  //GP3はDI・その他はDO
    GPIO = 0x00;    //ポートの設定 1:High 0:Low
    OPTION_REG = 0x0F;  //プリスケーラ128 WDTで使用
    //割り込み設定
    INTCON = 0xC0;  //割り込み許可とPIE1を許可
    PIE1 = 0x01;    //タイマ1割り込みを許可
    //タイマー1初期化
    T1CON = 0x00;
    TMR1H = 0x3C;//タイマ初期化
    TMR1L = 0xB0;//タイマ初期化
    TMR1IF = 0;//割り込みクリア 
    TMR1ON = 1;//タイマ1ON
    //タイマー1初期化 END
    cnt = 0;
    //各種初期化 END

割り込み設定はINTCONとPIE1のTMR1に関わるビットをセットするだけで使用することができます。割り込み条件を通知するTMR1IFのフラグがセットされていた場合、次の割り込みがスタートしないため念のためクリアしています。

スタート時に変数がすべてクリアされることが明らかであればクリアする必要はありませんが、不定値となって不良動作とならないために初期化をするほうが良いと思います。

割り込みの関数を作る

PIC12F675においては割り込みは共通になっています。割り込み関数を作るとコンパイラと連携しているのでinterruptの構造体の関数を準備すると使用できるようになります。XC8コンパイラのバージョンによって表記が変更になっているので注意が必要です。

割り込み関数の仕様について

XC8コンパイラのバージョンが2.10より前は
void interrupt intr( void ){}を準備すると(intrは任意)

XC8コンパイラのバージョンが2.10以上では void __interrupt() intr( void ){}となります。(アンダーバーは2つ)

MPLAB_XC8_C_Compilerのユーザーズマニュアル4.9INTERRUPTSの項目に記述について記載があります。4.9.1 Writing an Interrupt Service Routineに 詳細が書かれています。

コンパイラのバージョンによっては表記が変わることもあるのでインストールし直したときに動かなくなった場合は仕様を確認する必要があります。

XC8の2.1以前のバージョンで作成してコンパイルした場合においてはバージョンが2.10以上になったとしてもそのまま使えるようです。

メインの処理と割り込み関数の処理を作る

    while(1){
        CLRWDT();
        di();
        if( cnt >= 5){
            cnt -=5;
            GPIO0 = ~GPIO0; //ロジックを反転して代入
            GPIO2 = ~GPIO2; //ロジックを反転して代入
        }
        ei();
        
        if( GPIO3 == 1){
            GPIO5 = 1;
        }
        else{
            GPIO5 = 0;
        }
    }
//------------------割り込み関数-------------------------------
//void interrupt intr( void ){}    XC8 コンパイラが2.1以前の表記
void __interrupt() intr( void){
    
    if( TMR1IE == 1 && TMR1IF == 1){ //タイマ1の割り込みであるか
        TMR1IF = 0;//割り込みフラグをクリア
        ++cnt;
        TMR1ON = 0;
        TMR1H = 0x3C;//タイマ初期化
        TMR1L = 0xB0;//タイマ初期化
        TMR1ON = 1;//タイマ1ON
    }
}

割り込み関数をmain関数の外に作ります。__interrupt()のアンダーバーは2つあります。__interrupt()の構造のintrが割り込みの条件になると呼び出されて割り込み処理になります。

PIC12F675は割り込みが共通なので割り込み関数が呼び出され時どの内容で呼び出されたのかを切り分けて使用します。

TMR1割り込み許可であるTMR1IEとTMR1Fの2つを満たすときにタイマー1の割り込みであると判断して内部の処理を行います。割り込み関数内部ではTMR1を50msでオーバーフローさせるための初期値をセットします。

メイン関数では割り込み内で更新するcntを参照して更新しているので参照後に割り込みに遷移して更新されないように、割り込みを禁止にしてから条件を確認するにしています。

今回の例では割り込みでcntを更新して5以上であればcntを-5するだけの処理なので割り込みを禁止する必要はないのですが、AD変換のデータなどで処理を変化させたい場合などにおいては禁止する必要があります。

割り込みで50ms経過したらcntを更新しておき5回以上になるとGP0とGP2を変化しています。

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。チェックはしておりますがコメントなど細かな部分で間違っている可能性があります。参考としてお使いいただければと思います。

// CONFIG
#pragma config FOSC = INTRCIO  
#pragma config WDTE = ON   
#pragma config PWRTE = OFF   
#pragma config MCLRE = OFF   
#pragma config BOREN = OFF  
#pragma config CP = OFF     
#pragma config CPD = OFF   

#include <xc.h>
//--------------変数定義----------------------------
char    cnt;

void main(void) {
    //各種初期化    
    ADCON0 = 0x00;  //ADC使用しない 
    ANSEL = 0x00;   //アナログモードは使用しない
    CMCON = 0x07;   //コンパレータ使用しない
    TRISIO = 0x08;  //GP3はDI・その他はDO
    GPIO = 0x00;    //ポートの設定 1:High 0:Low
    OPTION_REG = 0x0F;  //プリスケーラ128 WDTで使用
    //割り込み設定
    INTCON = 0xC0;  //割り込み許可とPIE1を許可
    PIE1 = 0x01;    //タイマ1割り込みを許可
    //タイマー1初期化
    T1CON = 0x00;
    TMR1H = 0x3C;//タイマ初期化
    TMR1L = 0xB0;//タイマ初期化
    TMR1IF = 0;//割り込みクリア 
    TMR1ON = 1;//タイマ1ON
    //タイマー1初期化 END
    cnt = 0;
    //各種初期化 END
    
    while(1){
        CLRWDT();
        di();
        if( cnt >= 5){
            cnt -=5;
            GPIO0 = ~GPIO0; //ロジックを反転して代入
            GPIO2 = ~GPIO2; //ロジックを反転して代入
        }
        ei();
        
        if( GPIO3 == 1){
            GPIO5 = 1;
        }
        else{
            GPIO5 = 0;
        }
    }
}
//------------------割り込み関数-------------------------------
//void interrupt intr( void ){}    XC8 コンパイラが2.1以前の表記
void __interrupt() intr( void){
    
    if( TMR1IE == 1 && TMR1IF == 1){ //タイマ1の割り込みであるか
        TMR1IF = 0;//割り込みフラグをクリア
        ++cnt;
        TMR1ON = 0;
        TMR1H = 0x3C;//タイマ初期化
        TMR1L = 0xB0;//タイマ初期化
        TMR1ON = 1;//タイマ1ON
    }
}
//---------------------end file----------------------------

関連リンク

PICマイコンを使ってマイコンのレジスタの設定やMPLAB X IDEのプラグインであるMCCを使用して動作確認したことについてまとめています。

PICマイコン(PIC12F675)で実現できる機能と解説リンクまとめ

PICマイコン(PIC16F1827)で実現できる機能と解説リンクまとめ

Code Camp完全オンラインのプログラミング個人レッスン【無料体験】

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました