Elektronik: AVR-Wecker mit RTC

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:

Schaltplan "AVR-Wecker mit RTC"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

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.