// 2006/01/22 /*---------------------------------------------------------------------------- ・プロジェクト名 ボタン一つで多機能処理を行うテストプログラム ・仕様 INT0ポートの割り込みを使用したボタンの 短押し(〜2秒)、長押し(2秒〜5秒)、長押し(5秒以降)で動作変更 ・出力ポート PB0...7:LED駆動(Lアクティブ) PD6:LED駆動(Lアクティブ) PD0,1,3,4,5:H出力(未接続) ・入力ポート PD2:プッシュスイッチ端子(INT0) ・著作等 nemy WinAVRコンパイル用Cソースコード ----------------------------------------------------------------------------*/ //---------------------------------------------------------------------------- //インクルード、定義など #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #include <avr/sleep.h> #define CPU_CLOCK 40//CPUクロックを100k分の1で書く。(40=4MHz) //sbi cbi をC言語で感覚的に使えるように…。 #define sbi(PORT,BIT) PORT|=_BV(BIT) // PORTの指定BITに1をセット #define cbi(PORT,BIT) PORT&=~_BV(BIT) // PORTの指定BITをクリア //ボタン状態遷移列挙子 enum _ButtonStat {STANDBY,CLICK,LONGPUSH}; enum _ModeStat {BOOT,FLASH,LIGHT,SLEEP,WAKE}; //グローバル変数 enum _ButtonStat g_btnstat; enum _ModeStat g_modestat; unsigned char g_ucBtnCount;//ボタンPD2の押下時間 //---------------------------------------------------------------------------- //プロトタイプ宣言 void wait(unsigned char); void BootPerformance(void); void PowerDown(void); void SetInt0(unsigned char); void KillInt0(void); unsigned char GetInt0Type(void); void SetTimerCounter0(unsigned char); void SetTimerCounter1(unsigned char,unsigned char,unsigned char); //---------------------------------------------------------------------------- //ウェイト関数 void wait(unsigned char ucLoop) { unsigned char i,j; for(i = 0;i < ucLoop;i++) { for(j = 1;j < 0xFF;j++)//unsigned char は最大0xFFのはず { j--; //ダミー処理 j++; //ダミー処理 } } return; } //---------------------------------------------------------------------------- //スリープ(パワーダウン)関数 void PowerDown(void) { //スリープ動作のパワーダウンに設定 sbi(MCUCR, SM);//MCUCRのSMビットをセット(1) //スリープ動作のアイドルに設定 //cbi(MCUCR, SM);//MCUCRのSMビットをセット(0) //スリープ動作許可 sbi(MCUCR, SE);//MCUCRのSEビットをセット(1) //スリープ sleep_mode(); return; } //---------------------------------------------------------------------------- //外部割り込み処理(INT0)設定 #define INT_LOW 0x00 //ISC01=0, ISC00=0 → INT0Lowレベルで発生(SLEEPパワーダウンからの復帰条件) #define INT_DOWN 0x02 //ISC01=1, ISC00=0 → INT0立下りエッジ検出 #define INT_UP 0x03 //ISC01=1, ISC00=1 → INT0立上りエッジ検出 void SetInt0(unsigned char ucType) { unsigned char tmp; cbi(DDRD, PD2); //INT0を入力に設定 sbi(GIMSK, INT0); //一般割込みマスクレジスタ(GIMSK)のINT0(外部割込み0)を1にして割込み許可 tmp = MCUCR & 0xFC; MCUCR = tmp | ucType; return; } //---------------------------------------------------------------------------- //外部割り込み処理(INT0)設定解除 void KillInt0(void) { cbi(GIMSK, INT0); //一般割込みマスクレジスタ(GIMSK)のINT0(外部割込み0)を1にして割込み不許可 return; } //---------------------------------------------------------------------------- //外部割り込み処理(INT0)設定読込 unsigned char GetInt0Type(void) { if(bit_is_clear(MCUCR, ISC01) && bit_is_clear(MCUCR, ISC00)) return INT_LOW; if(bit_is_set(MCUCR, ISC01) && bit_is_clear(MCUCR, ISC00)) return INT_DOWN; if(bit_is_set(MCUCR, ISC01) && bit_is_set(MCUCR, ISC00)) return INT_UP; return INT_LOW; } //---------------------------------------------------------------------------- //タイマ/カウンタ0設定 #define STC0_STOP 0x00//動作停止 #define STC0_CK 0x01//CPUクロック1分周 #define STC0_CK8 0x02//CPUクロック8分周 #define STC0_CK64 0x03//CPUクロック64分周 #define STC0_CK256 0x04//CPUクロック256分周 #define STC0_CK1024 0x05//CPUクロック1024分周 #define STC0_DOWN 0x06//T0ピン立下りエッジ #define STC0_UP 0x07//T0ピン立上りエッジ void SetTimerCounter0(unsigned char ucType) { TCCR0 = ucType; TCNT0 = 0x00;//カウント値の初期化(8bit) return; } //---------------------------------------------------------------------------- //タイマ/カウンタ1設定 #define STC1_STOP 0x00//動作停止 #define STC1_CK 0x01//CPUクロック1分周 #define STC1_CK8 0x02//CPUクロック8分周 #define STC1_CK64 0x03//CPUクロック64分周 #define STC1_CK256 0x04//CPUクロック256分周 #define STC1_CK1024 0x05//CPUクロック1024分周 #define STC1_DOWN 0x06//T0ピン立下りエッジ #define STC1_UP 0x07//T0ピン立上りエッジ void SetTimerCounter1(unsigned char ucType,unsigned char ucCompareH,unsigned char ucCompareL) { unsigned char tmp; //カウンタ設定 tmp = TCCR1B & 0xFC; TCCR1B = tmp | ucType; //比較割込を有効化 sbi(TIMSK,OCIE1A); //比較カウント値設定 OCR1AH = ucCompareH; OCR1AL = ucCompareL; TCNT1 = 0x0000;//カウント値の初期化 return; } //---------------------------------------------------------------------------- //メイン int main(void) { //ポートIO設定 DDRB = 0xFF;//ポートB OOOO OOOO DDRD = 0x7B;//ポートD xOOO OIOO //ポート状態の初期化 PORTB = 0xFF;//Port_B HHHH HHHH PORTD = 0x7F;//Port_D xHHH HUHH H:出力(1) L:出力(0) U:内蔵プルアップ(1) D:プルアップなし(0) //ウォッチドッグタイマ設定(一応明示的に) //WDTCR = 0x18; sbi(WDTCR,WDTOE);//ウォッチドッグ不許可への条件 cbi(WDTCR,WDE);//ウォッチドッグ不許可に //タイマ割込設定 // CPUCLOCK(4MHz) / 1024 = 3906 Hz よって割込比較値651(0x028B)で1秒6回(0.1667秒毎)割込 SetTimerCounter1(STC1_CK1024,0x02,0x8B); //変数宣言・初期化 g_btnstat = STANDBY;//ボタン状態遷移 g_modestat = BOOT;//モード状態遷移 unsigned char ucFlashType = 0x00;//Flashモード時の点灯データ unsigned char ucLightType = 0x00;//Lightモード時の点灯データ //動作メイン処理 while(1) { //各モードの処理ルーチン switch(g_modestat) { //初期化 case BOOT: cli();//割り込み処理禁止 g_ucBtnCount = 0x00; ucFlashType = 0x01; ucLightType = 0x01; g_btnstat = STANDBY; g_modestat = FLASH; BootPerformance(); sei();//割り込み処理解禁 break; //点滅 case FLASH: //処理 PORTB = ~ucFlashType; wait(0xff); PORTB = 0xFF; wait(0xff); //ボタン状態遷移・処理ルーチン switch(g_btnstat) { case STANDBY: break; case CLICK: ucFlashType++; g_btnstat = STANDBY; break; case LONGPUSH: g_modestat = LIGHT; g_btnstat = STANDBY; break; } break; //点灯 case LIGHT: //処理 PORTB = ~ucLightType; //ボタン状態遷移・処理ルーチン switch(g_btnstat) { case STANDBY: break; case CLICK: ucLightType++; g_btnstat = STANDBY; break; case LONGPUSH: g_modestat = SLEEP; g_btnstat = STANDBY; break; } break; //スリープ case SLEEP: PORTB = 0xff;//非点灯に SetInt0(INT_LOW);//INT0割込み設定(Lowレベル) スリープ復帰用 PowerDown(); KillInt0();//INT0割込み禁止 g_modestat = WAKE; g_btnstat = STANDBY; break; //スリープ復帰 case WAKE: //ボタン状態遷移・処理ルーチン switch(g_btnstat) { case STANDBY: break; case CLICK: g_modestat = SLEEP; g_btnstat = STANDBY; break; case LONGPUSH: g_modestat = BOOT; g_btnstat = STANDBY; break; } break; } } return 0; } //---------------------------------------------------------------------------- //INT0 外部割り込み処理 SIGNAL(SIG_INTERRUPT0) { switch(GetInt0Type()) { //Lowレベルでした case INT_LOW: break; //立下りでした case INT_DOWN: break; //立上りでした case INT_UP: break; } return; } //---------------------------------------------------------------------------- //タイマ/カウンタ0 比較一致割込み処理 SIGNAL(SIG_OUTPUT_COMPARE1A) { //ボタン状態Lであれば押下時間計測継続 if(bit_is_clear(PIND,PD2)) { g_ucBtnCount += 1; } else { //ボタンが離されたのか、元々からか? if(g_ucBtnCount == 0) { //元々 } else { //離された g_ucBtnCount = 0; g_btnstat = CLICK; } } //長時間押して2秒以上たった if(12 < g_ucBtnCount) { g_ucBtnCount = 0; g_btnstat = LONGPUSH; } //カウンタを0に戻す TCNT1H = 0x00; TCNT1L = 0x00; return; } //---------------------------------------------------------------------------- //起動時のパフォーマンス void BootPerformance(void) { unsigned char ucTmp; for(ucTmp = 1;ucTmp < 0x80;ucTmp = ucTmp << 1) { PORTB = ~ucTmp; wait(0xff); } for(ucTmp = 128;1 < ucTmp;ucTmp = (ucTmp >> 1) & 0x7F) { PORTB = ~ucTmp; wait(0xff); } for(ucTmp = 0;ucTmp < 10;ucTmp++) { PORTB = 0x00; wait(0xff); PORTB = 0xff; wait(0xff); } return; } //----------------------------------------------------------------------------