/****************************************************************************** Title: Wecker Author: Fritz Ganter Date: March 2004 Software: AVR-GCC 3.4.0 Hardware: Tested with ATmega16 at 8 Mhz Description: Universal Wecker/Timer zum Kochen usw. $Log: wecker.c,v $ Revision 1.58 2004/05/07 02:27:31 ganter works fine.. Revision 1.57 2004/05/06 03:14:56 ganter accu charger implemented, testing... Revision 1.56 2004/05/04 06:10:37 ganter ... Revision 1.55 2004/05/02 20:56:43 ganter PWM now works fine with hardware. LCD-Light output pin is now Pin 18 on the Mega16 (OCR1B/PD4). Revision 1.54 2004/05/02 09:13:32 ganter will change to hardware PWM Revision 1.53 2004/05/02 05:20:26 ganter problems of lost interrupts? Revision 1.52 2004/04/30 17:04:28 ganter works fine Revision 1.51 2004/04/29 15:12:41 ganter flicker is away Revision 1.50 2004/04/29 14:35:44 ganter display flickers when light is on Revision 1.49 2004/04/29 01:37:44 ganter added dimmer for backlight Revision 1.48 2004/04/28 04:22:13 ganter some cosmetic changes, works fine min/max temperature is also stored in eeprom Revision 1.47 2004/04/27 23:14:06 ganter removed floating point support from printf, saves flash memory Revision 1.46 2004/04/27 22:49:32 ganter 2 Alarms works fine Revision 1.45 2004/04/27 16:44:00 ganter ... Revision 1.44 2004/04/27 16:43:02 ganter powersave now only needs about 0.7mA Revision 1.43 2004/04/27 16:14:38 ganter working on Temperature sensor powersave Revision 1.42 2004/04/26 01:05:10 ganter all seems to work with atmega16 PCB Revision 1.41 2004/04/25 16:58:04 ganter ... Revision 1.40 2004/04/25 16:21:23 ganter atmega16 version Revision 1.39 2004/04/14 08:49:39 ganter delayms now uses sleep_mode for reducing power consumption Revision 1.38 2004/04/06 10:38:44 ganter added temperature alarm Revision 1.37 2004/04/05 11:42:55 ganter works fine Revision 1.36 2004/04/01 12:35:17 ganter temp works fine Revision 1.35 2004/04/01 09:38:59 ganter ... Revision 1.34 2004/03/31 15:54:29 ganter temp works but is in a long delay Revision 1.33 2004/03/31 15:25:41 ganter added temperature display Revision 1.32 2004/03/30 01:22:46 ganter key "9" now switches on the powersaver Revision 1.31 2004/03/29 23:01:13 ganter reduced timer period from 1/1024sec to 1/128 sec Revision 1.30 2004/03/29 01:57:58 ganter with external oszillator, beep enabled with PORTD1 Revision 1.29 2004/03/29 01:20:45 ganter before ext. oszillator for sound Revision 1.28 2004/03/28 21:33:28 ganter ... Revision 1.27 2004/03/26 20:57:48 ganter reduced code size for eeprom handling Revision 1.26 2004/03/26 12:36:43 ganter store and restore time and alarm after reset Revision 1.25 2004/03/25 03:39:11 ganter added display off switch with powers off display Revision 1.24 2004/03/24 19:24:48 ganter ... Revision 1.23 2004/03/24 04:44:13 ganter added watchdog again Revision 1.22 2004/03/23 23:34:33 ganter looks good with 8MHz internal clock and 32768Hz crystal programed fuses: CKOPT SUT0 CKSEL3 CKSEL1 CKSEL0 Revision 1.21 2004/03/23 15:41:18 ganter ... Revision 1.20 2004/03/23 04:50:51 ganter added date into title Revision 1.19 2004/03/23 04:46:09 ganter ... Revision 1.18 2004/03/23 04:44:30 ganter switch with "*" between alarmtime and time-left Revision 1.17 2004/03/22 23:37:40 ganter ... Revision 1.16 2004/03/22 20:53:56 ganter now with 32.768kHz crystal on OSC1/OSC2 input Revision 1.15 2004/03/22 03:00:45 ganter support for timer1 and timer2 Revision 1.14 2004/03/22 00:28:16 ganter before rewrite of readkeyboard Revision 1.13 2004/03/21 18:00:37 ganter ... Revision 1.12 2004/03/21 14:57:21 ganter call readkeyboard less often Revision 1.11 2004/03/21 13:25:59 ganter playing on delay Revision 1.10 2004/03/21 13:09:20 ganter removed uhrzent Revision 1.9 2004/03/21 00:43:03 ganter added delayms(ms), delays ms miliseconds Revision 1.8 2004/03/20 22:47:34 ganter added revision Revision 1.7 2004/03/20 22:45:18 ganter ... Revision 1.6 2004/03/20 22:40:36 ganter ... Revision 1.5 2004/03/19 21:56:17 ganter timer und uhrzeitmode für wecker funktionieren Revision 1.4 2004/03/18 22:16:47 ganter wecker tut über Tastatur Revision 1.3 2004/03/17 19:34:16 ganter vor tastatur Revision 1.2 2004/03/17 04:37:30 ganter ... Revision 1.1 2004/03/16 22:13:33 ganter ... $Date: 2004/05/07 02:27:31 $ $Revision: 1.58 $ *******************************************************************************/ #include #include #include #include #include #include "lcd.h" #include #include #include #include #include #include #include /* ** constant definitions */ /* real xtal frequency * 1000 */ #define XTALREALFREQ 32767052 #define XTALFREQ 32768000 #define XTALFREQ2 32768 #define ESECT __attribute__((section(".eeprom"))) #define ENABLESCREENSAVER #define MAXASEC 300 /* delay in seconds to switch screensaver on */ #define SCREENSAVER 30 #define SCREENSAVERMIN 600 #define VCORR 1.02373 #define MAXLIGHT 512 #define USEREVISION void delay (uint16_t us); void uhr (void); void okbeep (void); void getinput (char t); void delayms (uint16_t ms); void clrscr (void); void power_lcd (char on); void wake_lcd (void); void save_uhr (void); void calc_weck (void); int16_t THERMO_GetTemp (void); void messbat (void); void lcdlight (void); void dosleep (void); void startladen (void); /* ** module global variables */ static volatile uint16_t asec = 0, savercnt; static volatile uint8_t alarmed, talarmed, tempalarmed, uhrsek, uhrmin, uhrstund, uhrneu, key, oldkey, keyreleased; volatile uint8_t dispon = 1, needto_save_uhr = 0; static volatile int32_t restzeit, gesamtzeit, oldrestzeit; char text[40], uhrzeit[10], doppelpunkt[2], tenable = 0, lastline[20]; uint16_t runcount; static uint16_t weckstund, weckmin; int8_t weckdisplay = 0, tempmax = 100, tempmin = 0; int8_t tstund = 8, tmin = 0; static volatile uint8_t pwm, dimmflag = 0, int0event = 0, laden = 0, habenfertig = 0, ladenendflag; static volatile uint8_t beeped = 0, lc; static volatile int16_t milliseconds = 0; static volatile uint16_t light, xtalcorr; static volatile uint32_t xtalcorrcount; static int16_t maxvolt = 0; static int16_t zeit = 0, lastzeit = 0; uint8_t i_stund ESECT = 0xFF; uint8_t i_min ESECT = 0xFF; int32_t i_gesamtzeit ESECT = 0xFFFF; int32_t i_restzeit ESECT = 0xFFFF; uint8_t t_stund ESECT = 8; uint8_t t_min ESECT = 0; uint8_t t_enable ESECT = 1; uint8_t i_tempmax ESECT = 70; uint8_t i_tempmin ESECT = 4; int16_t waitcount = 0; float battvoltage = 0.0; const char ich[] PROGMEM = "\n(c)Fritz Ganter "; const char resetstr[] PROGMEM = "\n ** RESET!!! ** "; const char temphialarmstr[] PROGMEM = " Zu heiss! "; const char templowalarmstr[] PROGMEM = " Zu kalt! "; const char leerstr[] PROGMEM = " "; const char normalstr[] PROGMEM = "1,3:Timer 2:Zeit"; const char battstr[] PROGMEM = " Batt. wechseln!"; const char powersavestr[] PROGMEM = " Stromsparmodus "; const char alarmstr[] PROGMEM = " *** ALARM *** "; const char ladenstr[] PROGMEM = "Akku laden "; const char akkuvollstr[] PROGMEM = "Akku voll "; const char inp_leerstr[] PROGMEM = " "; const char inp_taglstr[] PROGMEM = " täglich"; const char missedstr[] PROGMEM = " * versäumt * "; const char int0str[] PROGMEM = "INT0 aufgetreten"; const char stoppedstr[] PROGMEM = " Alarm\n beendet"; const char inp_timerstr[] PROGMEM = "Timer stellen\nhhmm"; const char inp_kurztimerstr[] PROGMEM = "Kurztimer stell.\nmmss"; const char inp_uhrstr[] PROGMEM = "Uhrzeit stellen\nhhmm"; const char inp_tempstr[] PROGMEM = "Min./max. Temp.?\n"; const char inp2_stellstr[] PROGMEM = "Weckzeit stellen\nhhmm *=täglich"; const char uhr_stellstr[] PROGMEM = "\"8\" drücken!\n"; const char notokstr[] PROGMEM = "Falsche Eingabe!"; #ifdef USEREVISION char rev[] = "$Revision: 1.58 $"; char revdate[] = "$Date: 2004/05/07 02:27:31 $"; #endif extern int16_t TemperaturAlt; /* ** functions */ int readkeyboard (void) { uint8_t t; static uint8_t releasedcounter = 0; #define MAXRELEASE 8 #define KEYWAIT 10 /* Eingänge PORTB1=7 B2=6 B3=5 D2=4 Ausgänge B0=3 D6=2 D5=1 */ /* port B 1-3 Ausgänge */ /* port B 4-7 Eingänge */ key = ' '; /* setze Ausgänge auf 0 */ PORTB &= ~_BV (2); PORTB &= ~_BV (3); /* setzte T1 auf 1 */ PORTB |= _BV (1); delay (KEYWAIT); t = PINB; if (t & _BV (4)) key = '1'; else if (t & _BV (5)) key = '4'; else if (t & _BV (6)) key = '7'; else if (t & _BV (7)) key = '*'; delay (KEYWAIT); /* 2.Reihe setze Ausgänge auf 0 */ /* setze Ausgänge auf 0 */ PORTB &= ~_BV (1); PORTB &= ~_BV (3); /* setzte T2 auf 1 */ PORTB |= _BV (2); delay (KEYWAIT); t = PINB; if (t & _BV (4)) key = '2'; else if (t & _BV (5)) key = '5'; else if (t & _BV (6)) key = '8'; else if (t & _BV (7)) key = '0'; delay (KEYWAIT); /* 3.Reihe setze Ausgänge auf 0 */ PORTB &= ~_BV (1); PORTB &= ~_BV (2); /* setzte T2 auf 1 */ PORTB |= _BV (3); delay (KEYWAIT); t = PINB; if (t & _BV (4)) key = '3'; else if (t & _BV (5)) key = '6'; else if (t & _BV (6)) key = '9'; else if (t & _BV (7)) key = '#'; /* alles aus */ PORTB &= ~(_BV (1) | _BV (2) | _BV (3)); if (key != oldkey) { uhrneu = 1; oldkey = key; if (key != ' ') { beeped = 2; if (light || pwm) lcdlight (); } } if (key == ' ') { if (releasedcounter < MAXRELEASE) releasedcounter++; else keyreleased = 1; } else { releasedcounter = 0; keyreleased = 0; } return 1; } void uhr () { uhrsek++; asec++; #ifdef ENABLESCREENSAVER savercnt++; #endif if (uhrsek >= 60) { uhrmin++; uhrsek -= 60; if (uhrmin >= 60) { runcount++; uhrmin = 0; uhrstund++; if (uhrstund >= 24) uhrstund = 0; } if ((uhrmin == 0) || (uhrmin == 30)) needto_save_uhr = 1; } uhrneu = 1; } SIGNAL (SIG_INTERRUPT0) { GICR &= ~_BV (INT0); int0event = 1; beeped = 2; } /* alle 1/128s */ /* handler for Output Compare 2interrupt */ SIGNAL (SIG_OUTPUT_COMPARE2) { /* if (lc & 1) */ /* sbi (PORTD, 3); */ /* else */ /* cbi (PORTD, 3); */ milliseconds -= 8; /* portd, 0 ist quitscherl-enable */ if (beeped != 0) { sbi (PORTD, 0); beeped--; if (beeped == 0) cbi (PORTD, 0); } if (light) { light--; TCNT1 = 0x0000; if (light == 0) { set_sleep_mode (SLEEP_MODE_IDLE); // TIMSK |= _BV (OCIE1B); dimmflag = 1; pwm = 255; // beeped = 2; } } if (pwm) { pwm--; OCR1BL = 255 - pwm; if (pwm == 0) { // beeped = 2; set_sleep_mode (SLEEP_MODE_PWR_SAVE); dimmflag = 0; } } lc++; readkeyboard (); if (lc < 128) return; wdt_reset (); lc = 0; uhr (); xtalcorrcount++; if (xtalcorrcount >= 1280000) { int16_t x; beeped=2; x = xtalcorr; while (x >= 128) { uhr (); x -= 128; } lc = x; xtalcorrcount=0; } if (restzeit <= 1) restzeit = 0; else restzeit--; } void okbeep () { beeped = 12; delayms (150); beeped = 12; } void waitkeyrelease (void) { while (!keyreleased) dosleep (); } void getinput (char t) { int i; char str[10], timermode, savetimermode, shorttimer, saveshorttimer, tmode = 0; int32_t gs, uu; timermode = 0; shorttimer = 0; do { gs = uu = i = 0; strcpy (str, "hhmm"); clrscr (); if (t == 2) { /* Uhr stellen */ strcpy_P (text, inp_uhrstr); lcd_puts (text); waitkeyrelease (); while (!isdigit (key)) dosleep (); } if (t == 3) { /* Temperatur stellen */ strcpy_P (text, inp_tempstr); lcd_puts (text); strcpy (str, "ccHH"); waitkeyrelease (); while (!isdigit (key)) dosleep (); } /* Alarm stellen */ /* keys: 1.. Time hhmm 2.. Uhrzeit 3.. Kurztimer mmss */ if (t == 1) { if ((key == '1') || (key == '3')) timermode = 1; if (key == '3') shorttimer = 1; if (shorttimer == 1) strcpy (str, "mmss"); savetimermode = timermode; saveshorttimer = shorttimer; if (key == '1') strcpy_P (text, inp_timerstr); if (key == '3') strcpy_P (text, inp_kurztimerstr); if (key == '2') strcpy_P (text, inp2_stellstr); lcd_puts (text); waitkeyrelease (); while (key == ' ') dosleep (); } do { if (isdigit (key)) { str[i++] = key; /* str[i] = 0; */ /* clrscr (); if ((t == 1) && timermode) strcpy_P (text, inp_timerstr); if ((t == 2) || (!timermode)) strcpy_P (text, inp_uhrstr); if (t == 3) strcpy_P (text, inp_tempstr); lcd_puts (text); */ if ((i == 1) && (!tmode)) { lcd_gotoxy (4, 1); strcpy_P (text, inp_leerstr); lcd_puts (text); } lcd_gotoxy (0, 1); lcd_puts (str); } else if (key == '*') { tmode = 1; lcd_gotoxy (4, 1); strcpy_P (text, inp_taglstr); lcd_puts (text); } else i = 10; /* warten auf tastenrelease */ waitkeyrelease (); if (i < 4) while (key == ' ') dosleep (); } while (i < 4); if (i != 10) { /* alarm stellen */ if (t == 1) { if (timermode) { if (!shorttimer) { uu = atoi (str + 2); str[2] = 0; uu = uu + 60l * atoi (str); gesamtzeit = restzeit = uu * 60l; } else { uu = atoi (str + 2); str[2] = 0; uu = uu + 60l * atoi (str); gesamtzeit = restzeit = uu; } calc_weck (); okbeep (); alarmed = 0; weckdisplay = 0; } else { /* weckzeit stellen */ uint16_t ws, wm; wm = i = atoi (str + 2); if (i < 60) { str[2] = 0; ws = atoi (str); if (ws < 24) { i = i + 60 * atoi (str); gs = i * 60l; uu = uhrsek + 60l * uhrmin + 3600l * uhrstund; gs = gs - uu; if (gs < 0) gs += 86400l; if (tmode) { tstund = ws; tmin = wm; talarmed = 0; tenable = 1; } else { restzeit = gesamtzeit = gs; i = alarmed = 0; weckstund = ws; weckmin = wm; } okbeep (); i = 0; weckdisplay = 1; } else i = 10; } else i = 10; } if (i != 10) needto_save_uhr = 1; /* fertig und countdown starten */ } /* uhr stellen */ if (t == 2) { i = atoi (str + 2); if (i < 60) { uhrmin = i; str[2] = 0; i = atoi (str); if (i < 24) { uhrstund = i; uhrsek = 0; doppelpunkt[0] = ':'; lc = 0; uhr (); okbeep (); calc_weck (); needto_save_uhr = 1; i = 0; } else i = 10; } else i = 10; } /* temperatur stellen */ if (t == 3) { tempmax = 2 * atoi (str + 2); str[2] = 0; tempmin = 2 * atoi (str); i = 0; } } if (i == 10) { strcpy_P (text, notokstr); clrscr (); lcd_puts (text); /* beep for 1 sek */ beeped = 128; for (i = 0; i < 1000; i++) delay (1000); i = 10; } /* warten auf tastenrelease */ waitkeyrelease (); timermode = savetimermode; shorttimer = saveshorttimer; } while (i == 10); clrscr (); /* strcpy_P (text, normalstr); */ /* lcd_puts (text); */ } void save_uhr (void) { milliseconds = 5000; beeped = 128; wdt_reset (); eeprom_write_byte (&i_stund, uhrstund); asm volatile (" nop"); eeprom_write_byte (&i_min, uhrmin); eeprom_write_byte (&t_stund, tstund); asm volatile (" nop"); eeprom_write_byte (&t_min, tmin); eeprom_write_byte (&t_enable, tenable); asm volatile (" nop"); eeprom_write_byte (&i_tempmax, tempmax); eeprom_write_byte (&i_tempmin, tempmin); asm volatile (" nop"); eeprom_write_block (&gesamtzeit, &i_gesamtzeit, sizeof (gesamtzeit)); asm volatile (" nop"); eeprom_write_block (&restzeit, &i_restzeit, sizeof (restzeit)); beeped = 2; } void delayms (uint16_t ms) { milliseconds = ms; while (milliseconds > 0) dosleep (); } void clrscr () { lcd_gotoxy (0, 0); lcd_clrscr (); } void power_lcd (char on) { /* portd 7 ist lcd ein/aus */ if (!on) { /* LCD ausschalten */ lcd_command (LCD_DISP_OFF); DDRD &= ~_BV (7); PORTD &= ~_BV (7); LCD_PORT = 0; LCD_E_PORT &= ~_BV (LCD_E_PIN); } else { /* LCD einschalten */ DDRD |= _BV (7); PORTD |= _BV (7); lcd_init (LCD_DISP_ON); lcd_command (LCD_DISP_ON); if (savercnt >= SCREENSAVER) strcpy_P (lastline, powersavestr); /* else */ /* { */ /* strcpy_P (lastline, normalstr); */ /* } */ } } void wake_lcd (void) { savercnt = 0 - SCREENSAVERMIN; if (!dispon) { dispon = 1; power_lcd (dispon); } } void lcdlight (void) { if (laden) return; OCR1BL = 0; light = MAXLIGHT; pwm = 0; } void dosleep (void) { cbi (PORTD, 3); sleep_mode (); sbi (PORTD, 3); } void messbat (void) { char i; uint16_t volt; static uint16_t bm[5] = { 0, 0, 0, 0, 0 }; static uint8_t bmcount = 0; // ADCSRA = _BV (ADEN) | _BV (ADPS1) | _BV (ADPS2); // ADMUX = _BV (REFS0) | _BV (REFS1); delay (10); volt = 0; for (i = 0; i < 50; i++) { ADCSRA |= _BV (ADSC); loop_until_bit_is_set (ADCSRA, ADIF); volt += ADCW; } bm[bmcount++] = volt / i; if (bmcount >= 5) bmcount = 0; volt = 0; for (i = 0; i < 5; i++) volt += bm[bmcount]; battvoltage = 5.12 * (volt) / (VCORR * i * 1024.0); /* disable ADC for power saving */ // ADCSRA = ~_BV (ADEN); } void calc_weck (void) { weckstund = uhrstund + gesamtzeit / 3600; weckmin = (uhrmin + (gesamtzeit / 60) % 60); while (weckmin >= 60) { weckmin -= 60; weckstund++; } while (weckstund >= 24) weckstund -= 24; } /* Laderoutine für 2 NiMH Zellen */ void do_laden (void) { char t[6], t2[6]; static int16_t batt; if (!ladenendflag) { messbat (); strcpy_P (text, ladenstr); batt = battvoltage * 100; itoa (batt, t, 10); t2[0] = t[0]; t2[1] = '.'; t2[2] = t[1]; t2[3] = t[2]; t2[4] = 0; zeit++; lastzeit++; /* batt ist jetzt Millivolt! */ batt = battvoltage * 1000.0; /* Teste nach mind. 10 Sekunden, Batteriespannung muss größer als 2.5V sein */ if ((batt > maxvolt) && (zeit > 10) && (batt > 2.5)) { maxvolt = batt; lastzeit = 0; } sprintf (lastline, "%d %3d %4d %4d ", habenfertig, lastzeit, maxvolt, batt); /* Ladeende: kein Spannungsanstieg für STEIGTIME sekunden */ #define STEIGTIME 4*60 if (lastzeit > STEIGTIME) ladenendflag = 1; /* Ladeende: Spannung sinkt um DUDT mV */ #define DUDT 15 if ((batt < (maxvolt - DUDT)) && (zeit > 20)) ladenendflag = 1; /* Not-Ladeende: 4 Stunden geladen */ if (zeit >= 14400) ladenendflag = 1; if (ladenendflag) { okbeep (); habenfertig = 1; PORTA &= ~_BV (6); /* beleuchtung aus */ // OCR1BL = 255; // set_sleep_mode (SLEEP_MODE_PWR_SAVE); } } else { // strcpy_P (text, akkuvollstr); // sprintf (lastline, "%s%3dmin", text, zeit / 60); sprintf (lastline, "max%4d %4d %3d", maxvolt, batt, zeit); } } void startladen (void) { laden = 1; maxvolt = 0; zeit = 0; lastzeit = 0; ladenendflag = 0; PORTA |= _BV (6); } /* 1: Timer, zählt countdown runter, Auswahl: Stunden und Minuten 2: Zeit, weckt bei der eingestellten Uhrzeit 3: Kurz, Kurzzeittimer, mit Minuten und Sekundenauswahl */ int main (void) { char text2[33]; char alarmmissed = 0; /* ADC */ ADCSRA = _BV (ADEN) | _BV (ADPS1) | _BV (ADPS2); ADMUX = _BV (REFS0) | _BV (REFS1); uhrsek = 0; uhrneu = 1; laden = 0; ladenendflag = 0; uhrstund = eeprom_read_byte (&i_stund); uhrmin = eeprom_read_byte (&i_min); strcpy (doppelpunkt, "?"); /* setup 8bit counter2, clock from 32768Hz quartz*/ TIMSK = 0; sbi (ASSR, AS2); /* auf 1/128 sek. */ TCCR2 = _BV (CS22) | _BV (CS21) | _BV (WGM21); /* OCR2 = ((XTAL /64/ 1000) - 1); */ OCR2 = 0; TIMSK = _BV (OCIE2); /* setup 8bit counter0 */ /* TCCR0 = _BV (CS01) | _BV (CS00) | _BV (WGM01); */ /* OCR0 = 2; */ TCCR1A = _BV (WGM10) | _BV (COM1B1) | _BV (COM1B0); TCCR1B = _BV (CS11) | _BV (CS10) | _BV (WGM12); OCR1BH = 0; /* beleuchtung aus */ OCR1BL = 255; pwm = 0; light = 0; set_sleep_mode (SLEEP_MODE_PWR_SAVE); /* Tastatur: */ /* port B 1-3 Ausgänge */ /* port B 4-7 Eingänge */ DDRB = _BV (1) | _BV (2) | _BV (3); PORTB = 0x0; DDRA = _BV (5) | _BV (6); PORTA = 0; /* D2 WAR Eingang Taste, D7 Ausgang Summer, D5 und D6 Ausgang Tastatur */ /* d4 ist PWM für Licht */ DDRD = _BV (7) | _BV (6) | _BV (5) | _BV (4) | _BV (1) | _BV (0) | _BV (3); PORTD = _BV (7) | _BV (3) | _BV (2); /* while (1) */ /* asm volatile (" nop"); */ sei (); /* enable interrupts */ /* put string to display (line 1) with linefeed */ #ifdef USEREVISION strcpy (text2, (rev + 11)); text2[strlen (text2) - 1] = 0; strcpy (text, (revdate + 7)); text[10] = 0; strcat (text2, text); #else strcpy (text2, ""); #endif if (uhrstund == 0xff) strcpy_P (text, ich); else strcpy_P (text, resetstr); strcat (text2, text); /* clear display and home cursor */ lcd_init (LCD_DISP_ON); /* DDRB = 0x31; PORTB = 0x31; */ lcd_clrscr (); lcd_puts (text2); THERMO_GetTemp (); delayms (1000); okbeep (); oldrestzeit = 0; talarmed = 1; alarmed = 1; gesamtzeit = restzeit = 0; /* Abweichung in 1/128s Ticks nach 10000 Sekunden */ xtalcorr = (1280 * (XTALFREQ - XTALREALFREQ) / XTALFREQ2); xtalcorrcount = 0; /* for (i=0;i<=20;i++) */ /* { */ /* lcd_clrscr (); */ /* sprintf(text,"%d:_%c_ ",i,(char)i); */ /* lcd_puts(text); */ /* delayms (1000); */ /* } */ /* nicht stellen, wenn aus reset */ if (uhrstund == 0xff) { /* Zeit stellen */ getinput (2); } else { /* komme aus reset */ okbeep (); okbeep (); okbeep (); eeprom_read_block (&restzeit, &i_restzeit, sizeof (restzeit)); eeprom_read_block (&gesamtzeit, &i_gesamtzeit, sizeof (gesamtzeit)); if (restzeit < 0) gesamtzeit = restzeit = 0; else calc_weck (); weckdisplay = 1; tstund = eeprom_read_byte (&t_stund); tmin = eeprom_read_byte (&t_min); tenable = eeprom_read_byte (&t_enable); tempmin = eeprom_read_byte (&i_tempmin); tempmax = eeprom_read_byte (&i_tempmax); clrscr (); if (restzeit > 0) alarmed = 0; strcpy_P (text, uhr_stellstr); lcd_puts (text); } /* test */ alarmed = 1; gesamtzeit = restzeit = 0; /* wdt_enable (WDTO_2S); */ wdt_reset (); messbat (); messbat (); messbat (); messbat (); messbat (); messbat (); messbat (); /* Interrupt 0 enablen, reagiert auf positive Flanke */ MCUCSR = _BV (ISC00) | _BV (ISC01); savercnt = 0 - SCREENSAVERMIN; /* Hauptschleife */ for (;;) { /* portd 3 ist debug pin, low während sleep */ dosleep (); GICR |= _BV (INT0); if (uhrneu && dispon) { if (restzeit == 0) { if (!alarmmissed) strcpy_P (lastline, normalstr); else strcpy_P (lastline, missedstr); } } /* sprintf(lastline,"%d ",savercnt); */ /* screensaver erst ab letzten Tastendruck starten */ if (key != ' ') { char t; t = key; savercnt = 0 - SCREENSAVERMIN; tempalarmed = 0; /* bei bel. Taste Display wieder einschalten */ if (dispon == 0) { wake_lcd (); waitkeyrelease (); uhrneu = 1; strcpy_P (lastline, normalstr); clrscr (); if (t == '6') key = '6'; } /* Akku voll, bestätigen */ if (habenfertig) { laden = 0; habenfertig = 0; ladenendflag = 0; } } /* uhrzeit und Temperatur schreiben */ if (uhrneu) { char e; e = THERMO_GetTemp (); if (needto_save_uhr) { save_uhr (); sprintf (lastline, "EEPROM: %4dms ", 5000 - milliseconds); needto_save_uhr = 0; } if (laden) { /* beleuchtung mittel */ if (!habenfertig) { // set_sleep_mode (SLEEP_MODE_IDLE); // OCR1BL = 160; } savercnt = 0 - SCREENSAVERMIN; do_laden (); } else { if (!(uhrsek % 8)) messbat (); } if (dispon) { /* sprintf (uhrzeit, "%2d%s%02d\n", uhrstund, */ /* (uhrsek & 1) ? doppelpunkt : " ", uhrmin); */ uhrzeit[0] = 48 + (uhrstund / 10); uhrzeit[1] = 48 + uhrstund - 10 * (uhrstund / 10); uhrzeit[2] = (uhrsek & 1) ? doppelpunkt[0] : ' '; uhrzeit[3] = 48 + (uhrmin / 10); uhrzeit[4] = 48 + uhrmin - 10 * (uhrmin / 10); uhrzeit[5] = 0; if (battvoltage <= 2.2) { if (uhrsek & 1) strcpy_P (lastline, battstr); else strcpy_P (lastline, leerstr); wake_lcd (); } lcd_gotoxy (11, 0); lcd_puts (uhrzeit); lcd_gotoxy (9, 0); lcd_puts ((tenable) ? "T " : " "); if (TemperaturAlt == 170) TemperaturAlt = 49; if (e != 1) sprintf (text, "Err %d %d ", e, waitcount); else sprintf (text, " %2d.%s°C ", TemperaturAlt / 2, (TemperaturAlt & 1) ? "5" : "0"); lcd_gotoxy (0, 0); lcd_puts (text); } // end of dispon /* strcpy (text, ""); */ if (TemperaturAlt >= tempmax) { strcpy_P (lastline, temphialarmstr); if (tempalarmed == 1) beeped = 10; wake_lcd (); } else if (TemperaturAlt <= tempmin) { strcpy_P (lastline, templowalarmstr); if (tempalarmed == 1) beeped = 10; wake_lcd (); } else { tempalarmed = 1; } } if (int0event) { strcpy_P (lastline, int0str); int0event = 0; wake_lcd (); } /* abfrage eingabe */ if (key != ' ') { if ((key == '1') || (key == '2') || (key == '3')) getinput (1); if (key == '4') getinput (3); if (key == '6') { lcdlight (); messbat (); } if (key == '5') { char t[6]; int b; messbat (); clrscr (); sprintf (text, "Batt: "); lcd_puts (text); b = battvoltage * 100; itoa (b, t, 10); lcd_putc (t[0]); lcd_putc ('.'); lcd_putc (t[1]); lcd_putc (t[2]); if (runcount > 48) sprintf (text, "V %3dT\nmin:%2d° max:%2d°C", runcount / 24, tempmin / 2, tempmax / 2); else sprintf (text, "V %3dH\nmin:%2d° max:%2d°C", runcount, tempmin / 2, tempmax / 2); lcd_puts (text); delayms (3000); /* strcpy_P (text, normalstr); */ /* clrscr (); */ /* lcd_puts (text); */ } /* Display ausschalten */ if (key == '9') { savercnt = SCREENSAVER; beeped = 2; waitkeyrelease (); strcpy_P (lastline, powersavestr); } /* Nach einemm Watchdog oder anderem Reset muss man die Uhr mit '8' stellen Oder man hält 8 für 2 Sekunden gedrückt */ if (key == '8') { if (doppelpunkt[0] == '?') getinput (2); else { milliseconds = 2500; while ((milliseconds >= 500) && (key == '8')) dosleep (); if (milliseconds < 500) { okbeep (); getinput (2); } } } /* 0 für 2 Sekunden gedrückt halten zum Akku laden einschalten */ if ((key == '0') && (!laden)) { milliseconds = 2500; while ((milliseconds >= 500) && (key == '0')) dosleep (); if (milliseconds < 500) { okbeep (); startladen (); } } /* täglichen Alarm ein/aus */ if (key == '#') { if (tenable) { tenable = 0; talarmed = 1; } else { tenable = 1; talarmed = 0; } sprintf (text, "Tägl. Alarm %s\nWeckzeit: %2d:%02d", (tenable) ? "EIN" : "AUS", tstund, tmin); clrscr (); needto_save_uhr = 1; lcd_puts (text); delayms (3000); } /* umschalten zw. Zielzeit und Restzeitanzeige */ if (key == '*') { weckdisplay = !weckdisplay; beeped = 2; waitkeyrelease (); } if ((key != ' ') && (alarmmissed)) { alarmmissed = 0; okbeep (); } } // ende if key != " " /* kurz vor Alarmablauf screensaver ausschalten */ if ((restzeit != 0) && (restzeit < SCREENSAVER)) { wake_lcd (); } if (savercnt == SCREENSAVER) { if (dispon == 0) power_lcd (1); dispon = 1; } if (savercnt == (SCREENSAVER + 3)) { if (dispon == 1) power_lcd (0); dispon = 0; savercnt = 0; } if ((restzeit) != oldrestzeit) { int min, sek, h; if (restzeit <= 5) beeped = 2; min = restzeit / 60; sek = restzeit - (min * 60); if ((battvoltage <= 2.2) && (uhrsek & 1)) { strcpy_P (lastline, battstr); } else { if (!((uhrsek & 2) && laden)) { if (!weckdisplay) { if (min >= 60) { h = min / 60; min = min - h * 60; sprintf (lastline, "%2dh %2dmin %02dsek ", h, min, sek); } else sprintf (lastline, " %2d min %02d sek ", min, sek); } else sprintf (lastline, "Weckzeit: %2d:%02d", weckstund, weckmin); } } oldrestzeit = restzeit; } /* Alarm startet */ if (((uhrstund == tstund) && (uhrmin == tmin) && tenable && (talarmed == 0)) || ((restzeit <= 0) && (alarmed == 0))) { uint8_t pressed; pressed = 0; asec = 0; wake_lcd (); do { int min, sek, h; clrscr (); strcpy_P (text, alarmstr); lcd_puts (text); lcd_gotoxy (0, 1); if ((uhrstund == tstund) && (uhrmin == tmin) && tenable) sprintf (text, " Täglich: %2d:%02d ", tstund, tmin); else { min = gesamtzeit / 60l; sek = gesamtzeit - (min * 60l); if (min >= 60) { h = min / 60; min = min - h * 60; sprintf (text, "%2dh %2dmin %02dsek ", h, min, sek); } else sprintf (text, " %2d min %02d sek ", min, sek); } lcd_puts (text); beeped = 20; if (key != ' ') pressed = 1; else { delayms (200); if (key != ' ') pressed = 1; clrscr (); delayms (200); if (key != ' ') pressed = 1; } } while ((!pressed) && (asec < MAXASEC)); if (asec >= MAXASEC) alarmmissed = 1; okbeep (); if ((uhrstund == tstund) && (uhrmin == tmin) && tenable && (talarmed == 0)) talarmed = 1; else alarmed = 1; key = ' '; clrscr (); needto_save_uhr = 1; strcpy_P (text, stoppedstr); lcd_puts (text); delayms (2000); /* fertig, in normalmodus gehen */ restzeit = 0; clrscr (); if (alarmmissed) strcpy_P (lastline, missedstr); else strcpy_P (lastline, normalstr); } if (uhrneu) { uhrneu = 0; if (dispon) { lcd_gotoxy (0, 1); lcd_puts (lastline); } } } /* loop forever */ }