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