/******************************************* sample.c 2007.04.26 by Masaki Shinomiya PIC16F84A サンプルプログラム to be compiled by SDCC ********************************************/ #include #include /*** usefull assembler codes ***/ #define Nop() do { _asm nop _endasm; } while(0) #define ClrWdt() do { _asm clrwdt _endasm; } while(0) #define Sleep() do { _asm sleep _endasm; } while(0) #define EEPROM_WRITE() do { \ EECON2=0x00; /* Get in right bank */ \ __asm MOVLW 0x55 __endasm; \ __asm MOVWF EECON2 __endasm; \ __asm MOVLW 0xaa __endasm; \ __asm MOVWF EECON2 __endasm; \ __asm BSF EECON1,1; __endasm; \ } while(0) /*** word <--> byte ******************/ struct hl { unsigned char low; unsigned char high; }; union uword { struct hl bytes; unsigned short word; }; static union uword work; /*** word <--> byte usage unsigned char lowerbyte, higerbyte; unsigned int value; work.bytes.low = lowerbyte; work.bytes.high = higherbyte; value = work.word; *****************************************/ /*** I/O layout ******** PORT# In/Out Name RB7 IN SW1 RB1 OUT LED1 *************************/ #define SW1 (RB7 == 0) // negative logic #define LED1 RB1 #define LON 0 // sink on #define LOFF 1 #define CPUFREQ 20.0 // MHz #define MSEC 20 // CPUFREQ*250.0/256 kHz #define SMOOTH 100 // SW1入力の平滑度 #define BRINK1 500 // msec 最初の点滅(半)周期 #define BRINK2 100 // msec static unsigned char volatile loadflag, waitflag; static unsigned int volatile brink, countvalue; static unsigned int up1, down1; static signed char swcount; static unsigned char swflag, swold; void wait_msec( unsigned int ); /* configuration bits */ int at 0x2007 __config = _HS_OSC & _WDT_ON & _PWRTE_ON; void initialize() { PORTA = 0xff; // 全ビットhigh PORTB = 0xff; // LED全消灯 TRISA = 0xff; // RAは全入力 TRISB = 0xf0; // RB下位4bit出力 OPTION_REG = 0x07; // WDT分周比128 (約2秒), week pull up PSA = 1; // TM0はプリスケーラ使わない(WDTで使う) /*** カウンタの初期化 ***/ waitflag = 0; up1 = 0; down1 = 0; brink =0; /*** フラグの初期化 ***/ loadflag = 0; waitflag = 0; swflag = 0; swold = 0; T0IF = 0; // 割り込みフラグクリア T0IE = 1; // TMR0オーバーフロー割り込み発生許可 GIE= 1; // 割り込み許可 LED1 = LON; // LED点灯 wait_msec( 500 ); ClrWdt(); // ウェイト時間中にWDTがタイムアップすると困るので wait_msec( 500 ); ClrWdt(); wait_msec( 500 ); ClrWdt(); wait_msec( 500 ); LED1 = LOFF; // LED消灯 } /* interrupt process */ static void timer() interrupt 0 { T0IF = 0; // 割り込みフラグクリア /*** load down counter ***/ if ( loadflag ) { down1 = countvalue; // カウント値(msec)をロード up1 = 0; // msec未満をクリア loadflag = 0; } /*** msec timer ***/ if ( ++up1 > MSEC ) { up1 = 0; if (down1) { --down1; } } /*** アンダーフロー時の処理 ***/ if ( down1 == 0 ) { if ( waitflag ) { // ウェイト中(点滅しない) waitflag = 0; // アンダーフローを伝えるフラグ } else if ( brink > 0) { // LED点滅 if ( LED1 == LOFF ) { LED1 = LON; } else { LED1 = LOFF; } down1 = brink; // カウント再スタート } } } void wait_msec( unsigned int msec) { if ( msec == 0 ) { return; } // 0 msec なら何もしない countvalue = msec; // カウント値をセット loadflag = 1; // ロード指令 waitflag = 1; // ウエイト中を示すフラグ while ( waitflag ) { ; } // アンダーフローまで待つ } unsigned char sw() { /*** SW1の状態をカウントすることで積分の効果 ***/ if ( SW1 ) { if ( ++swcount >= SMOOTH ) { swcount = SMOOTH; swflag = 1; } } else { if ( --swcount <= 0 ) { swcount = 0; swflag = 0; } } return swflag; } int main() { unsigned char swnew; initialize(); while (1) { ClrWdt(); // WDTクリア swnew = sw(); // SW1入力をチェック if ( swnew ) { LED1 = LON; // SW1が押されている間はLED点灯 } else if ( swold ) { // 立ち下がり検出 LED1 = LOFF; // いったん消灯 wait_msec( 100 ); // 2重押し防止のための休止 if ( brink == BRINK1 ) { brink = BRINK2; // 点滅周期変更 } else { brink = BRINK1; // 点滅開始または変更 } countvalue = brink; // 新しい点滅(半)周期をセットして loadflag = 1; // カウンタへのロード指令 } swold = swnew; // SW1のステータスを保存 } }