//binary clock (c) 2005 gregi //last change: 25.02.2005, 20:00 // features for now: // * display and increment current time // * set time/date via pushbuttons // * switch between date/time // * increment date (months, switching years) // features to do: // * set alarm time?! (with buzzer? PBx?) // (save to eeprom) // * boot-up-effects (self test) // io configurations, avr-libc #include #include #include //#define DEBUG 1 // Multiplex-Pins #define MPLEX_HOURS 0x04 #define MPLEX_MINUTES 0x02 #define MPLEX_SECONDS 0x01 // needed to clear all multiplex pins (every cycle) #define MPLEX_CLEAR 0xF8 //port definitions #define CLKDATA PORTD #define CLKCTRL PORTB //compatibility defines for 2313 (timer routine by peter danegger) #ifndef OCR1A #define OCR1A OCR1 // 2313 support #endif #ifndef WGM12 #define WGM12 CTC1 // 2313 support #endif #define XTAL 10000000L // nominal value #define DEBOUNCE 256L // debounce clock (256Hz = 4msec) typedef unsigned char u08; // our time structure, year could need an int, but we can't display it. typedef struct _Time { u08 seconds; u08 minutes; u08 hours; u08 day; u08 month; u08 year; } Time; // global variables u08 prescaler; // clock Time meineuhr; // display clock/date u08 mode; // set mode u08 set; // step (digit) u08 step; // release key flag u08 release; // count registers (debounce) u08 tempset; u08 tempinc; // multiplex u08 mplex_clk; //update: this function is called every second to update the clock/date void update(Time *meineuhr) { if(++meineuhr->seconds == 60) { meineuhr->seconds = 0; if(++meineuhr->minutes == 60) { meineuhr->minutes = 0; if(++meineuhr->hours == 24) { meineuhr->hours = 0; if(++meineuhr->day == 32) { meineuhr->month++; meineuhr->day = 1; } else if(meineuhr->day == 31) { if((meineuhr->month == 4 || 6 || 9 || 11)) { meineuhr->month++; meineuhr->day = 1; } } else if(meineuhr->day == 30) { if(meineuhr->month == 2) { meineuhr->month++; meineuhr->day = 1; } } else if(meineuhr->day == 29) { if((meineuhr->month == 2) && (meineuhr->year % 4)) { meineuhr->month++; meineuhr->day = 1; } } if(meineuhr->month == 13) { meineuhr->month = 1; meineuhr->year++; } } } } } #ifdef DEBUG void print(Time *meineuhr) { printf("%02i:%02i:%02i\n",meineuhr->hours, meineuhr->minutes, meineuhr->seconds); } #endif // this function sets the hour-multiplexline and the calculated (BCD) hour-databits. void OutputHours(Time *meineuhr) { u08 myhours; myhours = meineuhr->hours / 10; // tens! myhours <<= 4; myhours |= meineuhr->hours % 10; // ones #ifdef DEBUG printf("%2X\n",myhours); #endif //output to port CLKCTRL &= MPLEX_CLEAR; CLKCTRL |= MPLEX_HOURS; CLKDATA = myhours; } // this function sets the minutes-multiplexline and the calculated (BCD) minutes-databits. void OutputMinutes(Time *meineuhr) { u08 myminutes; myminutes = meineuhr->minutes / 10; //tens myminutes <<= 4; myminutes |= meineuhr->minutes % 10; //ones #ifdef DEBUG printf("%02X\n",myminutes); #endif //output to port CLKCTRL &= MPLEX_CLEAR; CLKCTRL |= MPLEX_MINUTES; CLKDATA = myminutes; } // this function sets the minutes-multiplexline and the calculated (BCD) minutes-databits. void OutputSeconds(Time *meineuhr) { u08 myseconds; myseconds = meineuhr->seconds / 10; //tens myseconds <<= 4; myseconds |= meineuhr->seconds % 10; //ones #ifdef DEBUG printf("%02X\n",myseconds); #endif //output to port CLKCTRL &= MPLEX_CLEAR; CLKCTRL |= MPLEX_SECONDS; CLKDATA = myseconds; } // this function sets the hours-multiplexline and the calculated (BCD) days-databits. void OutputDays(Time *meineuhr) { u08 mydays; mydays = meineuhr->day / 10; //tens mydays <<= 4; mydays |= meineuhr->day % 10; //ones CLKCTRL &= MPLEX_CLEAR; CLKCTRL |= MPLEX_HOURS; CLKDATA = mydays; } // this function sets the minutes-multiplexline and the calculated (BCD) months-databits. void OutputMonths(Time *meineuhr) { u08 mymonths; mymonths = meineuhr->month / 10; //tens mymonths <<= 4; mymonths |= meineuhr->month % 10; //ones CLKCTRL &= MPLEX_CLEAR; CLKCTRL |= MPLEX_MINUTES; CLKDATA = mymonths; } // this function sets the seconds-multiplexline and the calculated (BCD) years-databits. void OutputYears(Time *meineuhr) { u08 myyears; myyears = meineuhr->year / 10; //tens myyears <<= 4; myyears |= meineuhr->year % 10; //ones CLKCTRL &= MPLEX_CLEAR; CLKCTRL |= MPLEX_SECONDS; CLKDATA = myyears; } //timer compare interrupt, every 4 ms SIGNAL (SIG_OUTPUT_COMPARE1A) { #if XTAL % DEBOUNCE OCR1A = XTAL / DEBOUNCE - 1; // compare DEBOUNCE - 1 times #endif if( --prescaler == 0 ){ prescaler = (u08)DEBOUNCE; if(set != 1) update(&meineuhr); // exact one second over #if XTAL % DEBOUNCE // handle remainder OCR1A = XTAL / DEBOUNCE + XTAL % DEBOUNCE - 1; // compare once per second #endif } if(set == 1) // set mode! { switch(step) { case 1: case 2: OutputHours(&meineuhr); break; case 3: case 4: OutputMinutes(&meineuhr); break; case 5: case 6: OutputSeconds(&meineuhr); break; case 7: case 8: OutputDays(&meineuhr); break; case 9: case 10: OutputMonths(&meineuhr); break; case 11: case 12: OutputYears(&meineuhr); break; case 13: set = 0; step = 0; break; default: break; } } else //display mode { switch(mplex_clk) { case 0: (mode) ? OutputHours(&meineuhr) : OutputDays(&meineuhr); break; case 1: (mode) ? OutputMinutes(&meineuhr) : OutputMonths(&meineuhr); break; case 2: (mode) ? OutputSeconds(&meineuhr) : OutputYears(&meineuhr); break; } } mplex_clk++; if(mplex_clk == 3) mplex_clk = 0; // key debouncing and input routine if(!(PINB & (1 << PB3))) // set key pressed? { tempset++; } else { tempset = 0; //set = 0; release = 1; } if(!(PINB & (1 << PB4))) // inc key pressed? { tempinc++; } else { tempinc = 0; release = 1; } if(tempset == 25) // set key debounced and pressed { if(set && release) { step++; //next step (set!) } else { mode = ~mode; //switch between clock and date } } if(tempset == 200) // set key pressed really long (800ms) { set = 1; // we are in set-mode step = 1; release = 0; //clear time // meineuhr.hours = 0; // meineuhr.minutes = 0; // meineuhr.seconds = 0; // meineuhr.day = 0; // meineuhr.month = 0; // meineuhr.year = 0; } if(tempinc == 25) // increment key pressed { switch(step) { case 1: //hours tens if(meineuhr.hours >= 20) meineuhr.hours -= 20; else meineuhr.hours += 10; break; case 2: //hours ones if((meineuhr.hours % 10) == 9) meineuhr.hours -= 9; else meineuhr.hours++; break; case 3: //minutes tens if(meineuhr.minutes >= 50) meineuhr.minutes -= 50; else meineuhr.minutes += 10; break; case 4: //minutes ones if((meineuhr.minutes % 10) == 9) meineuhr.minutes -= 9; else meineuhr.minutes++; break; case 5: //seconds tens if(meineuhr.seconds >= 50) meineuhr.seconds -= 50; else meineuhr.seconds += 10; break; case 6: //seconds ones if((meineuhr.seconds % 10) == 9) meineuhr.seconds -= 9; else meineuhr.seconds++; break; case 7: //day tens if(meineuhr.day >= 30) meineuhr.day -= 30; else meineuhr.day += 10; break; case 8: //day ones if((meineuhr.day % 10) == 9) meineuhr.day -= 9; else meineuhr.day++; break; case 9: //month tens if(meineuhr.month >= 10) meineuhr.month -= 10; else meineuhr.month += 10; break; case 10: //month ones if((meineuhr.month % 10) == 9) meineuhr.month -= 9; else meineuhr.month++; break; case 11: //year tens if(meineuhr.year >= 70) meineuhr.year -= 70; else meineuhr.year += 10; break; case 12: // year ones if((meineuhr.year % 10) == 9) meineuhr.year -= 9; else meineuhr.year++; break; default: break; } } } void Init(void) { /* port configuration */ DDRD = 0xFF; DDRB = 0x07; PORTB = 0xFF; //pullup resistors /* timer 1 config */ TCCR1B = 1<