PICマイコン(PIC12F675)のINT機能の使い方

組み込みエンジニア

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

マイコンのソフトを開発していると外部からパルスを入力してタイミングの同期をとったり処理をしたりすることがあります。DIピンの機能の一つであるINT機能を使うことで割り込みを発生させ同期をとるような処理を作ることができます。

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

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

INT(外部割込み)機能

INT機能は多くのマイコンに実装されている機能です。パルス波形を入力した時の立ち上がりや立下りを検出して割り込みを発生させたり、パルスの電圧レベルで判定して割り込みを発生させることができます。

RXマイコンになると機能が多彩で外部割込みの他にインプットキャプチャと呼ばれている機能があり波形の間隔をカウントしておきカウントから計算して周波数を求めることができます。

エッジの検出の説明図

INT端子に50Hz(60Hz)のパルスが入力された場合立ち上がりエッジまたは立下りエッジの周期で割り込みが入ります。

外部の波形とプログラムの同期を取りたいときなどに有効な機能になります。

PIC12F675においてはレベル検出の機能は実装されていないため波形のエッジのみでの検出になります。またインプットキャプチャのようにカウントする機能を持っていないためパルスの間隔が50Hz(60Hz)になっていることは保証できません。

PIC12F675においてINT端子で商用周波数を管理したい場合はタイマー機能を併用することで周波数が大きく外れたときの監視ができます。

PIC12F675で商用周波数を管理する場合の例
PIC12F675で商用周波数を管理する場合の例

50msよりも時限の長い40msでタイマーをINT割り込みの際に起動しINT割り込みが正常なときに初期値をセットしなおすことでオーバーフローしない状態にしています。

異常によってパルスが途切れたときにタイマーの初期値の更新ができなくなるためタイマーオーバーフローの割り込みが発生することで異常の検出ができます。

正弦波を入力する際はコンパレータなどを使用して正弦波から矩形波に変換してマイコンのINT端子に入力するとよいでしょう。

今回はDOとTMR1を組み合わせて模擬のパルスを生成しINTピンに入力します。

INT機能を使用するための設定

INT機能を使用するまでの初期化について説明していきます。I/Oピンの設定やTMR1の設定については下記記事を参考にしてください。

PICマイコン(PIC12F675)のI/Oポート設定と使い方

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

割り込み許可の設定

INT機能を使用するためには割り込み許可のレジスタであるINTCONの設定を行う必要があります。

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

bit4のINTEがINT機能による割り込み許可になるので1をセットします。また割り込み全体の許可であるbit7とTMR1の割り込み許可をするためにbit6に1をセットします。

bit1はINT機能において条件が満たされると1がセットされるフラグとなっています。ユーザーでフラグをクリアする必要があります。

割り込みのエッジの選択

INT機能が立ち上がりエッジで動作するか立ち下がりエッジで動作するかを選択する必要があります。OPTION_REGレジスタの設定を行います。

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

bit6でエッジの選択を行います。今回は立ち上がりエッジで使用するので1をセットします。

割り込みの設定と初期化

#include <xc.h>
//--------------定数定義----------------------------
#define _XTAL_FREQ	4000000
#define	TIME_40HZ_H	0x9E
#define	TIME_40HZ_L	0x58 

//--------------変数定義----------------------------
char    cnt;

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

_XTAL_FREQはdelayマクロを使用する際に定義しておく必要があります。内部クロック4MHzとなるので4000000になります。delay関数は模擬パルスを生成する際に使用します。またTMR1は25ms(40Hz)でオーバーフローするように初期値を設定しています。

INT機能の動作確認

INT機能の動作確認の回路図
INT機能の動作確認の回路図

GP1で50Hzのパルスを模擬してINT端子に入力します。50Hzは20msなのでパルスを作るために10ms毎にGP1を反転させて模擬します。

模擬は__delay_ms(10)を使用します。SW1を押すとLED3を点灯してGP1の反転を停止します。GP1の更新が停止しタイマ1が40回(1s)オーバーフローした時にLED1を点灯するようにします。

    while(1){
        CLRWDT();//WDTクリア
        
        if( GPIO3 == 1){
            GPIO5 = 1; //LED3を点灯  
        }
        else{
            GPIO5 = 0; //LED3を消灯            
            GPIO1 = 1;  //立ち上がりパルス
            __delay_ms(10); //10msの間High
            GPIO1 = 0;  //立下りパルス
            __delay_ms(10); //10msの間High
        }
    }
//割り込み関数
void __interrupt() intr( void){
    
    if( INTE == 1 && INTF == 1){  //立ち上がりエッジで割り込み
        INTF = 0; //INTフラグをクリア
        GPIO0 = 1; //LED1を消灯
        cnt = 0;
        T1CON = 0x00;
        TMR1H = TIME_40HZ_H; //タイマ初期化
        TMR1L = TIME_40HZ_L; //タイマ初期化
        TMR1ON = 1; //タイマ1ON
    }
    if( TMR1IE == 1 && TMR1IF == 1){ //タイマ1の割り込みであるか
        TMR1IF = 0; //割り込みフラグをクリア
        
        if( cnt < 40 ){
            ++cnt;
        }
        else{
            GPIO0 = 0; //LED1を点灯
        }
        T1CON = 0x00;
        TMR1H = TIME_40HZ_H; //タイマ初期化
        TMR1L = TIME_40HZ_L; //タイマ初期化
        TMR1ON = 1; //タイマ1ON
    }
}

GP3が押されていないときに10ms毎にGP1を反転させます。__delay_ms(10)のソフトウェアウェイトを使ってパルスを生成しています。

GP1のパルスが生成されるとエッジ入力となるためINT割り込みが立ち上がりエッジ(立下りに設定した場合は立下りエッジ)ごとに発生します。

__delay_ms(数値)や__delay_us(数値)は便利なようですが、メインループ内で一時停止しているようなものなので基本的には多用しないほうが良いのですが、模擬波形を作る程度の処理にしか使わないため今回は使用しています。

PIC12F675においては割り込み関数が共通なのでif文でどの割り込みが発生しているのかを区別して処理を行っています。

通常はTMR1がオーバフローすることがないのでINT割り込みのみとなりますが、SW1を押して25ms間の間にINT機能による割り込みがなかった場合にはTMR1がオーバフローします。

TMR1の割り込みが40回連続(1s間)は発生すると異常とみなしてLED1を点灯するようにしています。

INT割り込み内ではINTフラグをクリアしLED1を消灯とTMR1がオーバフローしないように初期値で更新してリスタートしています。

INT機能が正常に動作していることが分かりにくいため空き端子であるGP4にLEDと実装して点灯/消灯させるのもありと思います。

ソースコード全体

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

// 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>
//--------------定数定義----------------------------
#define _XTAL_FREQ	4000000
#define	TIME_40HZ_H	0x9E
#define	TIME_40HZ_L	0x58 

//--------------変数定義----------------------------
char    cnt;

void main(void) {
    //各種初期化    
    ADCON0 = 0x00;  //ADC使用しない 
    ANSEL = 0x00;   //アナログモードは使用しない
    CMCON = 0x07;   //コンパレータ使用しない
    TRISIO = 0x0C;  //GP2・GP3はDI その他はDO
    GPIO = 0x00;    //ポートの設定 1:High 0:Low
    OPTION_REG = 0x4F;  //INT機能・プリスケーラ128 WDTで使用
    //割り込み設定
    INTCON = 0xD0;  //割り込み許可とPIE1を許可とINT許可
    PIE1 = 0x01;    //タイマ1割り込みを許可
    //タイマー1初期化
    T1CON = 0x00;
    TMR1H = TIME_40HZ_H; //タイマ初期化
    TMR1L = TIME_40HZ_L; //タイマ初期化
    TMR1IF = 0; //割り込みクリア 
    TMR1ON = 1; //タイマ1ON
    //タイマー1初期化 END
    cnt = 0;
    GPIO0 = 1;
    //各種初期化 END
    
    while(1){
        CLRWDT();//WDTクリア
        
        if( GPIO3 == 1){
            GPIO5 = 1; //LED3を点灯  
        }
        else{
            GPIO5 = 0; //LED3を消灯            
            GPIO1 = 1;  //立ち上がりパルス
            __delay_ms(10); //10msの間High
            GPIO1 = 0;  //立下りパルス
            __delay_ms(10); //10msの間High
        }
    }
}
//----------------割り込み関数---------------------------
void __interrupt() intr( void){
    
    if( INTE == 1 && INTF == 1){  //立ち上がりエッジで割り込み
        INTF = 0; //INTフラグをクリア
        GPIO0 = 1; //LED1を消灯
        cnt = 0;
        T1CON = 0x00;
        TMR1H = TIME_40HZ_H; //タイマ初期化
        TMR1L = TIME_40HZ_L; //タイマ初期化
        TMR1ON = 1; //タイマ1ON
    }
    if( TMR1IE == 1 && TMR1IF == 1){ //タイマ1の割り込みであるか
        TMR1IF = 0; //割り込みフラグをクリア
        
        if( cnt < 40 ){
            ++cnt;
        }
        else{
            GPIO0 = 0; //LED1を点灯
        }
        T1CON = 0x00;
        TMR1H = TIME_40HZ_H; //タイマ初期化
        TMR1L = TIME_40HZ_L; //タイマ初期化
        TMR1ON = 1; //タイマ1ON
    }
}
//---------------------end file----------------------------

関連リンク

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

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

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

GEEKJOB-未経験からITエンジニアに【オンライン無料体験】

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

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