目次
前
次
クリスマスツリー
8ピンのPIC16F629を利用して
クリスマスツリーを実現します。
9個のLEDを利用していますが、木の頂上に
ある赤LEDは1個独立で、他は左右2個のLED
を1セットで考えます。
LEDを点灯するためのドライバとして小信号の
トランジスタを使います。
5セットのLEDを順次点灯すればよいので
複数ステップでの点灯、消灯を考えました。
(上から0、1、2、3、4とLEDセットの番号付け)
- step0 0(ON) 1(OFF) 2(OFF) 3(OFF) 4(ON)
- step1 0(ON) 1(ON) 2(OFF) 3(OFF) 4(OFF)
- step2 0(ON) 1(OFF) 2(ON) 3(OFF) 4(OFF)
- step3 0(ON) 1(ON) 2(ON) 3(OFF) 4(ON)
- step4 0(ON) 1(OFF) 2(OFF) 3(ON) 4(OFF)
- step5 0(ON) 1(ON) 2(OFF) 3(ON) 4(OFF)
- step6 0(ON) 1(OFF) 2(ON) 3(ON) 4(ON)
- step7 0(ON) 1(ON) 2(ON) 3(ON) 4(OFF)
- step8 0(OFF) 1(ON) 2(ON) 3(ON) 4(ON)
合計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 ;
}
目次
前
次