/* * dcf77_1.c * * Created: 23.07.2013 20:43:18 * Author: Anwender */ #include #include #include #include #include //#define DISPLAY_DCFERROR // show DCF 77 Error #undef DISPLAY_DCFERROR // show DCF 77 Error //#define ONLY_SIMULATOR // define simulator = 2ms instead of 20ms interval, maxbright = 1 instead of 16, 20ms reset pulse for dcf and display init #undef ONLY_SIMULATOR // define simulator = 2ms instead of 20ms interval, maxbright = 1 instead of 16, 20ms reset pulse for dcf and display init #define ENABLE_DEBUG_KEY // Längeres Drücken von "Datum" startet Debug-Modus // #undef ENABLE_DEBUG_KEY #define BRIGHTNESS_ENABLE // Verschiedene Helligkeitsstufen //#undef BRIGHTNESS_ENABLE typedef unsigned char byte; typedef unsigned short word ; union word_u { word wordval; byte byteval[2]; }; union quadword_u { uint64_t orgval; byte byteval[8]; }; //-------------------------- DCF 77 --------------------------- // DCF 77 Input = PORT A 0; #define GET_DCF ((PINA >> PINA0) & 1) // Result in LSB!, d.h. >> falls nicht Bit 0 von Port #define DCF_BEGIN_RESET PORTA |= (1 << PORTA3) // set dcf 77 module Reset (Port A, Pin 3) #define DCF_END_RESET PORTA &= ~ (byte) (1 << PORTA3) // clear dcf 77 module Reset volatile static union word_u prescale_20ms; static byte dcf_lastval; static byte dcf_lowtime; static byte dcf_hightime; static union quadword_u dcf_bits; static byte dcf_bitcount; volatile static byte dcf_msg; #define DCF_INP_NONE 0 // for dcf_stat 000 #define DCF_INP_ERR 1 // dcf signal error (timing/timeout)static byte dcf_ok; 001 #define DCF_INP_RECEIVED 2 // #define DCF_INP_0 0 // "0" received 010 #define DCF_INP_1 1 // "1" received 011 #define DCF_INP_COMPLETE 4 // dcf end of cycle received 100 (+ INP_0 oder INP_1) static byte dcf_stat; #define DCF_STAT_NULL 0 // for dcf_stat #define DCF_STAT_ERR 1 #define DCF_STAT_REC 2 #define DCF_STAT_OK 3 static byte dcf_err ; // BCD Error Code volatile static byte dcf_reset_ctr; #ifdef simulator #define DCF_RESET_CYCLES 10 // 100 20ms cycles = 2 sec !!! #endif #ifndef simulator #define DCF_RESET_CYCLES 100 // 100 20ms cycles = 2 sec !!! #endif //------------------------------ TIME --------------------------------- struct time_str { byte secL; // all BCD ! byte secH; byte minL; byte minH; byte hourL; byte hourH; byte dow; // 0...6 byte dayL; byte dayH; byte monthL; byte monthH; byte yearL; byte yearH; }; const static PROGMEM char CompileDate[] = __DATE__; // "Aug 15 2013" 0 = month, 4,5 = day, 9 byte eeprom_year EEMEM = 0x13 ; byte eeprom_month EEMEM = 0x08; byte eeprom_day EEMEM = 0x15 ; byte eeprom_checksum EEMEM = 0x30 ; volatile static byte sec_prescaler; // prescaler from 20ms to 1sec static struct time_str time; static struct time_str new_time; // für Zeit setzen und debug #define PRESC_20MS_TO_SEC 50+1 // volatile static byte msg_newsecond; // 1=message from ISR to main: new second! #define MSG_NEWSEC_NO 0 #define MSG_NEWSEC_YES 1 const PROGMEM byte DaysinMonth[] = {31, 28 ,31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const PROGMEM char MonthNames[] = {"Jan.Feb.Mar.Apr.May.Jun.Jul.Aug.Sep.Oct.Nov.Dec"}; static byte time_is_set; #define TIME_SET 1 #define TIME_NOTSET 0 //--------------------------- KEYBOARD --------------------------------- // Key0/1 Input = Port A 1/2 #define GET_KEY0 ((PINA >> PINA1) & 0x01) // result in LSB => 0 or 1 #define GET_KEY1 ((PINA >> PINA2) & 0x01) static byte key0_lastval; // 0=key pressed static byte key0_downtime; static byte key0_releasetime; volatile static byte key0_stat; static byte key0_repeat_ctr; #define KEY_REPEAT_COUNT 20 // 20*20ms = 400ms static byte key1_lastval; // 0=key pressed static byte key1_downtime; static byte key1_releasetime; static byte key1_repeat_ctr; volatile static byte key1_stat; #define KEY_NULL 0 #define KEY_PRESS 1 #define KEY_RELEASE 2 #define KEY_DOWNL 3 #define KEY_REPEAT 4 static byte key_was_autorepeat; // 0 = normaler Tastendruck 1 = Autorepeat (für Blinken beim Zeiteinstellen) volatile static byte toggle_key; // NUR DEBUG: wechselt jeden Tastendruck!!! //----------------------- LED ------------------------- // LED columns = PORT B; 1=on, 0=off // LED rows = PORT C 0...7 PORT D 0...3; 1=on, 0=off // LED #define INIT_TIMER_PRESC 500-1 // 8MHz / 500 = 16 kHz (-1 lt. www) bzw. 8 kHz bei maxBright = 7; 1kHz bei Maxbright = 0 #define LED_ROW_COUNT 12 #define LED_COL_COUNT 8 #define LED_START_MASK 1; #ifdef simulator #define MAX_BRIGHT 7 #endif #ifndef simulator #define MAX_BRIGHT 7 #endif #define LED_COUNT 96 // 8*12 #ifdef simulator #define PRESCALE_20MS 32+1 // nur für debug #endif #ifndef simulator #define PRESCALE_20MS 320+1 // 8 kHz/50 Hz + 1 wegen preinc; 1kHz/50Hz = 20 #endif #define MILLISEC_20 20 // milliseconds per key/dcf cycle #define MILLISEC_LONGKEYPRESS 1500 // milliseconds for long keypress volatile static byte led_bright; // 0...cMax_Bright static byte led_pwm_ctr; static byte blink_ctr; // cycled 0..255 in 1ms clock. Overflow toggle blink_bit static byte blink_bit; volatile static byte ledout[LED_ROW_COUNT]; // 0: Mo(0) - So(6) // 1: Day1(0) - Day7(6) // 2: Day8(0) - Day14(6) // 3: Day15(0) - Day21(6) // 4: Day22(0) - Day28(6) // 5: Day29(0) - Day31(2), Sek.Timer(6) // 6: Jan(0) - Juni(6) // 7: Juli(0) - Dez(6) static byte led_row_nr; static union word_u led_row_mask; #define MASK_0 0x3F #define MASK_1 0x06 #define MASK_2 0x5B #define MASK_3 0x4F #define MASK_4 0x66 #define MASK_5 0x6D #define MASK_S 0x6D #define MASK_t 0x78 #define MASK_n 0x54 #define MASK_i 0x10 #define MASK_6 0x7D #define MASK_7 0x07 #define MASK_8 0x7F #define MASK_9 0x6F #define MASK_A 0x77 #define MASK_b 0x7C #define MASK_DASH 0x40 #define MASK_C 0x39 #define MASK_c 0x58 #define MASK_d 0x5E #define MASK_r 0x50 #define MASK_E 0x79 #define MASK_F 0x71 #define MASK_y 0x6E #define MASK_BLANK 0x00 const static byte bcd_mask[16] PROGMEM = {MASK_0,MASK_1,MASK_2,MASK_3,MASK_4,MASK_5,MASK_6,MASK_7,MASK_8,MASK_9,MASK_A,MASK_DASH,MASK_C,MASK_r,MASK_E,MASK_BLANK}; // A-CrE // access by ... = pgm_read_byte(&(segment_mask[...])) const static byte hex_mask[16] PROGMEM = {MASK_0,MASK_1,MASK_2,MASK_3,MASK_4,MASK_5,MASK_6,MASK_7,MASK_8,MASK_9,MASK_A,MASK_b,MASK_C,MASK_d,MASK_E,MASK_F}; // A-F // access by ... = pgm_read_byte(&(segment_mask[...])) const static byte ini_led_mask[LED_ROW_COUNT] PROGMEM = {0x7F,0x20,0x10,0x08,0x04,0x02,0x01,0x7F}; // access by ... = pgm_read_byte(&(ini_led_mask[...])) #define INI_MASK1 MASK_A #define INI_MASK2 MASK_n #define INI_MASK3 MASK_d #define INI_MASK4 MASK_i //------------------------- STATUS -------------------------------- #define STAT_NORM 0 #define STAT_SET_YEAR 1 #define STAT_SET_MONTH 2 #define STAT_SET_DAY 3 #define STAT_SET_HOUR 4 #define STAT_SET_MIN 5 #define STAT_SHOW_ERR 6 #define STAT_SHOW_DATE 7 #define STAT_SHOW_DEBUG 8 static byte clock_status; volatile static byte status_timer; // 0xFF: off, 0x00: end reached, 0xnn: countdown nn seconds #define SHOW_ERR_SEC 2 // 2s seconds error display #define SHOW_DATE_SEC 3 // 3s Datum anzeigen //------------------------- DEBUG ----------------------------------- volatile static byte debug_lowtime; volatile static byte debug_hightime; volatile static byte debug_dcfcount; // 0 bc volatile static byte debug_dcferror; // 1 de volatile static byte debug_dcfcorrect; // 2 dS volatile union quadword_u debug_dcfbits; // 3..10 d0..d7 volatile static byte debug_bytenr; // 0..10 volatile static byte debug_inprocess; // 0 = debug variabel durch andere prozeduren verändern 1 = debug variablen nicht mehr ändern! #define MAX_DEBUG_BYTENR 16 //===================================================================== static void init_keys (void) { DDRA &= ~ (byte) ((1 << PINA1) | (1 << PINA2)); // Port 1,2 Input (0) PORTA |= ((1 << PINA1) | (1 << PINA2)); // Pullup Resistor key1_lastval = 1; key0_lastval = 1; } static void init_dcf (void) { DDRA = ((DDRA | (1 << PINA3)) & ~ (1 << PINA0)); // bit 0 = 0 (dcf input), bit 3 = 1 (reset dcf output) PORTA &= ~ (byte) (1 << PINA0); // reset Bit 0 Port A -> no pullup für dcf input DCF_BEGIN_RESET; // set bit 3 (dcf 77 module reset), reset after 2 seconds; dcf_reset_ctr = DCF_RESET_CYCLES; dcf_msg = DCF_INP_NONE; } static int dayofweek(uint8_t day, uint8_t month, uint16_t year) { /** Zeller's congruence for the Gregorian calendar. **/ /** With 0=Monday, ... 5=Saturday, 6=Sunday **/ if (month < 3) { month += 12; year--; } return ((13*month+3)/5 + day + year + year/4 - year/100 + year/400) % 7; } static byte str2month (void) { const char *mystring; const char *monthstr; byte count; mystring = &CompileDate[0]; monthstr = &MonthNames[0]; count = 0; while ((count < 12) && ((pgm_read_byte(monthstr) != pgm_read_byte(mystring) || (pgm_read_byte(monthstr+1) != pgm_read_byte(mystring+1)) || (pgm_read_byte(monthstr+2) != pgm_read_byte(mystring+2))))) { count++; monthstr += 4; } return (count); } static void init_time (void) { byte tempY; byte tempM; byte tempD; byte checksum; tempY = eeprom_read_byte(&eeprom_year); checksum = tempY; time.yearL = tempY & 0x0F; time.yearH = tempY >> 4; tempM = eeprom_read_byte(&eeprom_month); checksum += tempM; time.monthL = tempM & 0x0F; time.monthH = tempM >> 4; tempD = eeprom_read_byte(&eeprom_day); checksum += tempD; time.dayL = tempD & 0x0F; time.dayH = tempD >> 4; if ((eeprom_read_byte(&eeprom_checksum) != checksum ) || (tempM > 12) || (tempM == 0) || (tempD > 31) || (tempD == 0)) { // wrong or no date stored in eeprom time.yearH = pgm_read_byte(&CompileDate[9]) & 0x0F; time.yearL = pgm_read_byte(&CompileDate[10]) & 0x0F; time.monthL = str2month(); if (time.monthL > 11) { time.monthL = 1; // falscher oder unbekannter Monat -> JAnuar time.monthH = 0; } else if (time.monthL > 8) { time.monthH = 1; time.monthL++; } else { time.monthH = 0; time.monthL++; } time.dayL = pgm_read_byte(&CompileDate[5]) & 0x0F; time.dayH = pgm_read_byte(&CompileDate[4]) & 0x0F; // Achtung verschiebt sich evtl bei einstelligen Tagen ??? if ((time.dayL > 9) || (time.dayL + 10*time.dayH > 31)) { time.dayL = 1; time.dayH = 1; } }; time.dow = dayofweek(time.dayL+10*time.dayH,time.monthL+10*time.monthH,2000+time.yearL+10*time.yearH); // all others are zero } static void init_leds (void) { int8_t i; led_bright = MAX_BRIGHT; // led_pwm_ctr = 0; --- alle Statischen Variablen sind beim Start := 0 gesetzt // led_row_nr = 0; led_row_mask.wordval = LED_START_MASK; // 01, shifted to the left // ... define ports PORTB = 0; // Column PORTC = 0; // Row L PORTD = 0; // Row H DDRB = 0xFF; // Column Output DDRC = 0xFF; // Row (L) DDRD = 0x0F; // Row (H) for(i = LED_ROW_COUNT-1; i >= 0; i--) { ledout[i] = pgm_read_byte(&(ini_led_mask[i])); } } static void tim_leds (void) { // Select Row PORTB = 0; // Zeile abschalten PORTC = 0; PORTD = 0; PORTC = led_row_mask.byteval[0]; PORTD = led_row_mask.byteval[1]; #ifdef BRIGHTNESS_ENABLE if (led_pwm_ctr++ <= led_bright) { PORTB = ledout[led_row_nr]; // LED column } else { PORTB = 0; // blank LEDs } if (led_pwm_ctr > MAX_BRIGHT) { // Dieser Teiler wird alle (MAX_LED_BRIGHT+1) mal im Timmer-Interrupt aufgerufen, d.h. für MAX_LED_BRIGHT = 8 bei 8KHz Timer jede Millisekunde // PWM finished -> called every ms ! led_pwm_ctr = 0; // Next Row if (++led_row_nr >= LED_ROW_COUNT) { led_row_nr = 0; led_row_mask.wordval = LED_START_MASK; } else { led_row_mask.wordval <<= 1; } if ((--blink_ctr) == 0) { // every 256ms toggle blink bit - feste Frequenz direkt aus dem Überlauf eines Bytes bestimmt. blink_bit ^= 0x01; } } #endif #ifndef BRIGHTNESS_ENABLE PORTB = ledout[led_row_nr]; if (++led_row_nr >= LED_ROW_COUNT) { led_row_nr = 0; led_row_mask.wordval = LED_START_MASK; } else { led_row_mask.wordval <<= 1; } if ((--blink_ctr) == 0) { // every 256ms toggle blink bit - feste Frequenz direkt aus dem Überlauf eines Bytes bestimmt. blink_bit ^= 0x01; } #endif } static void init_timer (void) { TCCR1A = 0x00; //no Compare-Bit-Out/PWM OCR1A = INIT_TIMER_PRESC; TIMSK = (1< not counted down yet if ((--dcf_reset_ctr) != 0) { return; // -> EXIT if in 2 sec reset period } } dcfval = GET_DCF; dcflastval = dcf_lastval; switch (dcfval | (dcflastval << 1)) { case 0: //00b: // persisting low if (dcf_lowtime < UINT8_MAX) { dcf_lowtime++; } if (dcf_lowtime > DCF_FINALCYCLE_MAX) { dcf_msg = DCF_INP_ERR; } break; case 1: //01b: // lo -> high debug_lowtime = dcf_lowtime; debug_hightime = dcf_hightime; myhtime = dcf_hightime; myctime = myhtime + dcf_lowtime; dcf_hightime = 0; // clear last high time - keep low-time byte mymsg; if ((myctime <= DCF_CYCLE_MAX) && (myctime >= DCF_CYCLE_MIN)) { // Zyklus hat 1s Länge mymsg = DCF_INP_RECEIVED; } else if ((myctime <= DCF_FINALCYCLE_MAX) && (myctime >= DCF_FINALCYCLE_MIN)) { // Endzyklus mit 2 ms Länge mymsg = DCF_INP_COMPLETE | DCF_INP_RECEIVED; } else { mymsg = DCF_INP_ERR; } if (mymsg != DCF_INP_ERR) { if ((myhtime <= DCF_H0_MAX) && (myhtime >= DCF_H0_MIN)) { // 0 empfangen: Keine Oder-Verknüfung, da bit1 für 0 schon gelöscht } else if ((myhtime <= DCF_H1_MAX) && (myhtime >= DCF_H1_MIN)) { // 1 empfangen mymsg |= DCF_INP_1; } else { mymsg = DCF_INP_ERR; } } dcf_msg = mymsg; break; case 2: //10b: // High -> Low dcf_lowtime = 0; // sonst nichts machen break; case 3: //11b: // persisting high if (dcf_hightime < UINT8_MAX) { dcf_hightime++; } if (dcf_hightime > DCF_H1_MAX) { dcf_msg = DCF_INP_ERR; } break; } dcf_lastval = dcfval; } static void tim_keys(void) { byte keyval; // check key0 keyval = GET_KEY1; if (key1_lastval == 0) { // key was already pressed if (keyval == 0) { // key is keeping pressed if (++key1_downtime == 0) { // downtime ovfl -> keep on maxint key1_downtime = UINT8_MAX; } if (key1_downtime == MILLISEC_LONGKEYPRESS/MILLISEC_20) { key1_stat = KEY_DOWNL; key1_repeat_ctr = KEY_REPEAT_COUNT; } else if (key1_downtime > MILLISEC_LONGKEYPRESS/MILLISEC_20) { if ((--key1_repeat_ctr) == 0) { key1_stat = KEY_REPEAT; key1_repeat_ctr = KEY_REPEAT_COUNT; } } } else { // key released // if (key1_downtime <= MILLISEC_LONGKEYPRESS/MILLISEC_20) // signal "release" only if not long keypress -> veraltet { key1_stat = KEY_RELEASE; } key1_releasetime = 0; } } else { // key had not been pressed if (keyval == 0) { // key pressed now key1_downtime = 0; if (key1_releasetime >= 60/MILLISEC_20) { // ignore key press again after short release -> bounce! key1_stat = KEY_PRESS; } } else // key keeping released -> no action, just count { if (++key1_releasetime == 0) { key1_releasetime = UINT8_MAX; } } } key1_lastval = keyval; // check key0 keyval = GET_KEY0; if (key0_lastval == 0) { // key was already pressed if (keyval == 0) { // key is keeping pressed if (++key0_downtime == 0) { // downtime ovfl -> keep on maxint key0_downtime = UINT8_MAX; } if (key0_downtime == MILLISEC_LONGKEYPRESS/MILLISEC_20) { key0_stat = KEY_DOWNL; key0_repeat_ctr = KEY_REPEAT_COUNT; } else if (key0_downtime > MILLISEC_LONGKEYPRESS/MILLISEC_20) { if ((--key0_repeat_ctr) == 0) { key0_stat = KEY_REPEAT; key0_repeat_ctr = KEY_REPEAT_COUNT; } } } else { // key released // if (key0_downtime <= MILLISEC_LONGKEYPRESS/MILLISEC_20) // signal "release" only if not long keypress -> veraltet { key0_stat = KEY_RELEASE; } key0_releasetime = 0; } } else { // key had not been pressed if (keyval == 0) { // key pressed now key0_downtime = 0; if (key0_releasetime >= 60/MILLISEC_20) { // ignore key press again after short release -> bounce! key0_stat = KEY_PRESS; } } else // key keeping released -> no action, just count { if (++key0_releasetime == 0) { key0_releasetime = UINT8_MAX; } } } key0_lastval = keyval; /*if ((key0_stat != KEY_NULL) || (key1_stat != KEY_NULL)) // DEBUG ONLY !!! { toggle_key ^= 0x80; } */ } static void tim_secs(void) { if (--sec_prescaler == 0) { sec_prescaler = PRESC_20MS_TO_SEC; // 20ms * 50 + 1 (predecrement) msg_newsecond = MSG_NEWSEC_YES; // set every second if (status_timer != 0xFF) // 0xFF = off, 0x0 = count down reached (must pe processed elsewhere) 0xnn = wait for nn seconds { status_timer--; } } } static byte getdaysinMonth(byte yearL, byte yearH, byte monthL, byte monthH) { byte binmonth; byte binyear; binmonth = monthL; if (monthH != 0) { binmonth += 10; } if (binmonth == 2) { binyear = yearL + 10*yearH; if ((binyear & 0x03) == 0) { // probably leap year except 2100, but including 2000 return(29); } else { return(28); } } else { return(pgm_read_byte (&DaysinMonth[binmonth-1])); } } static void ee_savedate(void) { byte checksum; byte value; value = (time.yearH << 4) | (time.yearL); checksum = value; eeprom_write_byte(&eeprom_year,value); value = (time.monthH << 4) | (time.monthL); checksum += value; eeprom_write_byte(&eeprom_month,value); value = (time.dayH << 4) | (time.dayL); checksum += value; eeprom_write_byte(&eeprom_day,value); eeprom_write_byte(&eeprom_checksum,checksum); } static void incdate(void) { if (++time.dayL > 9) { time.dayL = 0; time.dayH++; } byte binday; byte maxday; maxday = getdaysinMonth(time.yearL,time.yearH,time.monthL,time.monthH); binday = time.dayL + 10*time.dayH; if (binday > maxday) { time.dayH = 0; time.dayL = 1; if (++time.monthL > 9) { time.monthL = 0; ++time.monthH; } if ((time.monthH == 1) && (time.monthL == 3)) { time.monthL = 1; time.monthH = 0; if (++time.yearL > 9) { time.yearL = 0; if (++time.yearH > 9) { time.yearH = 0; } } } } // save changed date ee_savedate(); } static void proc_dcf(void) { // byte mydcfstat; byte mymsg; byte dcfcorrect = 0; // 0= DCF total falsch, 1= Ddatum OK, Rest falsch, 3=Datum und Stunde OK, 7=Datum und Zeit OK, F=alles OK #define DCF_CORRECT_DATE 1 #define DCF_CORRECT_HOUR 2 #define DCF_CORRECT_MIN 4 #define DCF_CORRECT_ELSE 8 mymsg = dcf_msg; dcf_msg = DCF_INP_NONE; // alwas reset dcf_msg if (mymsg == DCF_INP_ERR) { dcf_stat = DCF_STAT_NULL; dcf_bits.orgval = 0; dcf_bitcount = 0; } else if ((mymsg & DCF_INP_RECEIVED) != 0) { // 1 oder 0 empfangen, evtl. auch Ende des Zyklus dcf_bitcount++; dcf_bits.orgval = dcf_bits.orgval >> 1; if ((mymsg & DCF_INP_1) != 0) { // Bit 1 empfangen: oberstes Bit setzen! dcf_bits.byteval[7] = dcf_bits.byteval[7] | 0x80; } if ((mymsg & DCF_INP_COMPLETE) == 0) { // Nur Bit empfangen, kein Ende dcf_stat = DCF_STAT_REC; } else { // DCF Komplett! // decode dcf 77: pYYY Yyyy | yMmm mmww | wDDd dddp | HHhh hhpM | MMmm mm1x | Ssxx xxxx | xxxx xxxx | xx00 0000 // 7:7654 3210 6:7654 3210 5:7654 3210 4:7654 3210 3:7654 3210 2:7654 3210 1:0000 0000 0:0000 0000 // org: 58 50 42 34 26 18 10 2 0 // // bits are shifted from top -> Bit59 (Parity date) is top bit! byte parity_min; byte parity_hour; byte parity_date; struct time_str temp_time; parity_date = dcf_bits.byteval[7] >> 7; temp_time.yearH = (dcf_bits.byteval[7] >> 3) & 0x0F; temp_time.yearL = ((dcf_bits.byteval[7] << 1) | (dcf_bits.byteval[6] >> 7)) & 0x0F; temp_time.monthH = ((dcf_bits.byteval[6] >> 6) & 0x01); temp_time.monthL = ((dcf_bits.byteval[6] >> 2) & 0x0F); temp_time.dow = ((dcf_bits.byteval[6] << 1) | (dcf_bits.byteval[5] >> 7)) & 0x0F; temp_time.dayH = ((dcf_bits.byteval[5] >> 5) & 0x03); temp_time.dayL = ((dcf_bits.byteval[5] >> 1) & 0x0F); parity_hour = dcf_bits.byteval[5] & 0x01; temp_time.hourH = ((dcf_bits.byteval[4] >> 6) & 0x03); temp_time.hourL = ((dcf_bits.byteval[4] >> 2) & 0x0F); temp_time.minH = ((dcf_bits.byteval[4] << 2) | (dcf_bits.byteval[3] >> 6)) & 0x07; temp_time.minL = ((dcf_bits.byteval[3] >> 2) & 0x0F); parity_min = (dcf_bits.byteval[4] >> 1) & 0x01; dcf_err = 0; if (dcf_bitcount == 59) { if (((dcf_bits.byteval[3] >> 1) & 0x01) != 1) { dcf_err = 0x20; // Bit 20 not one } else if ((((dcf_bits.byteval[2] >> 6) ^ (dcf_bits.byteval[2] >> 7)) & 1) != 1) { dcf_err = 0x17; } else if (((dcf_bits.byteval[0] >> 5) & 1) != 0) { dcf_err = 0x01; } else { dcfcorrect = DCF_CORRECT_ELSE; } } if (dcf_bitcount >= 38) { if ((parity_even_bit(temp_time.minL) ^ parity_even_bit(temp_time.minH) ^ parity_min) != 0) { dcf_err = 0x28; // Min Parity Error; } else if (temp_time.minH > 5) { dcf_err = 0x25; // Min H Error } else if (temp_time.minL > 9) { dcf_err = 0x21; // Min L Error } else { dcfcorrect |= DCF_CORRECT_MIN; } } if (dcf_bitcount >= 30) { if ((parity_even_bit(temp_time.hourL) ^ parity_even_bit(temp_time.hourH) ^ parity_hour) != 0) { dcf_err = 0x35; // Parity Hour Error } else if ((temp_time.hourL > 9) || ((temp_time.hourL + 10*temp_time.hourH) > 23)) { dcf_err = 0x29; // Hour Error; } else { dcfcorrect |= DCF_CORRECT_HOUR; } } if (dcf_bitcount >= 23) { if ((parity_even_bit(temp_time.yearH) ^ parity_even_bit(temp_time.yearL) ^ parity_even_bit(temp_time.monthH) ^ parity_even_bit(temp_time.monthL) ^ parity_even_bit(temp_time.dayH) ^ parity_even_bit(temp_time.dayL) ^ parity_even_bit(temp_time.dow) ^ parity_date) != 0) { dcf_err = 0x58; // Date parity error } else if (temp_time.yearH > 9) { dcf_err = 0x54; // Year H Error } else if (temp_time.yearL > 9) { dcf_err = 0x50; // Year L Error } else if ((temp_time.monthL + 10*temp_time.monthH) > 12) { dcf_err = 0x45; // Month Error } else if (((temp_time.dayL) > 9) || (temp_time.dayL + 10*temp_time.dayH) > 31) { dcf_err = 0x36; // Day Error } else if (temp_time.dow == 0) // 1..7 in DCF ! (0..6 intern) { dcf_err = 0x42; // DOW Error } else { dcfcorrect |= DCF_CORRECT_DATE; temp_time.dow--; } } else { // zu wenig Bits empfangen, um irgendetwas zu dekodieren dcf_err = 0x64; } if ((dcf_err == 0) && (dcf_bitcount != 59)) { dcf_err = 0x64; } if (debug_inprocess == 0) { debug_dcfbits.orgval = dcf_bits.orgval; debug_dcfcount = dcf_bitcount; debug_dcferror = dcf_err; debug_dcfcorrect = dcfcorrect; } byte date_changed = 0; if ((dcfcorrect == (DCF_CORRECT_DATE | DCF_CORRECT_ELSE | DCF_CORRECT_HOUR | DCF_CORRECT_MIN))) { // dcf korrekt: Immer Zeit setzen! if ((time.dayL != temp_time.dayL) || (time.dayH != temp_time.dayH) || (time.monthH != temp_time.monthH) || (time.monthL != temp_time.monthL) || (time.yearL != temp_time.yearL) || (time.yearH != temp_time.yearH)) { date_changed = 1; } time = temp_time; time_is_set = TIME_SET; // dcf ok, reset sceconds; time.secH = 0; time.secL = 0; dcf_stat = DCF_STAT_OK; sec_prescaler = PRESC_20MS_TO_SEC; // Reset Sec counter msg_newsecond = MSG_NEWSEC_NO; } else { dcf_stat = DCF_STAT_ERR; if (time_is_set == TIME_NOTSET) { // Zeit ist noch nicht gesetzt, versuche Reste von DCF Signal aufzuwerten! if ((dcfcorrect & DCF_CORRECT_DATE) != 0) { // datum stimmt vermutlich time.dow = temp_time.dow; time.dayL = temp_time.dayL; time.dayH = temp_time.dayH; time.monthL = temp_time.monthL; time.monthH = temp_time.monthH; time.yearL = temp_time.yearL; time.yearH = temp_time.yearH; date_changed = 1; } if ((dcfcorrect & (DCF_CORRECT_HOUR | DCF_CORRECT_MIN)) == (DCF_CORRECT_HOUR | DCF_CORRECT_MIN)) { // Stunde stimmt und Minute stimmt time.hourL = temp_time.hourL; time.hourH = temp_time.hourH; time.minL = temp_time.minL; time.minH = temp_time.minH; time.secH = 0; time.secL = 0; sec_prescaler = PRESC_20MS_TO_SEC; // Reset Sec counter msg_newsecond = MSG_NEWSEC_NO; } } // if time not set } if (date_changed != 0) { ee_savedate(); } dcf_bits.orgval = 0; dcf_bitcount = 0; } // else } // if mymsg != DCF_INP_NULL if (msg_newsecond > MSG_NEWSEC_NO) { msg_newsecond = MSG_NEWSEC_NO; if (++time.secL > 9) { time.secL = 0; if (++time.secH > 5) { time.secH = 0; if (++time.minL > 9) { time.minL = 0; if (++time.minH > 5) { time.minH = 0; if (++time.hourL > 9) { time.hourL = 0; time.hourH++; } if ((time.hourH == 2) && (time.hourL == 4)) { time.hourL = 0; time.hourH = 0; // .. datum weiterzählen incdate(); } } } } } } } static void display_debugval(byte textl, byte textr, byte val) { ledout[8] = (pgm_read_byte (&(hex_mask[val & 0x0F]))); ledout[9] = (pgm_read_byte (&(hex_mask[val >> 4]))); ledout[10] = textr; ledout[11] = textl; } static void proc_leds(void) // make LEDout from time/newtime { int8_t temp; struct time_str *timebase; int8_t i; if ((clock_status == STAT_NORM) || (clock_status == STAT_SHOW_DATE)) { timebase = &(time); } else { timebase = &(new_time); } if (clock_status == STAT_SHOW_ERR) { ledout[8] = pgm_read_byte (&(bcd_mask[(dcf_err & 0x0F)])); ledout[9] = pgm_read_byte (&(bcd_mask[(dcf_err >> 4)])); ledout[10] = pgm_read_byte (&(bcd_mask[0x0E])); if (dcf_err == 0x64) { ledout[11] = dcf_bitcount; // pattern of bitcount } else { ledout[11] = status_timer; } return; // ---> EXIT if SHOW ERROR } // ledout[0] Day of week if (clock_status == STAT_NORM) { ledout[0] = 0x01 << (*timebase).dow; } else { ledout[0] = 0; // setting time -> no day of week } // ledout[1..5] Day of Month volatile byte *mask; mask = &ledout[1]; if ((clock_status == STAT_NORM) || (clock_status == STAT_SET_DAY)) { temp = (*timebase).dayL + 10*(*timebase).dayH; } else if (clock_status == STAT_SET_YEAR) { temp = (*timebase).yearL + 10*(*timebase).yearH; } else { temp = 0; } i = 5; do { if (temp == 0) { *(mask++) = 0; } else if (temp <= 7) { if (((clock_status == STAT_SET_DAY) || (clock_status == STAT_SET_YEAR)) && (blink_bit && (key_was_autorepeat == 0))) { *(mask++) = 0x00; // LED off when blink and set time: day / year } else { *(mask++) = 0x01 << (temp-1); } temp = 0; } else // > 7 { temp = temp-7; *(mask++) = 0; } } while (--i > 0); // ledout[6..7] month if ((clock_status == STAT_SET_MONTH) && blink_bit && (key_was_autorepeat == 0)) { ledout[6] = 0; ledout[7] = 0; } else if ((clock_status == STAT_NORM) || (clock_status == STAT_SET_MONTH)) { temp = (*timebase).monthH; if (temp == 0) { // Monat 1..9 temp = (*timebase).monthL; if (temp == 0) // Monat 0 -> keine Ausgabe { ledout[6] = 0; ledout[7] = 0; } else if (temp < 7) { ledout[6] = 0x01 << (temp-1); ledout[7] = 0; } else { // 7,8,9 ledout[6] = 0; ledout[7] = 0x01 << (temp-7); } } else // 10,11,12 { temp = (*timebase).monthL; ledout[6] = 0; ledout[7] = 0x01 << (temp+3); } } else { ledout[6] = 0; ledout[7] = 0; } // ledout[8...11]: Time HHMM if (clock_status == STAT_SHOW_DEBUG) { byte byteno = debug_bytenr+1; if (--byteno == 0) { ledout[8] = pgm_read_byte (&(hex_mask[dcf_bits.byteval[7] >> 7])); ledout[9] = pgm_read_byte (&(hex_mask[dcf_bitcount &0x0F])) | 0x80; ledout[10] = pgm_read_byte (&(hex_mask[dcf_bitcount >> 4])); ledout[11] = MASK_d; } else if (--byteno == 0) { ledout[8] = pgm_read_byte (&(hex_mask[dcf_lowtime & 0x0F])) | 0x80; ledout[9] = pgm_read_byte (&(hex_mask[dcf_lowtime >> 4])) ; ledout[10] = pgm_read_byte (&(hex_mask[dcf_hightime & 0x0F])) | 0x80; ledout[11] = pgm_read_byte (&(hex_mask[dcf_hightime >> 4])); } else if (--byteno == 0) { display_debugval(MASK_b,MASK_C,debug_dcfcount); // bc = bitcount } else if (--byteno == 0) { display_debugval(MASK_E,MASK_r,debug_dcferror); // Er = dcf Error } else if (--byteno == 0) { display_debugval(MASK_S,MASK_t,debug_dcfcorrect); // St = dcf Status } else if (--byteno == 0) { display_debugval(MASK_E,MASK_y,eeprom_read_byte(&eeprom_year)); // Ey = EEPROM Year } else if (--byteno == 0) { display_debugval(MASK_E,MASK_1,eeprom_read_byte(&eeprom_month)); // E1 = month } else if (--byteno == 0) { display_debugval(MASK_E,MASK_d,eeprom_read_byte(&eeprom_year)); // Ed = day } else if (--byteno == 0) { display_debugval(MASK_E,MASK_c,eeprom_read_byte(&eeprom_checksum)); // Ec = checksum } else { byteno--; display_debugval(MASK_b,pgm_read_byte (&(hex_mask[byteno])),debug_dcfbits.byteval[byteno]); // DCF Bytes } } else if (clock_status == STAT_NORM) { ledout[8] = pgm_read_byte (&(bcd_mask[(*timebase).minL])); ledout[9] = pgm_read_byte (&(bcd_mask[(*timebase).minH])); ledout[10] = (pgm_read_byte (&(bcd_mask[(*timebase).hourL])) | ((((*timebase).secL & 0x01) == 1 ) && (dcf_stat >= DCF_STAT_REC) ? 0x0 : 0x80)); if ((*timebase).hourH == 0) { ledout[11] = 0; } else { ledout[11] = pgm_read_byte (&(bcd_mask[(*timebase).hourH])); } } else if (clock_status == STAT_SHOW_DATE) { ledout[8] = pgm_read_byte (&(bcd_mask[(*timebase).monthL])) | 0x80; ledout[9] = pgm_read_byte (&(bcd_mask[(*timebase).monthH])); ledout[10] = (pgm_read_byte (&(bcd_mask[(*timebase).dayL])) | 0x80); ledout[11] = pgm_read_byte (&(bcd_mask[(*timebase).dayH])); } else if (clock_status == STAT_SET_YEAR) { if ((blink_bit != 0) && (key_was_autorepeat == 0)) { ledout[8] = 0; ledout[9] = 0; } else { ledout[8] = pgm_read_byte (&(bcd_mask[(*timebase).yearL])); ledout[9] = pgm_read_byte (&(bcd_mask[(*timebase).yearH])); } ledout[10] = pgm_read_byte (&(bcd_mask[0])); ledout[11] = pgm_read_byte (&(bcd_mask[2])); } else if (clock_status == STAT_SET_MONTH) { if ((blink_bit != 0) && (key_was_autorepeat == 0)) { ledout[8] = 0; ledout[9] = 0; } else { ledout[8] = pgm_read_byte (&(bcd_mask[(*timebase).monthL])); if ((*timebase).monthH == 0) { ledout[9] = 0; } else { ledout[9] = pgm_read_byte (&(bcd_mask[(*timebase).monthH])); } } ledout[10] = 0; ledout[11] = 0; } else if (clock_status == STAT_SET_DAY) { if ((blink_bit != 0) && (key_was_autorepeat == 0)) { ledout[8] = 0; ledout[9] = 0; } else { ledout[8] = pgm_read_byte (&(bcd_mask[(*timebase).dayL])); ledout[9] = pgm_read_byte (&(bcd_mask[(*timebase).dayH])); } ledout[10] = 0; ledout[11] = 0; } else if (clock_status == STAT_SET_HOUR) { ledout[8] = pgm_read_byte (&(bcd_mask[(*timebase).minL])); ledout[9] = pgm_read_byte (&(bcd_mask[(*timebase).minH])); if ((blink_bit != 0) && (key_was_autorepeat == 0)) { ledout[10] = 0x80; ledout[11] = 0; } else { ledout[10] = pgm_read_byte (&(bcd_mask[(*timebase).hourL])) | 0x80; ledout[11] = pgm_read_byte (&(bcd_mask[(*timebase).hourH])); } } else if (clock_status == STAT_SET_MIN) { if ((blink_bit != 0) && (key_was_autorepeat == 0)) { ledout[8] = 0; ledout[9] = 0; } else { ledout[8] = pgm_read_byte (&(bcd_mask[(*timebase).minL])); ledout[9] = pgm_read_byte (&(bcd_mask[(*timebase).minH])); } ledout[10] = pgm_read_byte (&(bcd_mask[(*timebase).hourL])) | 0x80; ledout[11] = pgm_read_byte (&(bcd_mask[(*timebase).hourH])); } } static void inc_time_bcd(byte *lowbyte, byte incby, byte maxval, byte resval) // incby nur 1 oder 5 !!! { byte *hibyte; hibyte = lowbyte+1; if (incby == 5) // Wert 5 rundet auf nächste Vielfache von 5; 0..4 -> 5, 5..9 -> 10 { if (*lowbyte > 4) { *lowbyte = 10; // provoziert Überlauf! } else { *lowbyte = 5; } } else { (*lowbyte)++; } if (*lowbyte > 9) // incby <10! { // BCD overflow *lowbyte = *lowbyte - 10; (*hibyte)++; } if ((byte) ((byte) (*hibyte * 10) + *lowbyte) > maxval) { // maxval exceeded, reset! *lowbyte = resval; *hibyte = 0; } } static void proc_status(void) // Key0 (long): SET TIME; Key0 (short): NEXT; Key1 (short): INC; Key1 (long/repeat): INC by 5 { #ifdef DISPLAY_DCFERROR // -------------------------- STAT_SHOW_ERR ----------------------------------- if ((dcf_stat == DCF_STAT_ERR) && ((clock_status == STAT_NORM) || (clock_status == STAT_SHOW_ERR))) // show error only if normal clock display or error already being displayed - also: new error will restart timer { if (status_timer == 0xFF) { // Timer for status display has not been started status_timer = SHOW_ERR_SEC; // clock_status = STAT_SHOW_ERR; } } if ((clock_status == STAT_SHOW_ERR) && ((status_timer == 0) || (status_timer == 0xFF) || (key0_stat != KEY_NULL) || (key1_stat != KEY_NULL))) { // End Error display when timer done or key pressed! Timer= 0xFF should not occure, because clock_status should have already been reset then - just for security status_timer = 0xFF; // timer off clock_status = STAT_NORM; key0_stat = KEY_NULL; key1_stat = KEY_NULL; } #endif if (clock_status == STAT_NORM) { // Normal Clock Mode // Key0 long press -> Set Time if (key0_stat == KEY_DOWNL) { key0_stat = KEY_NULL; // ignore any other key // Enter Set Time new_time = time; clock_status = STAT_SET_YEAR; key_was_autorepeat = 0; } else if (key1_stat == KEY_PRESS) { key1_stat = KEY_NULL; // ignore any other key clock_status = STAT_SHOW_DATE; status_timer = SHOW_DATE_SEC; // 3 Seconds Date Display } } else if (clock_status == STAT_SHOW_DEBUG) { if (key1_stat == KEY_PRESS) { if ((++debug_bytenr) > MAX_DEBUG_BYTENR) { debug_bytenr = 0; } key1_stat = 0; } else if (key0_stat == KEY_PRESS) { if (debug_bytenr == 0) { debug_bytenr = MAX_DEBUG_BYTENR; } else { debug_bytenr--; } key0_stat = 0; } else if (key1_stat == KEY_DOWNL) { key1_stat = 0; debug_inprocess = 0; clock_status = STAT_NORM; } else if (key0_stat == KEY_DOWNL) { key0_stat = 0; debug_inprocess = 0; clock_status = STAT_NORM; } } else if (clock_status == STAT_SHOW_DATE) { if (key1_stat == KEY_DOWNL) { key1_stat = KEY_NULL; // ignore any other key #ifdef ENABLE_DEBUG_KEY clock_status = STAT_SHOW_DEBUG; debug_inprocess = 1; #endif debug_bytenr = 0; } if ((key0_stat == KEY_PRESS) || (key1_stat == KEY_PRESS) || (status_timer == 0xFF) || (status_timer == 0x0)) { key0_stat = KEY_NULL; // ignore any other key key1_stat = KEY_NULL; // ignore any other key clock_status = STAT_NORM; status_timer = 0xFF; } } else if ((clock_status >= STAT_SET_YEAR) && (clock_status <= STAT_SET_MIN)) { // Set Time if (clock_status == STAT_SET_YEAR) { if (key1_stat == KEY_PRESS) { key1_stat = KEY_NULL; // ignore any other key // Inc key_was_autorepeat = 0; inc_time_bcd(&(new_time.yearL),1,99,0); } else if (key1_stat >= KEY_DOWNL) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0xFF; // Inc by 5 inc_time_bcd(&(new_time.yearL),5,99,0); } else if (key1_stat == KEY_RELEASE) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // start blinking again when key is released; } if (key0_stat == KEY_PRESS) { key0_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // Next Number clock_status = STAT_SET_MONTH; } else if (key0_stat == KEY_DOWNL) { key0_stat = KEY_NULL; // ignore any other key // abort time setting clock_status = STAT_NORM; } } else if (clock_status == STAT_SET_MONTH) { if (key1_stat == KEY_PRESS) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // Inc inc_time_bcd(&(new_time.monthL),1,12,1); } else if (key1_stat >= KEY_DOWNL) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0xFF; // Inc by 5 inc_time_bcd(&(new_time.monthL),5,12,1); } else if (key1_stat == KEY_RELEASE) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // start blinking again when key is released; } if (key0_stat == KEY_PRESS) { key0_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // Next clock_status = STAT_SET_DAY; } else if (key0_stat == KEY_DOWNL) { key0_stat = KEY_NULL; // ignore any other key // abort time setting clock_status = STAT_NORM; } } else if (clock_status == STAT_SET_DAY) { byte maxday; maxday = getdaysinMonth(new_time.yearL,new_time.yearH,new_time.monthL,new_time.monthH); if (key1_stat == KEY_PRESS) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // Inc inc_time_bcd(&(new_time.dayL),1,maxday,1); } else if (key1_stat >= KEY_DOWNL) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0xFF; // Inc by 5 inc_time_bcd(&(new_time.dayL),5,maxday,1); } else if (key1_stat == KEY_RELEASE) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // start blinking again when key is released; } if (key0_stat == KEY_PRESS) { key0_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // next clock_status = STAT_SET_HOUR; } else if (key0_stat == KEY_DOWNL) { key0_stat = KEY_NULL; // ignore any other key // abort time setting clock_status = STAT_NORM; } } else if (clock_status == STAT_SET_HOUR) { if (key1_stat == KEY_PRESS) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // Inc inc_time_bcd(&(new_time.hourL),1,23,0); } else if (key1_stat >= KEY_DOWNL) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0xFF; // Inc inc_time_bcd(&(new_time.hourL),5,23,0); } else if (key1_stat == KEY_RELEASE) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // start blinking again when key is released; } if (key0_stat == KEY_PRESS) { key0_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // next clock_status = STAT_SET_MIN; } else if (key0_stat == KEY_DOWNL) { key0_stat = KEY_NULL; // ignore any other key // abort time setting clock_status = STAT_NORM; } } else if (clock_status == STAT_SET_MIN) { if (key1_stat == KEY_PRESS) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // Inc inc_time_bcd(&(new_time.minL),1,59,0); } else if (key1_stat >= KEY_DOWNL) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0xFF; // Inc inc_time_bcd(&(new_time.minL),5,59,0); } else if (key1_stat == KEY_RELEASE) { key1_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // start blinking again when key is released; } if (key0_stat == KEY_PRESS) { key0_stat = KEY_NULL; // ignore any other key key_was_autorepeat = 0; // time setting finished new_time.dow = dayofweek(new_time.dayL+10*new_time.dayH,new_time.monthL+10*new_time.monthH,2000+new_time.yearL+10*new_time.yearH); time = new_time; ee_savedate(); clock_status = STAT_NORM; } else if (key0_stat == KEY_DOWNL) { key0_stat = KEY_NULL; // ignore any other key // abort time setting clock_status = STAT_NORM; time_is_set = TIME_SET; } } } } ISR(TIMER1_COMPA_vect) { // 16kHz = 66us für Vorteiler INIT_TIMER_PRESC 500 bzw. 8KHz = 133us für Vorteiler 1000; tim_leds(); if ((--prescale_20ms.wordval) < 4) { // 20ms Intervall fast erreicht: in den letzten 4 Ticks verschiedene Aufgaben abarbeiten // initialisiert wird mit PRESCALE_20MS; für 8 KHz Timer -> 160 Vorteiler = 50Hz switch (prescale_20ms.byteval[0] & 0x03) { case 3: tim_dcf(); break; case 2: tim_secs(); break; case 1: tim_keys(); break; case 0: prescale_20ms.wordval = PRESCALE_20MS; break; } } } static void wait_2sec(void) { DCF_BEGIN_RESET; byte last_rest_ctr; ledout[8] = MASK_i; ledout[9] = MASK_d; ledout[10] = MASK_n; ledout[11] = MASK_A; while(dcf_reset_ctr != 0) { // wait 2 seconds last_rest_ctr = dcf_reset_ctr; // set LEDout shift pattern byte ctr; if (last_rest_ctr < (DCF_RESET_CYCLES >> 1)) { ctr = LED_ROW_COUNT; } else { ctr = LED_ROW_COUNT - 4; } do { ctr--; ledout[ctr] = 1 << ((ctr + (last_rest_ctr >> 1)) & 0x07); } while (ctr > 0); // wait 8*20ms = 160ms while ((dcf_reset_ctr != 0) && (((dcf_reset_ctr ^ last_rest_ctr) & 0xFE ) == 0)) { // wait until 8 cylces of 20ms = 160ms are gone } } DCF_END_RESET; } int main(void) { init_leds(); init_keys(); init_dcf(); init_time(); init_timer(); sei(); wait_2sec(); while(1) { proc_dcf(); proc_status(); proc_leds(); } }