目次

充電用タイマー

 DIPスイッチ、アナログスイッチを利用して
 1時間単位で1から15時間まで計時する
 タイマーを作りました。



 写真では、8ビットのDIPスイッチ、アナログスイッチを
 利用していますが、4ビットで充分です。

 以下が、ブロック図。



 手持ちのPIC12F629を使うため、次のようにピン割当。



 クロックは内蔵4MHzを利用します。

 タイマーは、時間を計測するのでクロックから
 1kHzを生成し、内部カウンタをインクリメント
 しながら、経過時間を1分単位で管理します。



 システムクロックがfであっても、CPUコア、タイマーの
 動作クロックはf/4になります。1命令が、4クロックで
 構成されているので、高速処理には向かないと言えます。

 トリガーボタンを押したときの動作シーケンスを
 設定し、必要な処理を洗い出します。

 動作シーケンスをCのコードで記述します。

    /* 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 ; }
      /* judge */
      if ( trg_sft == 0x01 ) {
        /* get last count */
        lastcnt = 60 * get_tcnt();
        /* enable */
        GPIO.B5 = ON ;
      }
    }
    /* 60 seconds pass handling */
    if ( tflag == ON ) {
      /* clear flag */
      tflag = OFF ;
      /* decrement */
      lastcnt-- ;
      /* judge */
      if ( lastcnt == 0 ) { GPIO.B5 = OFF ; }
    }

 トリガーボタンは、チャタリング除去のため
 シフトレジスタでエッジを捉えます。

 4ビットの2進数を入力するには、専用関数
 get_tcntを定義して使います。
 関数get_tcntは、次のように定義しました。

UBYTE get_tcnt(void)
{
  UBYTE loop ;
  UBYTE result ;
  UBYTE xgpio ;
  /* clear */
  result = 0 ;
  /* loop  */
  for ( loop = 0 ; loop < 4 ; loop++ ) {
    /* address */
    xgpio = GPIO ;
    xgpio &= ~MASK03 ;
    xgpio |= ((3-loop) & MASK03);
    GPIO = xgpio ;
    /* shift */
    result <<= 1 ;
    /* get target bit state */
    if ( GPIO.B2 == ON ) { result |= ON ; }
  }

  return result ;
}


 タイマー割込みで、10msと6000msを生成すれば
 よいので、割込みハンドラを次のように定義
 します。


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 */
      sflag = ON ;
    }
    if ( timv == 250 ) {
      /* increment */
      scnt++ ;
      /* past 60 seconds */
      if ( scnt == 240 ) {
        scnt = 0 ;
        tflag = ON ;
      }
    }
  }
}


 システムタイマーカウンタを用意し、1msごとに
 インクリメントします。オーバーフロー割込みで
 使わなければならないので、250分周になるよう
 カウンタの初期値を調整して対応します。

 10msと6000msの経過は、sflag、tflagで通知します。

 大まかなカラクリを考えたので、I/O関係を初期化します。

 PICは電源ONで、アナログコンパレータ、A/Dコンバータが
 使える仕様なので、これらを停止し単純なI/Oで利用可能
 とします。

 レジスタを見ると、次のようになっています。



 アナログコンパレータを使わないときは、レジスタに
 0x07を設定すればよいとわかります。

  CMCON = 0x07 ;

 利用するPICには、A/Dコンバータがないので
 このモジュールの動作を停止させないでOK。

  外付け部品を減らすため、入力ピンの内部に
 プルアップ抵抗を接続します。

 GP2、GP4にプルアップ抵抗を設定するため
 関連するレジスタを調べます。



 プルアップ抵抗を接続するには、該当ビットに1を
 指定すればよいので、レジスタ設定は以下となります。

  WPU = 0x14 ;

 但し書きで、GPPUビットをイネーブル(0設定)にします。

  GPPUビットは、OPTION_REGの中にありますが
 電源オンで0になるので、レジスタの該当
 ビットはそのままとします。

 I/Oピンの入出力方向と初期値を設定するため
 該当するレジスタの内容を把握します。



 初期値は、GPIOレジスタに格納し、入出力方向は
 TRISIOに設定します。

  /* I/O state */
  GPIO = 0x00 ;
  /* I/O directions */
  TRISIO = 0x1C ; /* bit0,1,5 as output , others as input */

 タイマー0の動作を設定するため、ブロック図をみます。



 タイマー0のプリスケーラには、4MHzの1/4である1MHzが
 入り、プリスケーラの出力で内蔵タイマーインクリメント
 が発生します。また、割込みは、オーバーフローになると
 記されています。

 1kHzをタイマーから出力されるクロックだとすると
 250分周すればよいことに。
 さらに、WatchDogTimerを使わないでタイマー利用
 とする設定が必要となります。

 割込みを、オーバーフローで利用するとなれば、カウンタ
 タイマーには、250を設定したのと等価になるように、6を
 代入します。

 初期化は、次のように値を設定しました。

    /*
       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 ;

 PICでは、全体割込みをイネーブルにしないと個々の
 割込みが使えないので、次の一文が必要に。

  INTCON.GIE = ON ;

 ソースコードにまとめます。

/* redefine data type */
typedef unsigned char  UBYTE ;
typedef unsigned int   UWORD ;
typedef unsigned long  ULONG ;

#define OFF 0
#define ON  OFF+1

#define MASKFF 0xff
#define MASK30 0x30
#define MASK0F 0x0f
#define MASK03 0x03

volatile UBYTE tflag ;
volatile UBYTE sflag ;
volatile ULONG timcnt ;
volatile UBYTE timv ;
volatile UBYTE scnt ;
volatile UWORD lastcnt ;
volatile UBYTE trg_sft ;

/* function prototype */
void  init_usr(void);
UBYTE get_tcnt(void);

/* interrupt handler */
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 */
      sflag = ON ;
    }
    if ( timv == 250 ) {
      /* increment */
      scnt++ ;
      /* past 60 seconds */
      if ( scnt == 240 ) {
        scnt = 0 ;
        tflag = ON ;
      }
    }
  }
}

void main(void) {
  /* user initialize */
  init_usr();
  /* endless loop */
  while ( 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 ; }
      /* judge */
      if ( trg_sft == 0x01 ) {
        /* get last count */
        lastcnt = 60 * get_tcnt();
        /* enable */
        GPIO.B5 = ON ;
      }
    }
    /* 60 seconds pass handling */
    if ( tflag == ON ) {
      /* clear flag */
      tflag = OFF ;
      /* decrement */
      lastcnt-- ;
      /* judge */
      if ( lastcnt == 0 ) { GPIO.B5 = OFF ; }
    }
  }
}

/* define function body */
void init_usr(void)
{
  /* I/O state */
  GPIO = 0x00 ;
  /* I/O directions */
  TRISIO = 0x1C ;  /* bit0,1,5 as output , others as input */
  /* disable compare module */
  CMCON = 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 flags */
  tflag = OFF ;
  sflag = OFF ;
  /* clear */
  timcnt = 0 ;
  scnt = 0 ;
  lastcnt = 10 ;
}

UBYTE get_tcnt(void)
{
  UBYTE loop ;
  UBYTE result ;
  UBYTE xgpio ;
  /* clear */
  result = 0 ;
  /* loop  */
  for ( loop = 0 ; loop < 4 ; loop++ ) {
    /* address */
    xgpio = GPIO ;
    xgpio &= ~MASK03 ;
    xgpio |= ((3-loop) & MASK03);
    GPIO = xgpio ;
    /* shift */
    result <<= 1 ;
    /* get target bit state */
    if ( GPIO.B2 == ON ) { result |= ON ; }
  }

  return result ;
}

 回路図は、以下です。




目次

inserted by FC2 system