目次

7セグメントLED表示器(割込み活用)

 7セグメントLEDは表示器なので、次のように用途を
 考えることができます。

 これらは、7セグメントLED表示器を複数利用する
 ことになるので、各桁の値をダイナミック点灯して
 対応します。



 4桁の7セグメントLED表示器があるとすれば、次の
 シーケンスを繰返します。
  1. 0けた目の表示パターン出力
  2. 0けた目をイネーブル、他はディセーブル
  3. 1けた目の表示パターン出力
  4. 1けた目をイネーブル、他はディセーブル
  5. 2けた目の表示パターン出力
  6. 2けた目をイネーブル、他はディセーブル
  7. 3けた目の表示パターン出力
  8. 3けた目をイネーブル、他はディセーブル
  9. 1に戻る
 表示のタイミングは、タイマー割込みで通知します。 if ( LTRG == ON ) { /* clear flag */ LTRG = OFF ; /* get target digit */ tmp = *(digit+state); /* convert bit pattern */ ltmp = conv7segment( tmp ); /* impress */ PORTB = ltmp ; /* enable target digit */ PORTA = state & 0x03 ; /* update state */ state++ ; /* judge */ if ( state == 4 ) { state = 0 ; } }  タイマー割込みは、20msより小さい周期を利用します。  20ms程度にするとチラツキが出るので、20msを桁数で  割った周期を利用します。ここでは1msとします。  7セグメントLED表示器のダイナミック点灯では、ポートの  ピン数を減らすために、デコーダICを利用した方が楽になり  ます。  4511のような消費電力が少ないCMOSタイプを使います。  デコードICを利用することで、数字をビットパターンに  変換する処理を省くことができます。 if ( LTRG == ON ) { /* clear flag */ LTRG = OFF ; /* get target digit */ tmp = *(digit+state); /* clear lower nibble */ PORTB &= 0xf0 ; /* impress */ PORTB |= tmp ; /* enable target digit */ PORTA = state & 0x03 ; /* update state */ state++ ; /* judge */ if ( state == 4 ) { state = 0 ; } }  ポートの中で、使わなくなったビットをスイッチや  通信に振り分けられます。  プッシュスイッチでは、チャタリングを除去する処理が  必要になります。チャタリング除去にはタイマー割込み  とシフトレジスタを利用すれば簡単になります。  チャタリング除去は、次のコードで対応できます。 if ( TFLAG == ON ) { /* clear flag */ TFLAG = OFF ; /* get current switch state */ tmp = PORTB ; /* shift */ sreg0 <<= 1 ; sreg1 <<= 1 ; sreg2 <<= 1 ; sreg3 <<= 1 ; /* mask */ sreg0 &= 0x03 ; sreg1 &= 0x03 ; sreg2 &= 0x03 ; sreg3 &= 0x03 ; /* update LSB */ if ( tmp & 0x10 ) { sreg0 |= 1 ; } if ( tmp & 0x20 ) { sreg1 |= 1 ; } if ( tmp & 0x40 ) { sreg2 |= 1 ; } if ( tmp & 0x80 ) { sreg3 |= 1 ; } /* judge */ if ( sreg0 == ON ) { SFLAG0 = ON ; } if ( sreg1 == ON ) { SFLAG1 = ON ; } if ( sreg2 == ON ) { SFLAG2 = ON ; } if ( sreg3 == ON ) { SFLAG3 = ON ; } }  4つのシフトレジスタを用意し、チャタリング除去  しつつ0→1の変化をとらえます。変化があった時  各通知フラグを設定して、通知フラグを待っている  処理に操作を一任します。  対応処理を記述すると、いろいろなことができます。 if ( SFLAG0 == ON ) { /* clear flag */ SFLAG0 = OFF ; /* perform */ } if ( SFLAG1 == ON ) { /* clear flag */ SFLAG1 = OFF ; /* perform */ } if ( SFLAG2 == ON ) { /* clear flag */ SFLAG2 = OFF ; /* perform */ } if ( SFLAG3 == ON ) { /* clear flag */ SFLAG3 = OFF ; /* perform */ }  割込みを使うと、イベントに対応した処理を簡単に  記述できるようになります。  Windowsアプリケーションは、割込みによるイベント通知を  OSが担当するので、イベントに対応した処理だけを記述して  いきます。ファームウエアでWindowsアプリケーションに近い  プログラムを作成するとき、割込みをどう扱うのかをユーザ  が指定し、そのコードを作成します。  娯楽施設での入場者、退場者を表示するアプリケーションを  作成してみます。入場者は最大999人とします。  仕様を決めていきます。  表示   6桁の7セグメントLEDの上位3桁を入場者数   下位3桁を退場者数にします。   ハードウエアが決まれば、内部処理はある程度は確定します。 word in_passengers ; word out_passengers ; if ( LTRG == ON ) { /* clear flag */ LTRG = OFF ; /* in passengers */ *(digit+0) = in_passengers / 100 ; *(digit+1) = (in_passengers % 100) / 10 ; *(digit+2) = in_passengers % 10 ; /* out passengers */ *(digit+2) = out_passengers / 100 ; *(digit+4) = (out_passengers % 100) / 10 ; *(digit+5) = out_passengers % 10 ; /* get target digit */ tmp = *(digit+state); /* clear nibble */ PORTB = 0x00 ; /* impress */ PORTB |= tmp ; /* enable target digit */ if ( state < 5) { PORTA = 0 ; PORTA |= (1 << state & 0x07) ; PORTB &= ~(1 << 4); } else { PORTB |= (1 << 4); } /* update state */ state++ ; /* judge */ if ( state == 6 ) { state = 0 ; } }  入場者、退場者カウント表示   入口、出口のマット下に、マイクロスイッチを入れて   1→0の変化で人が通過したと判断します。   チャタリングを除去しながら、入退場者の数を更新すれば   よいので、次のコードで対応できます。 if ( TFLAG == ON ) { /* clear flag */ TFLAG = OFF ; /* get current switch state */ tmp = PORTB ; /* shift */ sreg0 <<= 1 ; sreg1 <<= 1 ; /* mask */ sreg0 &= 0x03 ; sreg1 &= 0x03 ; /* update LSB */ if ( tmp & 0x40 ) { sreg0 |= 1 ; } if ( tmp & 0x80 ) { sreg1 |= 1 ; } /* judge */ if ( sreg0 == ON ) { SFLAG0 = ON ; } if ( sreg1 == ON ) { SFLAG1 = ON ; } } /* update out passengers */ if ( SFLAG1 == ON ) { /* clear flag */ SFLAG1 = OFF ; /* increment */ out_passengers++ ; } /* update in passengers */ if ( SFLAG0 == ON ) { /* clear flag */ SFLAG0 = OFF ; /* increment */ in_passengers++ ; }  1日の入場者、退場者を逐次集計して、表示する場合の  ファームウエアは、以下。 #define OFF 0 #define ON OFF+1 #define STARTV 3036 #define XDIV 10 #define XXDIV 100 typedef unsigned char UBYTE ; typedef unsigned short UWORD ; 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 LTRG xflags.BIT.B0 #define TFLAG xflags.BIT.B1 #define SFLAG0 xflags.BIT.B2 #define SFLAG1 xflags.BIT.B3 volatile UWORD xcnt ; volatile UBYTE sreg0 ; volatile UBYTE sreg1 ; volatile UWORD in_passengers ; volatile UWORD out_passengers ; volatile UBYTE state ; volatile UBYTE digit[6] ; void interrupt(void) { /* timer0 overflow interrupt */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = 6 ; /* set flag */ TFLAG = ON ; } /* timer1 overflow interrupt */ if ( PIR1.TMR1IF == ON ) { /* clear flag */ PIR1.TMR1IF = OFF ; /* initialize */ TMR1L = STARTV % 256 ; TMR1H = STARTV / 256 ; /* set flag */ LTRG = ON ; } } /* prototype */ void usr_init(void); void main(void) { UBYTE tmp ; /* initialize */ usr_init(); /* endless loop */ while (ON) { if ( TFLAG == ON ) { /* clear flag */ TFLAG = OFF ; /* get current switch state */ tmp = PORTB ; /* shift */ sreg0 <<= 1 ; sreg1 <<= 1 ; /* mask */ sreg0 &= 0x03 ; sreg1 &= 0x03 ; /* update LSB */ if ( tmp & 0x40 ) { sreg0 |= 1 ; } if ( tmp & 0x80 ) { sreg1 |= 1 ; } /* judge */ if ( sreg0 == ON ) { SFLAG0 = ON ; } if ( sreg1 == ON ) { SFLAG1 = ON ; } } /* update out passengers */ if ( SFLAG1 == ON ) { /* clear flag */ SFLAG1 = OFF ; /* increment */ out_passengers++ ; /* calculate counter */ *(digit+2) = out_passengers / XXDIV ; *(digit+4) = (out_passengers % XXDIV) / XDIV ; *(digit+5) = out_passengers % XDIV ; } /* update in passengers */ if ( SFLAG0 == ON ) { /* clear flag */ SFLAG0 = OFF ; /* increment */ in_passengers++ ; /* calculate counter */ *(digit+0) = in_passengers / XXDIV ; *(digit+1) = (in_passengers % XXDIV) / XDIV ; *(digit+2) = in_passengers % XDIV ; } if ( LTRG == ON ) { /* clear flag */ LTRG = OFF ; /* get target digit */ tmp = *(digit+state); /* clear nibble */ PORTB = 0x00 ; /* impress */ PORTB |= tmp ; /* enable target digit */ if ( state < 5) { PORTA = 0 ; PORTA |= (1 << state & 0x07) ; PORTB &= ~(1 << 4); } else { PORTB |= (1 << 4); } /* update state */ state++ ; /* judge */ if ( state == 6 ) { state = 0 ; } } } } void usr_init(void) { /* port values */ PORTA = 0x00 ; PORTB = 0x00 ; /* port directions */ TRISA = 0xff ; TRISB = 0x3f ; /* clear flags */ xflags.DR = 0 ; /* disable analog comparator */ CMCON = 0x07 ; /* initialize timer0 */ { /* 10MHz/4 = 2.5MHz -> 2.5MHz/16 = 156250Hz prescaler = 1:16 156250Hz / 250 = 625 Hz */ OPTION_REG = 0x01 ; /* 256 - 250 = 6 */ TMR0 = 6 ; } /* initialize Timer 1 */ { /* 10MHz/4 = 2.5MHz -> 2.5MHz/8 = 312.5kHz prescaler = 1:8 */ T1CON = (3 << 4) | 1 ; /* 65536 - 62500 */ TMR1L = STARTV % 256 ; TMR1H = STARTV / 256 ; /* enable timer1 overflow interrupt */ PIE1.TMR1IE = ON ; } /* enable global interrupt */ INTCON.GIE = ON ; /* clear counter */ TMR1H = 0 ; TMR1L = 0 ; /* others */ state = 0 ; in_passengers = 0 ; out_passengers = 0 ; }  生産現場では、材料入庫と製品出庫の逐次集計に使えます。

目次

inserted by FC2 system