Die Idee hinter diesem kleinen Projekt war recht simpel: eine zeitgesteuerte Station für einen Geocache. So sollte zu einer bzw. zwei vordefinierten Zeiten pro Tag eine Aktion ausgelöst werden (z.B. ein Relais geschaltet werden), das ganze dazu a) stromsparend für dauerhaften Batteriebetrieb und b) korrigierbar.
Herausgekommen ist dieser kleine „Wecker“ auf AVR-Basis (ATMEGA8) und einer Dallas 1337 Realtimeclock.
Pro Tag lassen sich zwei Alarm-Zeiten einstellen, die ein Relais anziehen (im Schaltplan eine LED). Natürlich lässt sich auch jede beliebige andere Aktion starten, freie Ports und freier Speicher sind noch genug vorhanden
Über ein kleines LCD-Display und ein einfaches Menü mit 3 Taster-Eingaben lassen sich Zeit und Alarmzeiten jederzeit korrigieren, ohne dafür an den Rechner zu müssen.
(1 Taste Menü/OK, 1 Taste Wert erhöhen, 1 Taste Cursorposition).
Die Ruhestromaufnahme liegt bei etwa 7 uA und ist somit absolut „batterietauglich“.
Hier der Schaltplan:
R1-R3: PullUp-Widerstände (~22k), Q1: Uhrenquarz mit 6pf Lastkapazität
Und hier der Quellcode (BASCOM):
' ==================================== ' = "AVR-Wecker" mit Dallas 1337 RTC = ' = -------------------------------- = ' = Version 1.0 / qByter = ' ==================================== $regfile = "m8def.DAT" $crystal = 1000000 $baud = 9600 $hwstack = 20 Declare Sub Set_menu Declare Sub Settime_Menu Declare Sub Incrcursor_setmenu Declare Sub Selection_setmenu Declare Sub Setalarm_menu Declare Sub Alarm Declare Sub Display_time Declare Sub Display_setting Declare Sub Raisevalue Declare Sub Setcursor Declare Sub Incrcursor Declare Sub Turnoffavr Declare Sub Getdatetime Declare Sub Setdate Declare Sub Settime Declare Sub Setalarm Declare Sub Resetalarm Declare Sub Checkalarm Const Relaistime = 10 Config Portb = &B00000011 Config Portc = &B00111111 Config Portd = &B00000011 Config Sda = Portb.7 ' I2C Bus konfigurieren Config Scl = Portb.6 Const Ds1307w = &HD0 ' Addresse der Ds1307/Ds1337 Uhr Const Ds1307r = &HD1 Config Clock = User ' Interne Time/Date Routinen für Bascom konfigurieren Config Date = Dmy , Separator = . Config Lcd = 20 * 2 ' LCD konfigurieren Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5 Config Debounce = 25 ' Wartezeit zum Entprellen der Taster Portd.7 = 1 ' Pullups für Taster zuschalten Portd.6 = 1 Portd.2 = 1 Portd.3 = 1 ' Pullup für D3/INT1 zuschalten ' Variablen Dim Alarm_flag As Byte Dim Int1_flag As Byte Dim Zeichen As Byte 'Dim Stri As String * 5 Dim Weekday As Byte Dim Set_hour As Byte Dim Set_min As Byte Dim Set_sec As Byte Dim Alarm1_hour As Byte Dim Alarm1_min As Byte Dim Alarm1_sec As Byte Dim Alarm2_hour As Byte Dim Alarm2_min As Byte Dim Alarm2_sec As Byte Dim Alarm_to_change As Byte Dim Maincursorpos As Byte Dim Cursorpos As Byte Maincursorpos = 1 Cursorpos = 1 Int1_flag = 0 Alarm_flag = 0 Enable Interrupts Stop Adc Stop Ac Portb.1 = 1 ' LCD anschalten Waitms 50 ' Kleines INIT, zur Funktionsprüfung beim Start Initlcd Cls Locate 1 , 1 Lcd "Init..." ' Stellen der Uhr, muss nur einmal ausgeführt werden Time$ = "19:57:00" ' Initialwerte für Uhr Date$ = "01.12.10" ' Datum setzen, wird derzeit nicht wirklich gebraucht Alarm1_hour = 19 ' Alarmzeit 1 Alarm1_min = 59 Alarm1_sec = 20 Alarm2_hour = 23 ' Alarmzeit 2 Alarm2_min = 0 Alarm2_sec = 1 Gosub Setalarm ' Alarmzeiten in DS1337 programmieren Enable Int0 ' INT0 = Alarm ausgelöst Config Int0 = Low Level On Int0 Int0_alarm Enable Int1 ' INT 1 = Menü aufrufen Config Int1 = Low Level On Int1 Int1_alarm Lcd "OK!" Wait 1 ' Ende der Initialisierung ' ============= ' HAUPTSCHLEIFE ' ============= Do If Int1_flag = 1 Then ' INT1 ausgelöst, Menü aufrufen Getdatetime Set_menu Int1_flag = 0 Gifr = 32 End If If Alarm_flag = 1 Then ' INT0 ausgelöst, Alarm auslösen Disable Int0 ' Interrupt vorrübergehend abschalten Alarm Alarm_flag = 0 Gifr = 32 ' Interrupt Status Flag zurücksetzen Enable Int0 End If Gosub Turnoffavr ' LCD und AVR abschalten bis Interrupt Loop End ' =============== ' ISRs Int0_alarm: Alarm_flag = 1 Return Int1_alarm: Int1_flag = 1 Return ' ============== ' Sub-Routinen Sub Alarm ' Alarm auslösen Portb.1 = 1 ' LCD anschalten Initlcd Locate 2 , 1 Lcd Time$ ' Zeit anzeigen Locate 1 , 1 Lcd "ALARM" Portb.0 = 1 ' Ausgang schalten (Relais) Wait Relaistime ' Definierte Zeit warten Resetalarm ' Alarm in der RTC resetten/abschalten Portb.0 = 0 ' Ausgang wieder abschalten End Sub Sub Set_menu 'Hauptmenü - Auswahl ob Zeit, Alarm1 oder Alarm2 geändert werden soll Portb.1 = 1 Initlcd Locate 1 , 1 Lcd "SET: Zeit A1 A2" Locate 1 , 6 Cursorpos = 1 Cursor On Blink Int1_flag = 0 ' Interrupt flag löschen Gifr = 32 While Int1_flag = 0 ' Warten auf Tasteneingabe Debounce Pind.6 , 0 , Selection_setmenu , Sub Debounce Pind.7 , 0 , Incrcursor_setmenu , Sub Waitms 10 Wend End Sub Sub Incrcursor_setmenu ' Cursor im Menü auf Position bringen Select Case Cursorpos Case 1: Incr Cursorpos Locate 1 , 11 Case 2: Incr Cursorpos Locate 1 , 14 Case 3: Cursorpos = 1 Locate 1 , 6 End Select End Sub Sub Selection_setmenu ' Aktion je nach Auswahl im Menü Select Case Cursorpos Case 1: ' 1 = Zeit neu stellen Call Settime_menu Case 2: ' 2 = Alarm1 neu stellen Alarm_to_change = 1 Call Setalarm_menu Case 3: ' 3 = Alarm2 neu stellen Alarm_to_change = 2 Call Setalarm_menu End Select End Sub Sub Setalarm_menu ' Alarm neu stellen Cls Locate 1 , 1 Lcd "Neue Alarm" ; Str(alarm_to_change) ; "-Zeit" If Alarm_to_change = 1 Then Set_hour = Alarm1_hour Set_min = Alarm1_min Set_sec = Alarm1_sec Else Set_hour = Alarm2_hour Set_min = Alarm2_min Set_sec = Alarm2_sec End If Gosub Display_setting While Int1_flag = 0 ' Warten auf Tasteneingabe Debounce Pind.7 , 0 , Raisevalue , Sub Debounce Pind.6 , 0 , Incrcursor , Sub Waitms 10 Wend If Alarm_to_change = 1 Then Alarm1_hour = Set_hour Alarm1_min = Set_min Alarm1_sec = Set_sec Else Alarm2_hour = Set_hour Alarm2_min = Set_min Alarm2_sec = Set_sec End If Gosub Setalarm ' Alarm in RTC neu stellen Cls Locate 1 , 1 Lcd "Neuer Alarm" ; Str(alarm_to_change) ; ": " Gosub Display_setting Wait 3 ' Pause für Anzeige + Entprellung End Sub Sub Display_setting ' Zu ändernde Zeit anzeigen Locate 2 , 1 If Set_hour < 10 Then Lcd "0" ; Str(set_hour) ; ":" Else Lcd Str(set_hour) ; ":" End If Locate 2 , 4 If Set_min < 10 Then Lcd "0" ; Str(set_min) ; ":" Else Lcd Str(set_min) ; ":" End If Locate 2 , 7 If Set_sec < 10 Then Lcd "0" ; Str(set_sec) Else Lcd Str(set_sec) End If Gosub Setcursor End Sub Sub Settime_menu ' Zeit neu stellen Cls Locate 1 , 1 Lcd "Zeit einstellen:" Cursorpos = 1 Set_hour = _hour Set_min = _min Set_sec = _sec Gosub Display_setting While Int1_flag = 0 ' Auf Tasteneingabe warten Debounce Pind.7 , 0 , Raisevalue , Sub Debounce Pind.6 , 0 , Incrcursor , Sub Waitms 10 Wend ' An dieser Stelle ist Int1 erneut ausgelöst, also Zeit neu setzen _hour = Set_hour _min = Set_min _sec = Set_sec Gosub Settime ' Zeit in RTC schreiben Cls Locate 1 , 1 Lcd "Neue Zeit: " Gosub Display_setting Wait 3 ' Entprellpause, um sofortigen neuen INT zu verhindern End Sub Sub Incrcursor ' Cursor im Menu neu setzen / erhöhen If Cursorpos > 2 Then Cursorpos = 1 Else Incr Cursorpos End If Gosub Setcursor End Sub Sub Raisevalue ' Wert (h/min/sec) erhöhen Select Case Cursorpos Case 1: ' 1 = Stunden If Set_hour = 23 Then Set_hour = 0 Else Incr Set_hour End If Locate 2 , 1 If Set_hour < 10 Then Lcd "0" ; Str(set_hour) ; ":" Else Lcd Str(set_hour) ; ":" End If Locate 2 , 1 Case 2: ' 2 = Minuten If Set_min = 59 Then Set_min = 0 Else Incr Set_min End If Locate 2 , 4 If Set_min < 10 Then Lcd "0" ; Str(set_min) ; ":" Else Lcd Str(set_min) ; ":" End If Locate 2 , 4 Case 3: ' 3 = Sekunden If Set_sec = 59 Then Set_sec = 0 Else Incr Set_sec End If Locate 2 , 7 If Set_sec < 10 Then Lcd "0" ; Str(set_sec) Else Lcd Str(set_sec) End If Locate 2 , 7 End Select End Sub Sub Setcursor ' Cursor auf die Position der aktuellen Auswahl setzen Select Case Cursorpos Case 1: Locate 2 , 1 Case 2: Locate 2 , 4 Case 3: Locate 2 , 7 End Select End Sub Sub Turnoffavr: Portb.1 = 0 ' LCD aus Portc = 0 ' Alle Datenpins low Powerdown End Sub ' ================================================== ' Unterprogramme für die RTC Sub Getdatetime I2cstart I2cwbyte Ds1307w I2cwbyte 0 I2cstart I2cwbyte Ds1307r I2crbyte _sec , Ack I2crbyte _min , Ack I2crbyte _hour , Ack I2crbyte Weekday , Ack I2crbyte _day , Ack I2crbyte _month , Ack I2crbyte _year , Nack I2cstop _sec = Makedec(_sec) : _min = Makedec(_min) : _hour = Makedec(_hour) _day = Makedec(_day) : _month = Makedec(_month) : _year = Makedec(_year) End Sub Sub Setdate _day = Makebcd(_day) : _month = Makebcd(_month) : _year = Makebcd(_year) I2cstart I2cwbyte Ds1307w I2cwbyte 4 I2cwbyte _day I2cwbyte _month I2cwbyte _year I2cstop End Sub Sub Settime _sec = Makebcd(_sec) : _min = Makebcd(_min) : _hour = Makebcd(_hour) I2cstart I2cwbyte Ds1307w I2cwbyte 0 I2cwbyte _sec I2cwbyte _min I2cwbyte _hour I2cstop End Sub Sub Setalarm I2cstart I2cwbyte Ds1307w I2cwbyte 7 Zeichen = Makebcd(alarm1_sec) I2cwbyte Zeichen Zeichen = Makebcd(alarm1_min) I2cwbyte Zeichen Zeichen = Makebcd(alarm1_hour) I2cwbyte Zeichen I2cwbyte &B10000000 '128 = Jeweils beim Erreichen von h/m/s ALARM auslösen Zeichen = Makebcd(alarm2_sec) I2cwbyte Zeichen Zeichen = Makebcd(alarm2_min) I2cwbyte Zeichen Zeichen = Makebcd(alarm2_hour) I2cwbyte Zeichen I2cstop I2cstart I2cwbyte Ds1307w I2cwbyte 14 I2cwbyte &B00011011 'Alarme aktivieren I2cwbyte 0 'Statusbits auf 0 I2cstop End Sub Sub Resetalarm I2cstart I2cwbyte Ds1307w I2cwbyte 15 I2cwbyte 0 I2cstop End Sub