/********************************************* This program was produced by the CodeWizardAVR V1.24.0 Standard Automatic Program Generator © Copyright 1998-2003 HP InfoTech s.r.l. http://www.hpinfotech.ro e-mail:office@hpinfotech.ro Project : Version : Date : 12/26/2003 Author : Theodore Johnson Company : NY, USA Comments: Chip type : ATmega163 Program type : Application Clock frequency : 8.000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 256 *********************************************/ #include #include // DS1302 Real Time Clock functions #asm .equ __ds1302_port=0x18 .equ __ds1302_io=1 .equ __ds1302_sclk=0 .equ __ds1302_rst=2 #endasm #include #include #define CLOCK_5821 PORTB.5 #define DATA_5821 PORTB.4 #define STROBE_5821 PORTB.3 #define LIGHTR PORTB.7 #define LIGHTL PORTB.6 #define COLON PORTD.3 #define DIGITL0 PORTC.0 #define DIGITL1 PORTC.1 #define DIGITL2 PORTC.2 #define DIGITL3 PORTC.3 #define DIGITR0 PORTC.4 #define DIGITR1 PORTC.5 #define DIGITR2 PORTC.6 #define DIGITR3 PORTC.7 #define DIGITS PORTC #define BTN_CHANGE PINA.0 #define BTN_UP PINA.1 #define BTN_DOWN PINA.2 #define BTN_SET PINA.3 #define BTN_ALARM PINA.4 #define BTN_CHIME PINA.5 #define CHIME PORTD.6 #define H10_L 1 #define H_LDP 4 #define M_LDP 8 #define H_RDP 16 #define M_RDP 32 #define LEFT 0 #define RIGHT 1 // Timer 0 overflow interrupt service routine // interrupt every 4 ms char ovf0 = 0; interrupt [TIM0_OVF] void timer0_ovf_isr(void) { ovf0++; TCNT0=128; } unsigned char button_pressed(unsigned char b, unsigned char *s){ unsigned char retval; if(b == 1 && *s == 0) retval = 1; else retval = 0; *s = ((*s) << 1) + b; return(retval); } unsigned char button_filt(unsigned char b, unsigned char *s){ *s = ((*s) << 1) + b; return((*s) == 0xff); } ///////////////////////////////////////////////////// /// Load the display shift register. void init_5821(){ CLOCK_5821 = 0; DATA_5821 = 0; STROBE_5821 = 0; } void load_5821(char c){ char i=128; while(i>0){ if(i&c) DATA_5821=1; else DATA_5821=0; CLOCK_5821 = 1; i=i >> 1; CLOCK_5821=0; } STROBE_5821=1; DATA_5821=0; STROBE_5821=0; } /////////////////////////////////////////////////////// /// Set Display void set_display(char hrs, char mins, char dps, char lr){ char digits = 0; char dots = 0; if(lr == LEFT){ digits = (mins / 10) << 4; if((hrs/10) > 0) dots += H10_L; if(dps & 0x01) dots += H_LDP; if(dps & 0x02) dots += H_RDP; if(dps & 0x10) dots += M_LDP; if(dps & 0x20) dots += M_RDP; }else{ digits = ((mins % 10) << 4) + hrs % 10; if(dps & 0x04) dots += H_LDP; if(dps & 0x08) dots += H_RDP; if(dps & 0x40) dots += M_LDP; if(dps & 0x80) dots += M_RDP; } PORTC = digits; load_5821(dots); } unsigned char h; unsigned char m; unsigned char s; void main(void){ char lightside = 0; char serdat = 1; char dispchar = 0; char btn=0; char colon = 0; char iter = 0; unsigned int bell_cnt = 0; char bell_iter = 0; char ring_type = 0; char btn_up = 0, btn_down = 0, btn_change = 0; char btn_set = 0, btn_alarm = 0, btn_chime = 0; char set_ptr = 0; char disph=0, dispm=0, alarmh=0,alarmm=0; char lasth=0, lastm=0, lh=0, lm=0; char chime_trig = 0, fade_trigger = 0; char fade_level = 0; char alarm_on = 0, alarm_set = 0, set_set = 0; // Input/Output Ports initialization // Port A initialization // Func0=In Func1=In Func2=In Func3=In Func4=In Func5=In Func6=In Func7=In // State0=T State1=T State2=T State3=T State4=T State5=T State6=T State7=T PORTA=0x00; DDRA=0x00; // Port B initialization // Func0=Out Func1=In Func2=Out Func3=Out Func4=Out Func5=Out Func6=Out Func7=Out // State0=0 State1=T State2=0 State3=0 State4=0 State5=0 State6=0 State7=0 PORTB=0x00; DDRB=0xFD; // Port C initialization // Func0=Out Func1=Out Func2=Out Func3=Out Func4=Out Func5=Out Func6=Out Func7=Out // State0=0 State1=0 State2=0 State3=0 State4=0 State5=0 State6=0 State7=0 PORTC=0x00; DDRC=0xFF; // Port D initialization // Func0=In Func1=In Func2=In Func3=Out Func4=In Func5=In Func6=Out Func7=In // State0=T State1=T State2=T State3=T State4=T State5=T State6=0 State7=T PORTD=0x00; DDRD=0x48; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 125.000 kHz TCCR0=0x03; TCNT0=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: Timer 1 Stopped // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // External Interrupt(s) initialization // INT0: Off // INT1: Off GIMSK=0x00; MCUCR=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x01; UBRRHI=0x00; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off // Analog Comparator Output: Off ACSR=0x80; SFIOR=0x00; ////////////////////////////////////////////////////// // Initialize rtc_init(1,1,1); LIGHTR = 0; LIGHTL = 0; CHIME = 1; COLON = 0; init_5821(); load_5821(0); rtc_get_time(&h,&m,&s); // the 1302 can get stuck in an invalid state if(s>59){ rtc_set_time(h,m,0); } lasth=h; lastm=m; // Restore the alarm from the last setting alarmh = ds1302_read(0); if(alarmh>23){ alarmh=0; ds1302_write(0,alarmh); } alarmm = ds1302_read(1); if(alarmm > 59){ alarmm=0; ds1302_write(1,alarmm); } // Global enable interrupts #asm("sei") /////////////////////////////////////////////////////// // Main loop while (1){ // wait for heartbeat (once every 4 ms) while(!ovf0); ovf0 = 0; iter++; // set chime and fade triggers. // (avoid double triggering) if(s>30){ chime_trig = 1; fade_trigger = 1; } // Trigger the chime // the IDS1110 can only record one sound. // I recorded a ding-dong. // the ding takes 900 ms, the ding-dong 1800 ms if(button_filt(BTN_CHIME,&btn_chime)){ if(s == 0 && chime_trig && bell_iter == 0 && (m%15) == 0){ switch(m){ case 0: ring_type = 2; bell_cnt = 1800; bell_iter = 1; break; default: ring_type = 1; bell_cnt = 900; bell_iter = m/15; break; } chime_trig = 0; } } alarm_set = button_filt(BTN_ALARM,&btn_alarm); // trigger the alarm (or turn it off) if(alarm_set){ if(s == 0 && chime_trig && m == alarmm && h == alarmh){ ring_type = 2; bell_cnt = 1800; bell_iter = 10; alarm_on = 1; chime_trig = 0; } }else{ if(alarm_on){ alarm_on = 0; bell_iter = 0; } } // Process the chimes if(bell_iter > 0){ bell_cnt--; // If there are multiple chimes, // the IDS1110 needs a period where the NOT_PLAY // signal is high to reset itsels. if(bell_cnt < 50) CHIME=1; else CHIME=0; if(bell_cnt == 0){ bell_iter--; if(ring_type == 1) bell_cnt = 900; else bell_cnt = 1800; } }else{ CHIME=1; alarm_on = 0; } // Once every 10 iters, sample the time, switch the lit side if(iter>=10){ lasth=h; lastm=m; rtc_get_time(&h,&m,&s); // fade processing - trigger a fade. if(s == 0 && fade_trigger && lastm!=m){ lh=lasth; lm=lastm; fade_level = 100; fade_trigger = 0; } if(fade_level > 0) fade_level--; lightside = 1-lightside; LIGHTR = 0; LIGHTL = 0; } serdat = 0; disph = h; dispm = m; // Setting the time / alarm set_set = button_filt(BTN_SET,&btn_set); if(set_set){ if(alarm_set){ disph = alarmh; dispm = alarmm; } if(button_pressed(BTN_CHANGE,&btn_change)){ set_ptr++; if(set_ptr > 1) set_ptr = 0; } if(set_ptr == 0) serdat |= 0x0a; else serdat |= 0xa0; if(button_pressed(BTN_UP,&btn_up)){ switch(set_ptr){ case 0: disph++; if(disph>23) disph=0; break; case 1: dispm++; if(dispm>59) dispm=0; break; } if(alarm_set){ alarmh=disph; alarmm=dispm; ds1302_write(0,alarmh); ds1302_write(1,alarmm); }else{ rtc_set_time(disph,dispm,s); } } if(button_pressed(BTN_DOWN,&btn_down)){ switch(set_ptr){ case 0: if(disph>0) disph--; else disph=23; break; case 1: if(dispm>0) dispm--; else dispm=59; break; } if(alarm_set){ alarmh=disph; alarmm=dispm; ds1302_write(0,alarmh); ds1302_write(1,alarmm); }else{ rtc_set_time(disph,dispm,s); } } }else{ // Just display the time + fade processing // keep btn state fresh. button_pressed(BTN_DOWN,&btn_down); button_pressed(BTN_UP,&btn_up); set_ptr = 0; } // do the fade. ten levels. if(!set_set && (10*iter)12){ disph = disph-12; serdat |= 1; }else{ if(disph==0) disph = 12; } if(s&1 || (set_set && alarm_set)) COLON=1; else COLON=0; set_display(disph,dispm, serdat, lightside); if(iter>=10){ if(lightside == LEFT) LIGHTL = 1; else LIGHTR = 1; iter=0; } } }