目次

Night Flasher

 ピン数が少ないPICで、夜間点滅器を作成しました。

 回路は、以下。




 昼夜判定は、CdSを利用。デジタルで処理します。


 半田付けすると、写真のようにコンパクトに。



 夜間に点滅すればよいので、次のシーケンスを
 考えました。
  1. LEDに0出力、センサー情報入力
  2. 時間待ち
  3. LEDにセンサー情報出力
  4. 時間待ち
  5. 1に戻る
 シーケンスを扱うには、ステートマシンを用意。  主となる処理は、次のように単純。 if ( state < 2 ) { LED = OFF ; } else { LED = tmp ; }  変数stateを使い、LEDへの出力を0とセンサー情報の  どちらかにしています。変数値では、次のようにして  いるだけ。  状態変数stateにより、時間待ちとLEDに出力する値の  管理をしていると見ればわかりやすいでしょう。  ピン番号での接続は、わかりにくいのでラベル定義。 #define LED PORTA.F0 #define SENSOR PORTA.F5  点滅するには、インターバルがほしいので  タイマー割込みで、時間差を生成します。  1秒単位で、割込みハンドラからイベントフラグを  出力すると考えました。 void interrupt(void) { /* generate 500Hz/500 = 1Hz */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = CNTBEGIN ; /* increment */ xcnt++ ; /* judge */ if ( xcnt == CNTMAX ) { /* clear */ xcnt = 0 ; /* set flag */ tflag = ON ; } } }  タイマー0のオーバーフロー割り込みを使い、イベントフラグ  tflagで通知します。  1秒ごとにイベントフラグtflagが1になるので、状態変数  stateの値を+1して、イベントを発生。  この処理は単純です。 if ( tflag == ON ) { /* clear flag */ tflag = OFF ; /* update */ state++ ; /* judge */ if ( state == 4 ) { state = 0 ; } }  内蔵モジュールがたくさんあるPICを使う場合、A/D、D/A変換器  の動作停止やタイマー関係の指定が必要。  初期化は、次のようにひとつの関数にまとめます。 void init_usr(void) { /* 4MHz */ OSCCON = (0x0d << 3) | 0x03 ; /* disable A/D converter */ ADCON0.ADON = OFF ; ADCON2 = 0 ; /* disable D/A converter */ DACCON0.DACEN = OFF ; /* disable compare module */ CM1CON0.C1ON = OFF ; CM1CON0.C1OE = OFF ; /* I/O state */ LED = OFF ; /* I/O directions */ TRISA = 0x38 ; /* bit0,1,2 as output , others as input */ /* pull-up */ WPUA = 0x20 ; /* initialize Timer 0 */ { /* 4MHz/4 = 1MHz -> 1MHz/8 = 125kHz prescaler = 1:8 */ OPTION_REG = 0x02 ; /* 256 - 6 = 250 */ TMR0 = CNTBEGIN ; /* enable timer0 overflow interrupt */ INTCON.T0IE = ON ; } /* enable general interrupt */ INTCON.GIE = ON ; /* clear flag */ tflag = OFF ; /* initialize variables */ xcnt = 0 ; state = 0 ; }  まとめると、以下。 typedef unsigned char UBYTE ; typedef unsigned int UWORD ; #define OFF 0 #define ON OFF+1 #define LED PORTA.F0 #define SENSOR PORTA.F5 #define CNTBEGIN 6 #define CNTMAX 500 volatile UBYTE state ; volatile UWORD xcnt ; volatile UBYTE tmp ; volatile UBYTE tflag ; /* function prototype */ void init_usr(void); /* interrupt handler */ void interrupt(void) { /* generate 500Hz/500 = 1Hz */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = CNTBEGIN ; /* increment */ xcnt++ ; /* judge */ if ( xcnt == CNTMAX ) { /* clear */ xcnt = 0 ; /* set flag */ tflag = ON ; } } } void main(void) { /* initialize */ init_usr() ; /* endless loop */ while ( ON ) { /* get sensor state */ tmp = SENSOR ; /* event handling */ if ( tflag == ON ) { /* clear flag */ tflag = OFF ; /* update */ state++ ; /* judge */ if ( state == 4 ) { state = 0 ; } } /* flashing */ { if ( state < 2 ) { LED = OFF ; } else { LED = tmp ; } } } } /* define function body */ void init_usr(void) { /* 4MHz */ OSCCON = (0x0d << 3) | 0x03 ; /* disable A/D converter */ ADCON0.ADON = OFF ; ADCON2 = 0 ; /* disable D/A converter */ DACCON0.DACEN = OFF ; /* disable compare module */ CM1CON0.C1ON = OFF ; CM1CON0.C1OE = OFF ; /* I/O state */ LED = OFF ; /* I/O directions */ TRISA = 0x38 ; /* bit0,1,2 as output , others as input */ /* pull-up */ WPUA = 0x20 ; /* initialize Timer 0 */ { /* 4MHz/4 = 1MHz -> 1MHz/8 = 125kHz prescaler = 1:8 */ OPTION_REG = 0x02 ; /* 256 - 6 = 250 */ TMR0 = CNTBEGIN ; /* enable timer0 overflow interrupt */ INTCON.T0IE = ON ; } /* enable general interrupt */ INTCON.GIE = ON ; /* clear flag */ tflag = OFF ; /* initialize variables */ xcnt = 0 ; state = 0 ; }  同じハードウエアを使い、RTOS(Real Time Operating System)を  利用したファームウエアは、以下。 #define LLED0 PORTA.F0 #define MFOUT PORTA.F2 #define CDS PORTA.F5 #define OFF 0 #define ON OFF+1 #define MASKFF 0xff #define MASK0F 0x0F #define MASK0E 0x0e #define CNTBEGIN 131 #define CNTMAX 10 #define TSK_ID_MAX 8 #define TSK_ID0 0 #define TSK_ID1 1 #define TSK_ID2 2 #define TSK_ID3 3 #define TSK_ID4 4 #define TSK_ID5 5 #define TSK_ID6 6 #define TSK_ID7 7 #define TTS_SUSPEND 0 #define TTS_WAIT TTS_SUSPEND+1 #define TTS_READY TTS_SUSPEND+2 volatile unsigned char wflag ; volatile unsigned char ready ; volatile unsigned char suspend; volatile unsigned char waitq ; volatile unsigned char run_tsk; volatile unsigned char bpat[8] ; volatile unsigned char wcount[8] ; volatile unsigned char xtim0 ; volatile unsigned char timcnt ; volatile unsigned char state ; #define DAY 0 #define NIGHT 1 /*------------------------*/ /* task function protoype */ /*------------------------*/ void tsk0_proc(void); void tsk1_proc(void); void tsk2_proc(void); void tsk3_proc(void); void tsk4_proc(void); void tsk5_proc(void); void tsk6_proc(void); void tsk7_proc(void); /*-----------------------*/ /* system call prototype */ /*-----------------------*/ void init_os(void); void rsm_tsk(unsigned char x); void sus_tsk(unsigned char x); void slp_tsk(void); void wai_tsk(unsigned char x); unsigned char is_tsk_ready(unsigned char x); void timer_handler(void); /* function prototype */ void init_usr(void); /* interrupt handler */ void interrupt(void) { /* generate 100Hz */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = CNTBEGIN ; /* increment */ timcnt++ ; /* judge */ if ( timcnt == CNTMAX ) { /* clear */ timcnt = 0 ; /* set flag */ wflag = ON ; } } } void main(void) { /* initialize */ init_usr() ; /* initialize task */ init_os(); /* endless loop */ run_tsk = TSK_ID0 ; while ( ON ) { /* round robbin */ if ( is_tsk_ready( run_tsk ) != OFF ) { switch ( run_tsk ) { case TSK_ID0 : tsk0_proc(); break ; case TSK_ID1 : tsk1_proc(); break ; case TSK_ID2 : tsk2_proc(); break ; case TSK_ID3 : tsk3_proc(); break ; case TSK_ID4 : tsk4_proc(); break ; case TSK_ID5 : tsk5_proc(); break ; case TSK_ID6 : tsk6_proc(); break ; case TSK_ID7 : tsk7_proc(); break ; default : break ; } } run_tsk++; if ( run_tsk == TSK_ID_MAX ) { run_tsk = TSK_ID0 ; } /* 10ms counter */ if ( wflag == ON ) { wflag = OFF ; timer_handler(); } } } /* define function body */ void init_usr(void) { /* select 1MHz */ OSCCON = (0x0b << 3) | 0x03 ; /* disable A/D converter */ ADCON0.ADON = OFF ; ADCON2 = 0 ; /* disable D/A converter */ DACCON0.DACEN = OFF ; /* disable compare module */ CM1CON0.C1ON = OFF ; CM1CON0.C1OE = OFF ; /* I/O directions */ TRISA = 0x38 ; /* bit0,1,2 as output , others as input */ /* pull-up */ WPUA = 0x30 ; /* initialize Timer 0 */ { /* 1MHz/4 = 250kHz -> 250kHz/2 = 125kHz prescaler = 1:2 */ OPTION_REG = 0x00 ; /* 256 - 125 = 131 */ TMR0 = CNTBEGIN ; /* enable timer0 overflow interrupt */ INTCON.TMR0IE = ON ; } /* enable general interrupt */ INTCON.GIE = ON ; /* initialize variables */ state = NIGHT ; timcnt = 0 ; xtim0 = 0 ; /* clear flags */ wflag = OFF ; } /*----------------*/ /* task functions */ /*----------------*/ /* system control */ void tsk0_proc(void) { /* judge */ if ( CDS == ON ) { /* update state */ if ( state == DAY ) { state = NIGHT ; /* task handling */ rsm_tsk( TSK_ID1 ) ; } } else { /* udate state */ if ( state == NIGHT ) { state = DAY ; /* task handling */ sus_tsk( TSK_ID1 ) ; rsm_tsk( TSK_ID2 ) ; } } /* 200ms */ wai_tsk( 20 ) ; } /* LED flashing */ void tsk1_proc(void) { /* impress */ LLED0 = xtim0 & ON ; /* increment */ xtim0++ ; /* 500ms */ wai_tsk( 50 ) ; } /* turn off LED */ void tsk2_proc(void) { /* impress */ LLED0 = OFF ; /* exit */ slp_tsk(); } /* get sensor state */ void tsk3_proc(void) { /* monitor */ MFOUT = timcnt & ON ; /* 100ms */ wai_tsk( 10 ) ; } void tsk4_proc(void) { } void tsk5_proc(void) { } void tsk6_proc(void) { } void tsk7_proc(void) { } /*------------------*/ /* system call body */ /*------------------*/ void init_os(void) { /* clear RTOS values */ ready = 0 ; suspend = 0 ; waitq = 0 ; /* bit pattern */ *(bpat+0) = 0x01 ; *(bpat+1) = 0x02 ; *(bpat+2) = 0x04 ; *(bpat+3) = 0x08 ; *(bpat+4) = 0x10 ; *(bpat+5) = 0x20 ; *(bpat+6) = 0x40 ; *(bpat+7) = 0x80 ; /* TASK create */ *(wcount+0) = 0 ; *(wcount+1) = 0 ; *(wcount+2) = 0 ; *(wcount+3) = 0 ; *(wcount+4) = 0 ; *(wcount+5) = 0 ; *(wcount+6) = 0 ; *(wcount+7) = 0 ; /* initialize task state */ ready = 0x09 ; suspend = ready ^ MASKFF ; } void rsm_tsk(unsigned char x) { unsigned char tmp ; unsigned char tmpx ; /* get bit pattern */ tmp = *(bpat+x); tmpx = tmp ^ MASKFF ; /* bit handling */ ready |= tmp ; suspend &= tmpx; waitq &= tmpx; } void sus_tsk(unsigned char x) { unsigned char tmp ; unsigned char tmpx ; /* get bit pattern */ tmp = *(bpat+x); tmpx = tmp ^ MASKFF ; /* bit handling */ ready &= tmpx; suspend |= tmp ; waitq &= tmpx; } void slp_tsk(void) { sus_tsk(run_tsk); } void wai_tsk(unsigned char x) { unsigned char tmp ; unsigned char tmpx ; /* get bit pattern */ tmp = *(bpat+run_tsk); tmpx = tmp ^ MASKFF ; /* bit handling */ ready &= tmpx; suspend &= tmpx; waitq |= tmp ; /* update counter */ *(wcount+run_tsk) = x ; } unsigned char is_tsk_ready(unsigned char x) { return( ready & *(bpat+x) ) ; } void timer_handler(void) { int loop; for ( loop = 0 ; loop < TSK_ID_MAX ; loop++ ) { if ( (waitq & *(bpat+loop)) > 0 ) { *(wcount+loop) = *(wcount+loop) - 1 ; if ( *(wcount+loop) == 0 ) { rsm_tsk(loop); } } } }  タスクを4つ用意し、以下のように役割分担しました。 タスク0 昼夜判定 タスク1 LED点滅 タスク2 LED消灯 タスク3 動作モニタ  RTOSは、μITRONのシステムコールに仕様を合わせました。  昼だとLEDを消灯しておき、夜だとLED点滅に。  状況に対応して、どのタスクを使うかを考えて処理。  動作モニタは、マイコンが仕事をしているのかを、アナログ  マルチメータの針の振れでわかるようにと入れました。

目次

inserted by FC2 system