目次
前
次
Night Flasher
ピン数が少ないPICで、夜間点滅器を作成しました。
回路は、以下。
昼夜判定は、CdSを利用。デジタルで処理します。
半田付けすると、写真のようにコンパクトに。
夜間に点滅すればよいので、次のシーケンスを
考えました。
- LEDに0出力、センサー情報入力
- 時間待ち
- LEDにセンサー情報出力
- 時間待ち
- 1に戻る
シーケンスを扱うには、ステートマシンを用意。
主となる処理は、次のように単純。
if ( state < 2 ) { LED = OFF ; }
else { LED = tmp ; }
変数stateを使い、LEDへの出力を0とセンサー情報の
どちらかにしています。変数値では、次のようにして
いるだけ。
- state = 0 LED = 0
- state = 1 LED = 0 (時間待ち)
- state = 2 LED = tmp
- state = 3 LED = tmp(時間待ち)
状態変数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点滅に。
状況に対応して、どのタスクを使うかを考えて処理。
動作モニタは、マイコンが仕事をしているのかを、アナログ
マルチメータの針の振れでわかるようにと入れました。
目次
前
次