目次

クリスマスツリー

 8ピンのPIC16F629を利用して
 クリスマスツリーを実現します。



 9個のLEDを利用していますが、木の頂上に
 ある赤LEDは1個独立で、他は左右2個のLED
 を1セットで考えます。

 LEDを点灯するためのドライバとして小信号の
 トランジスタを使います。



 5セットのLEDを順次点灯すればよいので
 複数ステップでの点灯、消灯を考えました。
 (上から0、1、2、3、4とLEDセットの番号付け)

 合計9種の点灯パターンがあるので、変数stateを
 用意し、この変数の値でLEDの点灯パターンを作り
 ます。

 LED0処理
  変数値が8のときだけ、消灯しているので
  そのようにコードを記述します。
      LED0 = ON ;
      if ( state == 8 ) { LED0 = OFF ; }

 LED1処理
  変数値が奇数のときに点灯しているので
  stateのLSB(Least Signiticant Bit)が1
  のときに、点灯します。
      mystate = state & 1 ;
      LED1 = OFF ;
      if ( mystate == 1 ) { LED1 = ON ; }

 LED2処理
  変数値を2進数で表し、点灯するときだけを
  列挙してみます。
   0010
   0011
   0110
   0111
   1000
  変数値を1ビット右にシフトしてみます。
    001
    001
    011
    011
    100
  変数値を1ビット右にシフトすると3値に
  なります。
    001
    011
    100
  これらの値を10進数とみると、1、3、4で
  点灯しているとわかります。
  これをコードにて実現します。
      mystate = (state >> 1) & 0x07 ;
      LED2 = OFF ;
      if ( mystate == 1 ) { LED2 = ON ; }
      if ( mystate == 2 ) { LED2 = ON ; }
      if ( mystate == 4 ) { LED2 = ON ; }

 LED3処理
  変数値が4以上のときに点灯するよう
  コードに変換します。
      LED3 = OFF ;
      if ( state > 3 ) { LED3 = ON ; }

 LED4処理
  変数値を3で割ったときの余りが0か
  8のときに点灯します。
      mystate = (state % 3) ;
      LED4 = OFF ;
      if ( state == 8   ) { LED4 = ON ; }
      if ( mystate == 0 ) { LED4 = ON ; }

 ここまでの内容をまとめます。

    /* LED0 handling */
    LED0 = ON ;
    if ( state == 8 ) { LED0 = OFF ; }
    /* LED1 handling */
    mystate = state & 1 ;
    LED1 = OFF ;
    if ( mystate == 1 ) { LED1 = ON ; }
    /* LED2 handling */
    mystate = (state >> 1) & 0x07 ;
    LED2 = OFF ;
    if ( mystate == 1 ) { LED2 = ON ; }
    if ( mystate == 2 ) { LED2 = ON ; }
    if ( mystate == 4 ) { LED2 = ON ; }
    /* LED3 handling */
    LED3 = OFF ;
    if ( state > 3 ) { LED3 = ON ; }
    /* LED4 handling */
    mystate = (state % 3) ;
    LED4 = OFF ;
    if ( state == 8   ) { LED4 = ON ; }
    if ( mystate == 0 ) { LED4 = ON ; }

 どのポートを利用するかを考えると
 ポートRBを選びました。これで処理
 を単純にできます。各LEDとの対応を
 指定します。

#define LED0 PORTB.B0
#define LED1 PORTB.B1
#define LED2 PORTB.B2
#define LED3 PORTB.B3
#define LED4 PORTB.B4

 変数stateを変化させるにはタイマー割込みを
 使います。3秒ごとにフラグで通知してもらい
 変数値を変化させます。

  if ( tflag == ON ) {
    /* clear flag */
    tflag = OFF ;
    /* increment */
    state++ ;
    /* judge */
    if ( state == 9 ) { state = 0 ; }
  }

 main関数の主要処理は、割込み対応と
 LEDの点灯にします。

  while ( ON ) {
    /* timer handling */
    if ( tflag == ON ) {
      /* clear flag */
      tflag = OFF ;
      /* increment */
      state++ ;
      /* judge */
      if ( state == 9 ) { state = 0 ; }
      /* send LED control flag */
      eflag = ON ;
    }
    /* LED handling */
    if ( eflag == ON ) {
      /* clear flag */
      eflag = OFF ;
      /* LED0 handling */
      LED0 = ON ;
      if ( state == 8 ) { LED0 = OFF ; }
      /* LED1 handling */
      mystate = state & 1 ;
      LED1 = OFF ;
      if ( mystate == 1 ) { LED1 = ON ; }
      /* LED2 handling */
      mystate = (state >> 1) & 0x07 ;
      LED2 = OFF ;
      if ( mystate == 1 ) { LED2 = ON ; }
      if ( mystate == 2 ) { LED2 = ON ; }
      if ( mystate == 4 ) { LED2 = ON ; }
      /* LED3 handling */
      LED3 = OFF ;
      if ( state > 3 ) { LED3 = ON ; }
      /* LED4 handling */
      mystate = (state % 3) ;
      LED4 = OFF ;
      if ( state == 8   ) { LED4 = ON ; }
      if ( mystate == 0 ) { LED4 = ON ; }
    }
  }

 ここまでで主要な処理を定義したので
 初期化と割込み関係コードを記述します。

 初期化は、A/Dコンバータ、アナログコンパレータの
 動作を停止し、タイマー0関係の割込みを設定します。

void init_usr(void)
{
  /* disable Analog comparator */
  CMCON = 0x07 ;
  /* I/O initial state */
  GPIO  = 0x00 ;
  /* I/O direction */
  TRISIO = 0 ;
  /* 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.TMR0IE = ON ;
  }
  /* enable general interrupt */
  INTCON.GIE = ON ;
  /* clear flags */
  xflags.DR = 0 ;
  /* others */
  timcnt = 0 ;
  state = 0 ;
}

 タイマー割込みは、周期を1msとます。
 システムタイマーを用意し、分解能を1ms
 として刻みます。さらに3000msごとにフラグ
 で、時間経過を通知します。

void interrupt(void)
{
  UBYTE chx ;
  /* generate 1ms */
  if ( INTCON.TMR0IF == ON ) {
    /* clear flag */
    INTCON.TMR0IF = OFF ;
    /* initialize */
    TMR0 = 6 ;
    /* increment */
    timcnt++ ;
    /* judge 3000ms pass */
    timv = timcnt & MASKFFFF ;
    if ( timv == 3000 ) { TFLAG = 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 MASK07 0x07
#define MASK03 0x03

#define MASK3FF 0x3ff

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 EFLAG xflags.BIT.B1

#define LED0 PORTB.B0
#define LED1 PORTB.B1
#define LED2 PORTB.B2
#define LED3 PORTB.B3
#define LED4 PORTB.B4

#define MASKFFFF 0xffff

ULONG timcnt ;
UWORD timv ;
UBYTE state ;
UBYTE mystate ;

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

/* interrupt handler */
void interrupt(void)
{
  UBYTE chx ;
  /* generate 1ms */
  if ( INTCON.TMR0IF == ON ) {
    /* clear flag */
    INTCON.TMR0IF = OFF ;
    /* initialize */
    TMR0 = 6 ;
    /* increment */
    timcnt++ ;
    /* judge 3000ms pass */
    timv = timcnt & MASKFFFF ;
    if ( timv == 3000 ) { TFLAG = ON ; }
  }
}

void main(void)
{
  /* user initialize */
  init_usr();
  /* endless loop */
  while ( ON ) {
    /* 3 second handling */
    if ( TFLAG == ON ) {
      /* clear flag */
      TFLAG = OFF ;
      /* update */
      state++ ;
      /* judge */
      if ( state == 9 ) { state = 0 ; }
      /* enable LED handling */
      EFLAG = ON ;
    }
    /* LED handling */
    if ( EFLAG == ON ) {
      /* clear flag */
      TFLAG = OFF ;
      /* LED0 */
      LED0 = ON ;
      if ( state == 8 ) { LED0 = OFF ; }
      /* LED1 */
      mystate = state & ON ;
      LED1 = OFF ;
      if ( mystate == 1 ) { LED1 = ON ; }
      /* LED2 */
      mystate = (state >> 1) & 0x07 ;
      LED2 = OFF ;
      if ( mystate == 1 ) { LED2 = ON ; }
      if ( mystate == 2 ) { LED2 = ON ; }
      if ( mystate == 4 ) { LED2 = ON ; }
      /* LED3 */
      LED3 = OFF ;
      if ( state > 3 ) { LED3 = ON ; }
      /* LED4 */
      mystate = (state % 3) ;
      LED4 = OFF ;
      if ( state == 8 || mystate == 0 ) { LED4 = ON ; }
    }
  }
}

/* define function body */
void init_usr(void)
{
  /* disable Analog comparator */
  CMCON = 0x07 ;
  /* I/O initial state */
  GPIO = 0x00 ;
  /* I/O direction */
  TRISIO = 0 ;
  /* 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.TMR0IE = ON ;
  }
  /* enable general interrupt */
  INTCON.GIE = ON ;
  /* clear flags */
  xflags.DR = 0 ;
  /* others */
  timcnt = 0 ;
  state = 0 ;
}

 PICは8ビット処理が主体なので、16ビットや
 32ビットの値を操作すると、アセンブリ言語の
 レベルでコードが一気に増えます。

 32ビットを16ビット値にして、3000と比較して
 割込み処理にかかる時間を減らしています。

    timv = timcnt & MASKFFFF ;
    if ( timv == 3000 ) { TFLAG = ON ; }

 回路図は、以下です。



 CCSのCを利用すると、時間待ちの関数が
 用意されているので、もう少し簡単にできます。
  PIC16F873での記述は、以下。

#include <16F873.H>

/* local data type definistion */
typedef signed   int  SBYTE ;
typedef unsigned int  UBYTE ;
typedef signed   long SWORD ;
typedef unsigned long UWORD ;

#fuses HS,NOWDT,NOPROTECT
#use delay(clock=4000000)

#define OFF 0
#define ON  OFF+1

#define LED0_BIT 0
#define LED1_BIT 1
#define LED2_BIT 2
#define LED3_BIT 3
#define LED4_BIT 4

#define MASKFFFF 0xffff

UBYTE eflag ;
UBYTE state ;
UBYTE mystate ;

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

void main(void)
{
  /* user initialize */
  init_usr();
  /* endless loop */
  while ( ON ) {
    /* 3 second handling */
    {
      /* wait 3 second */
      delay_ms(3000) ;
      /* update */
      state++ ;
      /* judge */
      if ( state == 9 ) { state = 0 ; }
      /* enable LED handling */
      eflag = ON ;
    }
    /* LED handling */
    if ( eflag == ON ) {
      /* clear flag */
      eflag = OFF ;
      /* LED0 */
      PORTB |= (1 << LED0_BIT) ;
      if ( state == 8 ) { PORTB &= ~(1 << LED0_BIT) ; }
      /* LED1 */
      PORTB &= ~(1 << LED1_BIT) ;
      mystate = state & ON ;
      if ( mystate == 1 ) { PORTB |= (1 << LED1_BIT) ; }
      /* LED2 */
      PORTB &= ~(1 << LED2_BIT) ;
      mystate = (state >> 1) & 0x07 ;
      if ( mystate == 1 ) { PORTB |= (1 << LED2_BIT) ; }
      if ( mystate == 2 ) { PORTB |= (1 << LED2_BIT) ; }
      if ( mystate == 4 ) { PORTB |= (1 << LED2_BIT) ; }
      /* LED3 */
      PORTB &= ~(1 << LED3_BIT) ;
      if ( state > 3 ) { PORTB |= (1 << LED3_BIT) ; }
      /* LED4 */
      PORTB &= ~(1 << LED4_BIT) ;
      mystate = (state % 3) ;
      if ( state   == 8 || mystate == 0) { PORTB |= (1 << LED4_BIT) ; }
    }
  }
}

/* define function body */
void init_usr(void)
{
  /* disable A/D converter */
  ADCON1 = 0x07 ;
  /* disable Analog comparator */
  CMCON = 0x07 ;
  /* I/O initial state */
  PORTA = 0x00 ;
  PORTB = 0x01 ;
  PORTC = 0x00 ;
  /* I/O direction */
  TRISA = 0 ;
  TRISB = 0 ;
  TRISC = 0 ;
  /* clear flag */
  eflag = OFF ;
  /* others */
  state = 0 ;
}


目次

inserted by FC2 system