目次

方向指示器

 2個のプッシュスイッチ、2個のLEDを利用して
 方向指示器を作ります。



 プッシュスイッチは、1度押すと点滅を開始し
 再度押すと消灯します。内部にモードを表す
 変数を用意して対応。



 プッシュスイッチを押したかの判定に、シフト
 レジスタを使い、内部のモード変数を更新します。
 モード変数の値で、点滅と消灯を切替え。

 シフトレジスタによるモード切替は、次のように
 記述すればよいでしょう。

    if ( SFLAG == ON ) {
      /* clear flag */
      SFLAG = OFF ;
      /* get pin state */
      ltrg_sft <<= 1 ;
      rtrg_sft <<= 1 ;
      ltrg_sft &= MASK03 ;
      rtrg_sft &= MASK03 ;
      if ( LEFT_BUTTON  == OFF ) { ltrg_sft |= ON ; }
      if ( RIGHT_BUTTON == OFF ) { rtrg_sft |= ON ; }
      /* update mode */
      if ( ltrg_sft == 0x01 ) {
        lmode++ ;
        lmode &= 1 ;
      }
      if ( ltrg_sft == 0x01 ) {
        rmode++ ;
        rmode &= 1 ;
      }
    }

 フラグSFLAGは、タイマー割込みで10msごとに通知
 されるとしておきます。チャタリング除去できる
 程度のインターバルにしておけば、充分でしょう。

 モードは、フラグで扱えばよいので、変数値を
 インクリメントし、最下位ビットの値をフラグ
 に利用。

 点滅は、タイマー割込みで250msごと通知してもらい
 LEDに1あるいは0の論理値を出力します。

    if ( TFLAG == ON ) {
      /* clear flag */
      TFLAG = OFF ;
      /* increment */
      lcnt++ ;
      rcnt++ ;
      /* left LED handling */
      if ( lmode ) {
        LEFT_LED = (lcnt & 1) ;
      } else {
        LEFT_LED = ON ;
      }
      /* right LED handling */
      if ( lmode ) {
        RIGHT_BUTTON = (rcnt & 1) ;
      } else {
        RIGHT_BUTTON = ON ;
      }
    }

 モード変数値で、点滅、消灯を切り替えます。

 負論理で点灯としておき、カウンタの値で
 1と0を確定します。



 10msと250msの通知は、タイマー割込みでフラグをセット
 して通知します。タイマー割込みは、以下とします。

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 ) { SFLAG = ON ; }
    if ( timv == 250 ) { TFLAG = ON ; }
  }
}

 タイマー割込みは、4MHzから1kHzを生成するので
 次のイメージとなります。



 初期化をひとつの関数の中に入れていまいます。

void init_usr(void)
{
  /* I/O state */
  GPIO = 0x03 ;
  /* I/O directions */
  TRISIO = (1 << LB_BIT) | (1 << RB_BIT) ; 
  /* bit5,4 as input , others as output */
  /* disable compare module */
  CMCON = 0x07 ;
  /* pull-up */
  WPU = (1 << LB_BIT) | (1 << RB_BIT) ;
  /* initialize Timer 0 */
  {
    ltrg_sft = 0 ;
    rtrg_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 */
  xflags.DR = 0 ;
  /* clear */
  timcnt = 0 ;
  lmode = 0 ;
  rmode = 0 ;
  lcnt = 0 ;
  rcnt = 0 ;
}

 部品点数を減らすため、内蔵プルアップ抵抗を利用して
 います。また、フラグは8ビット中の2ビットを利用し
 フラグに使う変数を減らしています。

 まとめます。

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

#define OFF 0
#define ON  OFF+1

#define LB_BIT 5
#define RB_BIT 4
#define LLED   0
#define RLED   1

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

#define LEFT_BUTTON  GPIO.B5
#define RIGHT_BUTTON GPIO.B4

#define LEFT_LED     GPIO.B0
#define RIGHT_LED    GPIO.B1

typedef union {
  struct {
    unsigned B7:1;
    unsigned B6:1;
    unsigned B5:1;
    unsigned B4:1;
    unsigned B3:1;
    unsigned B2:1;
    unsigned B1:1;
    unsigned B0:1;
  } BIT ;
  unsigned char DR ;
} FLAGSP ;

volatile FLAGSP xflags ;

#define TFLAG xflags.BIT.B0
#define SFLAG xflags.BIT.B1

ULONG timcnt ;
UBYTE timv ;
UBYTE ltrg_sft ;
UBYTE rtrg_sft ;
UBYTE lmode ;
UBYTE rmode ;
UBYTE lcnt ;
UBYTE rcnt ;

/* function prototype */
void  init_usr(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 ) { SFLAG = ON ; }
    if ( timv == 250 ) { 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 */
      ltrg_sft <<= 1 ;
      rtrg_sft <<= 1 ;
      ltrg_sft &= MASK03 ;
      rtrg_sft &= MASK03 ;
      if ( LEFT_BUTTON  == OFF ) { ltrg_sft |= ON ; }
      if ( RIGHT_BUTTON == OFF ) { rtrg_sft |= ON ; }
      /* update mode */
      if ( ltrg_sft == 0x01 ) {
        lmode++ ;
        lmode &= 1 ;
      }
      if ( ltrg_sft == 0x01 ) {
        rmode++ ;
        rmode &= 1 ;
      }
    }
    /* 250ms seconds pass handling */
    if ( TFLAG == ON ) {
      /* clear flag */
      TFLAG = OFF ;
      /* increment */
      lcnt++ ;
      rcnt++ ;
      /* left LED handling */
      if ( lmode ) {
        LEFT_LED = (lcnt & 1) ;
      } else {
        LEFT_LED = ON ;
      }
      /* right LED handling */
      if ( lmode ) {
        RIGHT_BUTTON = (rcnt & 1) ;
      } else {
        RIGHT_BUTTON = ON ;
      }
    }
  }
}

/* define function body */
void init_usr(void)
{
  /* I/O state */
  GPIO = 0x03 ;
  /* I/O directions */
  TRISIO = (1 << LB_BIT) | (1 << RB_BIT) ; 
  /* bit5,4 as input , others as output */
  /* disable compare module */
  CMCON = 0x07 ;
  /* pull-up */
  WPU = (1 << LB_BIT) | (1 << RB_BIT) ;
  /* initialize Timer 0 */
  {
    ltrg_sft = 0 ;
    rtrg_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 */
  xflags.DR = 0 ;
  /* clear */
  timcnt = 0 ;
  lmode = 0 ;
  rmode = 0 ;
  lcnt = 0 ;
  rcnt = 0 ;
}

 内蔵クロックを利用するので、スイッチ
 LED、抵抗を接続するだけです。




目次

inserted by FC2 system