割り込みの使い方


【割り込み処理】

CCS C Compiler では割り込み処理の枠組みを自動生成してくれます。
そのためのプリプロセッサ関数が用意されており、比較的簡単に割り
込みを扱うことが出来ます。


《割り込み用プリプロセッサ関数》

プリプロセッサ関数

機能・その他

#INT_xxx この直後の関数がxxx要因の割り込みを扱う関数であることを指定する。
#INT_DEFAULT この直後の関数が割り込み要因が見つからない時の割り込み処理関数であることを指定する。
#INT_GLOBAL この直後の関数をコンパイラが自動生成する割り込み処理の代替えとして使うことを指定する。
この時には分岐処理、レジスタ待避など全てが自動生成されないので、関数の中でそれらを組込む必要があり、使い方に注意が必要
  割込み要因 xxx には下記の種類がある。
   #INT_EXT     外部割り込み(INT(RB0))
   #INT_RTCC     タイマ0オーバーフロー割り込み
   #INT_RB      RB4-RB7の変化割り込み
   #INT_AD     A/Dコンバータ変換終了割り込み
   #INT_EEPROM   EEPROM書き込み完了割り込み
   #INT_TIMER1   タイマ1オーバーフロー割り込み
   #INT_TIMER2   タイマ2  〃
   #INT_CP1     CCP1キャプチャ割り込み
   #INT_CCP2    CCP2キャプチャ割り込み
   #INT_SSP     Smart Serial Port(SPI,I2C)割り込み
   #INT_PSP     パラレルポート割り込み
   #INT_TBE     SCIシリアルデータ送信割り込み
   #INT_RDA     SCIシリアルデータ受信割り込み
   #INT_COMP    コンパレータ一致割り込み
 

【#INT_xxx関数の処理内容】

#INT_xxxプリプロセッサ関数によりコンパイラは次の様な実行プログラム
を自動生成します。

・割り込み時のジャンプ命令を割り込みベクトルにセットする。
・レジスタやSTATUSを待避、復旧する処理を生成する。
・割り込みフラグをリセットする命令を生成する。

このお陰で、割り込み処理関数の中では割り込みハードウェアに関する
処理
のことを意識せず、本来すべきアプリケーションの処理だけをすれば
良いことになります。これでぐっと割り込み処理作成が簡単化されます。


【割り込み用関数】

割り込み処理をコーディングする方法には、決まったパターンがあります。
それにはまず下記関数が必要です。

《割り込み処理関数》

関数名

機能・その他

DISABLE_INTERRUPTS(level) levelで指定された割り込みを禁止します。
levelがGLOBALの指定の時には全ての割り込みを禁止します。
ENABLE_INTERRUPTS(level) levelで指定された割り込みを許可します。
しかしこれとGLOBALのlevelの割り込みが許可になっていないと実際の割り込みは受付られません。
EXT_INT_EDGE(edge) 外部INT(RB0)割り込みのエッジの立上り/立下りの指定をします。
edgeは L_TO_H か H_TO_L のいずれか
  levelには下記がある。 (各PICの標準ヘッダーファイルで定義している)
    GLOBAL  INT_EXT  INT_RTCC  INT_RB  INT_AD
    INT_EEPROM  INT_TIMER1  INT_TIMER2  INT_CP1
    INT_CCP2  INT_SSP  INT_PSP  INT_TBE  INT_RDA
    INT_COMP  INT_ADOF  INT_RC  INT_I2C  INT_BUTTON

【割り込み処理のパターン】

実際の割り込み処理は、決まったパターンがあります。上記の各関数を
下記の手順で使います。

《割り込み処理のパターン》

 #include <16Cxx.H>   //標準ヘッダーファイル指定
 ------
 #INT_xxx        //xxxの割込み処理の開始指定
 xxx_isr() {      //xxxの割込み処理関数
   -------
 }
 
 main() {        //メイン関数
   -----
   -----
   enable_interrupts(xxx);   //指定の割り込み許可
   -----
   enable_interrupts(GLOBAL); //GLOBAL割り込み許可
   -----
   -----
 }


  (注意)#INT_xxx関数とxxx_isr()関数の間には、何も挿入しては
      ならない。挿入すると正常な割り込み処理展開がされない。
      コンパイルエラーにはならないので注意。

【実際の割り込み処理例】

最も簡単な割り込み処理例として、インターバルタイマがあります。
これにはタイマ0の割り込みを使います。
下記の例は、インターバルタイマの割り込み毎に割り込み回数を
カウントし、丁度1秒毎に発光ダイオードの点灯・消灯を切替える
という動作をします。
割り込みのインターバルが26.2msecとなっています。
本プログラム例も前ページで使ったテスト基板で動作します。


《割り込みプログラム例》  漢字を含むのでこのままでは使えません

////////////////////////////////////////////////////////
// This program is an example of Timer0 interrupt.
// Timer0 is setuped below.
//  clock : 10MHz then cycle : 0.4usec
//  prescale :256
//   then interrupt cycle = 0.4*256*256=26.2msec
//   then interval = 26.2*38=about 1sec
// Include the standard header file.
////////////////////////////////////////////////////////

#device PIC16F84        //PICの指定
#include <16f84.h>
#use delay(clock=10000000)   //クロック10MHzの指定
#define SECMAX 38       //グローバル変数の定義
int sec,flag;

#INT_RTCC           //タイマ0割込みの指定
rtcc_isr() {          //タイマ0割込み処理関数
 sec=sec-1;          //counter-1
 if(sec==0){         //just 1 sec?
  sec=SECMAX;        //タイマ0再設定
  if(flag==0){
   output_low(PIN_B0);   //led on
   flag=1;
  }
  else{
   output_high(PIN_B0);  //led off
   flag=0;
  }
 }
}               //ここまでが割込み処理関数

main() {
 setup_counters(RTCC_INTERNAL,RTCC_DIV_256); 
                    //タイマ0のモード設定
 sec=SECMAX;             //タイマ0初期設定
 
enable_interrupts(INT_TIMER0);    //タイマ0割込み許可
 
enable_interrupts(GLOBAL);      //グローバル割込み許可
 while(1){              //割込み待ちループ
 }
}


《注意》
 ・入出力ピンへのIO命令を「#USE FAST_IO」を指定せずに使うと
  入出力モード設定の命令が自動挿入されるため、
バンク切替命令
  が使われます。したがってバンク切替中に割り込みが入ると、以降
  の処理がバンク1上で実行されてしまい変数が正常に処理できなく
  なってしまいます。したがってその後の処理が異常な処理となって
  しまいますので注意が必要です。
  上記例では割込み処理の中でIO関数を実行しているので割込み
  禁止中にIO関数が実行されますからこの問題は発生しません。


  → その後この問題は、CCSコンパイラでは解決されていることが
     判りました。割込み処理の入り口で、現在のバンクをセーブし
     割込み処理終了時にもとに復帰するという処理がなされてい
     ます。従って、このバンク切替処理のことは気にしなくても良い
     ということになります。




       目次ページへ