目次

割込み処理

 PICは、ワンチップマイコンなので内蔵している
 ハードウエアモジュールが多数あります。
 チップにもよりますが、28ピンであれば、以下の
 ハードウエアモジュールが揃っています。

 これらのモジュールを使う場合、割込みを使うと
 ファームウエアが単純になります。

 PICは、割込みのエントリアドレスが0x004と固定で
 このエントリーアドレスからのコードで割込み種別
 を判定します。

 この形式を採用しているマイコンは、ARMがあります。

 割込みのエントリアドレスが、ひとつしかないと
 いうので、Cで割込み処理コードを担当する関数は
 ひとつでよくなります。

 CCS社のCでは、次のようにプラグマ記述で個別の
 割込み処理を定義します。

#int_rtcc
void timer_handler(void)
{
  /* set TMR0 6 (256-250) */
  set_timer0(6);
  /* interval process */
  state++ ;
  if ( state == STA_LAST ) state = 0 ;
  /* set flag */
  tflag = ON ;
}

#int_rda
void echo_handler(void)
{
  UBYTE chx ;

  /* get one character */
  chx = rcreg ;
  sbuf[s_idx] = chx ;
  /* update buffer index */
  s_idx++ ;
  if ( s_idx == SMAX ) s_idx = 0 ;
  /* judge */
  if ( chx == '\r' ) {
    sflag = ON ;
    s_idx = 0 ;
  }
}

 エントリー用の関数はなく、ハードウエアモジュール
 専用の関数を定義して対応します。



 MikroCでは、エントリー関数を用意して、その中に
 ハードウエアモジュールの動作を記述します。
 例は、以下となります。

void interrupt(void)
{
  /* generate 1ms */
  if ( INTCON.T0IF == ON ) {
    /* clear flag */
    INTCON.T0IF = OFF ;
    /* initialize */
    TMR0 = 6 ;
    /* increment */
    timcnt++ ;
    /* judge 10ms */
    timv = (UBYTE)(timcnt & MASK0F) ;
    if ( timv == LAST ) {
      /* set flag */
      tflag = ON ;
    }
  }
}

 割込みを要求したハードウエアモジュールの判断は
 レジスタのフラグがセット、リセットで判断します。



 PICでは、ハードウエアモジュールの初期化と割込みの
 有無を指定後、全体割込みを許可します。全体割込み
 を許可しないと、いずれのハードウエアモジュールから
 も割込みは、発生しません。

 これは、データシートの回路図を見るとわかります。
 (PIC16F84Aのデータシート上の割込み関係回路図)



 割込みをイネーブルと割込みフラグの2ビットを
 論理積でまとめて管理しています。GIEビットを
 セットすると、CPUコアに対して割込み信号が伝達
 される仕組み。

 CCSのCは、論理積部分の内容をプラグマで記述し
 MikroCは、全体をひとつの関数にまとめています。

 SDCCは、MikroCと同じ方式を採用しています。
 関数名は、好きにつけてよいのですが、定義の
 後に「interrupt 0」をつけます。

 次のように記述します。

  static void int_tim0() interrupt 0
  {
    /* clear interrupt flag */
    T0IF = 0 ;
    /* ????? */
  }

 全体割込みをイネーブルするまでの初期化は
 次のように記述します。

void init_usr(void)
{
  /* I/O initial state */

  /* I/O direction */

  /* disable compare module */

  /* pull-up */
  WPU = 0x14 ;
  /* initialize A/D converter */
  {
    /* select A/D bits */

    /* enable A/D converter */

    /* right justify */

    /* select reference voltage */

    /* select A/D frequency */

  }
  /* initialize serial interface */
  {
    /* BAUD rate */

    /* initialize TxD module */

    /* initialize RxD module */

    /* enable receive interrupt */

  }
  /* initialize Timer 0 */
  {
    /* set prescaler */

    /* initialie counter */

    /* enable timer0 overflow interrupt */

  }

  /* enable general interrupt */

}

 割込みに関連するレジスタとビットがどうなって
 いるのかは、チップごとに異なるのでデータシート
 を丹念に読んで理解します。


タイマー割込み応用  タイマー割込みを利用すると、時間を正確に  管理できます。応用している2例を紹介します。  タイマー0は、オーバーフロー割込みができるので  これを利用して、システムタイマーを実現します。  1ms周期で発生する割込みを定義し、カウンタを  インクリメントしていくと、32ビットカウンタ  で、約50日の時間を1msの分解能で実現できます。  MikroCで、PIC16F629を使ったコードを公開します。  カウンタ定義 typedef unsigned char UBYTE ; typedef unsigned int UWORD ; typedef unsigned long ULONG ; ULONG timcnt ;  初期化 /* initialize Timer 0 */ { /* 4MHz/4 = 1MHz -> 1MHz/4 = 250kHz prescaler = 1:4 all inputs are pull-up . */ OPTION_REG = 0x01 ; /* 256 - 250 = 6 */ TMR0 = 6 ; /* enable timer0 overflow interrupt */ INTCON.T0IE = ON ; } /* enable general interrupt */ INTCON.GIE = ON ;  割込み処理 void interrupt(void) { /* generate 1ms */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = 6 ; /* increment */ timcnt++ ; } }  1msディレイ処理関数 void delay_ms(UWORD x) { ULONG target ; /* calculate */ target = timcnt + x ; /* */ while ( timcnt < target ) ; }   1msディレイ処理関数は、最大で65535msまでの   待ちを生成できます。ただし、待っている最中   他のことができないので、10ms程度が利用範囲   内だと思います。  スイッチを利用する場合、チャタリング除去が  必要になります。10ms程度で通知してもらって  スイッチの状態を読み込んで、判定すると簡単  にチャタリングを除去できます。  チャタリング除去では、シフトレジスタを使い  シフトレジスタの2ビットあるいは3ビットの  値で、スイッチの状態を判断します。10ms経過  はフラグで通知します。  シフトレジスタ定義 typedef unsigned char UBYTE ; typedef unsigned int UWORD ; typedef unsigned long ULONG ; UBYTE sflag ; ULONG timcnt ; UBYTE timv ; UBYTE trg_sft ;  初期化 void init_usr(void) { /* I/O state */ GPIO = 0x00 ; /* I/O directions */ TRISIO = 0x1c ; /* bit2,3,4 as input , others as output */ /* disable compare module */ CMCON0 = 0x07 ; /* pull-up */ WPU = 0x14 ; /* initialize Timer 0 */ { trg_sft = 0 ; /* 4MHz/4 = 1MHz -> 1MHz/4 = 250kHz prescaler = 1:4 all inputs are pull-up . */ OPTION_REG = 0x01 ; /* 256 - 250 = 6 */ TMR0 = 6 ; /* enable timer0 overflow interrupt */ INTCON.T0IE = ON ; } /* enable general interrupt */ INTCON.GIE = ON ; /* clear flag */ sflag = OFF ; }  割込み処理 void interrupt(void) { /* generate 1ms */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = 6 ; /* increment */ timcnt++ ; /* get lower 8 bits */ timv = timcnt & MASKFF ; /* judge */ if ( (timv & 15) == 10 ) { /* set flag each 10ms */ sflag = ON ; } } }  チャタリング除去処理 /* switch handling */ if ( sflag == ON ) { /* clear flag */ sflag = OFF ; /* get pin state */ trg_sft <<= 1 ; trg_sft &= MASK03 ; if ( GPIO.B4 == OFF ) { trg_sft |= ON ; } /* debouncing */ if ( trg_sft == 0x01 ) { /* ????? */ } }

目次

inserted by FC2 system