// 『昼夜逆転』工作室 http://jsdiy.web.fc2.com/ // ATtiny2313 // 7セグ4桁ボード // // 3分タイマー // スイッチA0で開始 スイッチA1で停止 // 0.00→3.00をカウント、3.00で点滅 // // 2008/10/10 v1.00 初版 // ポート出力内容が一定のとき(MODE_TIMER以外のとき)、-Os/3/2最適化によってLEDが暗くなる // ポート出力後に_delay_ms()を入れると、この現象が回避できる /* ポート対応 [ATtiny2313] bit 7 6 5 4 3 2 1 0 PORTA - - - - - - swL swR PORTB - - - DP 桁4 桁3 桁2 桁1 LEDボードでは左から桁1-桁4 PORTD - G F E D C B A 7セグのセグメント(下図) 7セグのセグメント図 +-A-+ F B +-G-+ E C +-D-+ DP */ #define _CATHODE_CMN_ 1 #if _CATHODE_CMN_ #define SET_PORTB(n) PORTB = (n) #define SET_PORTD(n) PORTD = (n) #else #define SET_PORTB(n) PORTB = (~(n) & 0b00011111) #define SET_PORTD(n) PORTD = (~(n) & 0b01111111) #endif #define F_CPU 1000000UL //1MHz #include #include #include const uint8_t SEGCHAR[] = { // 0b0GFEDCBA 0b00111111, //0 0b00000110, //1 0b01011011, //2 0b01001111, //3 0b01100110, //4 0b01101101, //5 0b01111101, //6 0b00100111, //7 0b01111111, //8 0b01101111, //9 0b00000000 //null }; enum _SIDX { SIDX_NULL = 10 }; #define SEG_DP 0b00010000 enum _MODE { MODE_WAIT, MODE_TIMER, MODE_FINISH, MODE_STOP }; volatile uint8_t sec; //経過時間(秒) volatile uint8_t ff; ISR(TIMER1_COMPA_vect) { if (sec < 180) sec++; else ff = 1 - ff; } int main(void) { uint8_t sidx[] = { SIDX_NULL, 0, 0, 0 }; uint8_t k, sw, tmp, mode, segDP; //ポート設定 DDRD = 0b01111111; //7セグLEDのA-G = PD0-PD6 DDRB = 0b00011111; //7セグLEDの桁位置(LEDボードの左から) = PB0-PB3, 7セグLEDのDP = PB4 PORTA = 0b00000011; //スイッチが2個(制御ボードの右から) PA0-PA1 //16bitタイマ設定 TCCR1A = 0b00000000; //CTC動作 TCCR1B = 0b00001101; //カウント周期は 1MHz/1024 = 約1kHz → 約1ms間隔 OCR1A = 1000; //割り込み周期は 1ms * 1000 = 1sec TIMSK = 0b01000000; //比較一致割り込み mode = MODE_STOP; k = 0; while (1) { //スイッチ入力 sw = PINA; //動作モード switch (mode) { case MODE_TIMER: if (sec == 180) { OCR1A = 250; //割り込み周期を短くする(高速点滅の効果) TCNT1 = 0; mode = MODE_FINISH; } tmp = sec; sidx[1] = tmp / 60; tmp %= 60; sidx[2] = tmp / 10; tmp %= 10; sidx[3] = tmp; if (~sw & 0b00000010) //スイッチA1:停止 mode = MODE_STOP; break; case MODE_FINISH: if (~sw & 0b00000010) //スイッチA1:停止 mode = MODE_STOP; break; case MODE_STOP: cli(); //割り込み禁止 sec = 0; ff = 1; sidx[1] = sidx[2] = sidx[3] = 0; mode = MODE_WAIT; break; default: //MODE_WAIT if (~sw & 0b00000001) //スイッチA0:開始 { OCR1A = 1000; TCNT1 = 0; sei(); //割り込み許可 mode = MODE_TIMER; } break; } //表示 SET_PORTB(0); SET_PORTD(0); if (ff) { segDP = (k == 1) ? SEG_DP : 0; SET_PORTB((1<< k) | segDP); SET_PORTD(SEGCHAR[sidx[k]]); if (k == 0) //1桁目のお遊び { if (mode == MODE_TIMER && sec < 180) SET_PORTD(1 << sec % 6); } } _delay_ms(1); k = (k + 1) % 4; } return 0; }