; Intervallschaltuhr für NIKON D50, F75 ect.
; Version 2.3
; Versionsinfo 2.0: Tasten entprellt, Tasterturroutine eingeführt

; Versionsinfo 2.1: Abschalten eingfügt, Bildzähler aus EEPROM lesen eingefügt
; Versionsinfo 2.1: Bildzähler in EEPROM speichern eingefügt
; Versionsinfo 2.1: Bildzähler löschen eingefügt

; Versionsinfo 2.2: neue Tatastaturroutine 'TastLos' die die vorhandene Tastaturrpoutine
;      'TasteAbfragen' beinhaltet und zusätzlich darauf wartet, dass die
;      Taste wieder losgelassen wird.
; Versionsinfo 2.2: Neue Menueroutine,
; Versionsinfo 2.2: Externe Fernsteuerung auf C.2 gelegt

; Versionsinfo 2.3: Menuepunkt 'abschalten' entfernt. (Abschaltung erfolgt nun mit einem Schalter)
; Versionsinfo 2.3: Display bleibt nach Ablauf der Zeit erhalten. Controller bleibt eingeschaltet
;
; LCD-Display an B.0 bis B.5
; IR-LED an D.0
; Taste 'weiter' an C.0
; Taste 'ok' an C.1
; Taste 'Aufnahme' an C.1 (= ok)
; Externe Fernsteuerung 'Aufnahme' an C.2
;------------------------------------------------------------
.include "m88def.inc"

.def temp1   = r16
.def temp2   = r17
.def temp3   = r18
.def Flag    = r19

.def ISek     = r20
.def IMin       = r21
.def BilderL = r22
.def BilderH = r23

.def KeyPressed = r24
.def Menptr  = r25

.equ LCD_PORT  = PORTB
.equ LCD_DDR   = DDRB
.equ PIN_RS    = 4
.equ PIN_E     = 5

.ifndef XTAL
.equ XTAL   = 8000000
.endif

.CSEG
.org 0x0000
        rjmp    main             ; Reset Handler
.org OC1Aaddr
        rjmp    timer1_compare   ; Timer Compare Handler

main:
        ldi     temp1,  HIGH(RAMEND)
        out     SPH,  temp1
        ldi     temp1,  LOW(RAMEND)  ; Stackpointer initialisieren
        out     SPL,  temp1

  ldi  temp1,  0b00000001 ; IR-LED initialisieren
  out  DDRD,  temp1
  ldi  Temp1,  0
  out  PORTD,  Temp1

  ldi  Temp1, 0B00000100 ; Power Down und Sleep-mode Disable
  sts  SMCR, Temp1   ; Power Down und Sleep-mode Disable

   ldi     temp1,  0x00
  out  DDRC,  Temp1  ; Tasten sind auf Eingang
  ldi  TEMP1, 0xFF
  out  PORTC, Temp1  ; Pullup-Widerstände eingeschaltet

        rcall   lcd_init
        rcall   lcd_clear
                                     ; Vergleichswert
        ldi     temp1, high( 40000 - 1 )
        sts     OCR1AH, temp1
        ldi     temp1, low( 40000 - 1 )
        sts     OCR1AL, temp1
                                    ; CTC Modus einschalten
                                    ; Vorteiler auf 1
        ldi     temp1, ( 1 << WGM12 ) | ( 1 << CS10 )
        sts     TCCR1B, temp1

        ldi     temp1, 1 << OCIE1A  ; OCIE1A: Interrupt bei Timer Compare
        sts     TIMSK1, temp1

        ldi  Temp1, 1   ; Stunden auf Defaultwert 1 Setzen
  sts     Stunden, Temp1
  clr  Temp1
  sts     Minuten, Temp1      ; Die Uhr auf 0 setzen
        sts     Sekunden, Temp1
        sts     SubCount, Temp1
        clr     Flag                ; Flag löschen
;  clr  BilderL    ; Anzahl Bilder löschen
;  clr  BilderH
  rcall Zaehler_read
  ldi  Temp1, 10   ; Intervall setzen, Default = 10 Sekunden
  mov  ISek,Temp1
  sts  IntvSekunden, Temp1
  clr  Temp1
  mov  Imin,Temp1
  sts  IntvMinuten, Temp1
;------------------------------------------------------------------------------
HMenue:
  ldi ZL, LOW(Menue10*2)     ; Low-Byte der MenueAdresse in Z-Pointer
     ldi ZH, HIGH(Menue10*2)    ; High-Byte der MenueAdresse in Z-Pointer

  rcall Menue

  cpi  MenPtr,1
  breq HMenue01

  cpi  MenPtr,2
  breq HMenue02

  cpi  MenPtr,3
  breq HMenue03

  rjmp Hmenue

HMenue01:
  rjmp IMenue    ; 'OK' wurde gedrückt AUSGANG, IMenue
HMenue02:
  rjmp Fernsteuerung  ; AUSGANG, Fernsteuerung
HMenue03:
  rjmp LoeschZaehler

;------------------------------------------------------------------------------
IMenue:
  ldi ZL, LOW(Menue20*2)     ; Low-Byte der MenueAdresse in Z-Pointer
     ldi ZH, HIGH(Menue20*2)    ; High-Byte der MenueAdresse in Z-Pointer

  rcall Menue

  cpi  MenPtr,1
  breq IMenue01

  cpi  MenPtr,2
  breq IMenue02

  rjmp Imenue

IMenue01:
  rjmp start
IMenue02:
  rjmp IntMin
;------------------------------------------------------------------------------
;IntervallMinuten stellen
IntMin:
IntMin10:
  rcall Anzei1    ; Werte anzeigen
  ldi  Temp1, 0
  ldi  Temp2, 11
  rcall  lcd_cursor   ; Cursor positionieren
  ldi  Temp1, 0b00001111 ; Cursor blinken
  rcall lcd_command
IntMin11:
  ldi  KeyPressed, 0b00000011
  rcall TastLos      ; Tasten abfragen
  mov  Temp1, KeyPressed   ; und Ergebnis in Temp1
  mov  Temp2, Temp1    ; und Temp2 speichern

  andi Temp1, 0b00000001
  brne IntMin12   ; 'weiter' wurde gedrückt, Min erhöhen
  andi Temp2, 0b00000010
  breq IntMin11   ; 'OK' wurde gedrückt AUSGANG
 ; Umgekehrte Funktion
  ldi  Temp1, 0b00001100 ; Cursor blinken aus und Cursor aus
  rcall lcd_command
  sts  IntvMinuten,IMin
  rjmp IntSek    ; *********  AUSGANG nach 'Intervall Sekunden stellen' ********

IntMin12:
  inc  Imin    ; Minuten um 1 erhöhen
  cpi  Imin, 60
  brne IntMin10
  ldi  Imin, 0
  rjmp IntMin10
;------------------------------------------------------------------------------
;IntervallSekunden stellen
IntSek:
IntSek10:
  rcall Anzei1    ; Werte anzeigen
  ldi  Temp1, 0
  ldi  Temp2, 14
  rcall  lcd_cursor   ; Cursor positionieren
  ldi  Temp1, 0b00001111 ; Cursor blinken
  rcall lcd_command
IntSek11:
  ldi  KeyPressed, 0b00000011
  rcall TastLos      ; Tasten abfragen
  mov  Temp1, KeyPressed   ; und Ergebnis in Temp1
  mov  Temp2, Temp1    ; und Temp2 speichern

  andi Temp1, 0b00000001
  brne IntSek12   ; 'weiter' wurde gedrückt, Min erhöhen
  andi Temp2, 0b00000010
  breq IntSek11   ; 'OK' wurde nicht gedrückt
; Umgekehrte Funktion
  ldi  Temp1, 0b00001100 ; Cursor blinken aus und Cursor aus
  rcall lcd_command
  sts  IntvSekunden,ISek
  rjmp DauStu    ; *********  AUSGANG nach 'Dauer Stunden stellen' ********

IntSek12:
  inc  ISek    ; Sekunden um 1 erhöhen
  cpi  ISek, 60
  brne IntSek10
  ldi  ISek, 0
  rjmp IntSek10
;----------------------------------------------------------------------
;------------------------------------------------------------------------------
;Dauer Stunden stellen
DauStu:
DauStu10:
  rcall Anzei1    ; Werte anzeigen
  ldi  Temp1, 1
  ldi  Temp2, 4
  rcall  lcd_cursor   ; Cursor positionieren
  ldi  Temp1, 0b00001111 ; Cursor blinken
  rcall lcd_command
DauStu11:
  ldi  KeyPressed, 0b00000011
  rcall TastLos      ; Tasten abfragen
  mov  Temp1, KeyPressed   ; und Ergebnis in Temp1
  mov  Temp2, Temp1    ; und Temp2 speichern

  andi Temp1, 0b00000001
  brne DauStu12   ; 'weiter' wurde gedrückt, Stunden erhöhen
  andi Temp2, 0b00000010
  breq DauStu11   ; 'OK' wurde nicht gedrückt
; Umgekehrte Funktion
  ldi  Temp1, 0b00001100 ; Cursor blinken aus und Cursor aus
  rcall lcd_command
  rjmp DauMin    ; *********  AUSGANG nach 'Dauer Minuten stellen' ********

DauStu12:
  lds  Temp1, Stunden
  inc  Temp1    ; Stunden um 1 erhöhen
  sts  Stunden, Temp1
  cpi  Temp1, 24
  brne DauStu10
  clr  Temp1
  sts  Stunden, Temp1
  rjmp DauStu10
;------------------------------------------------------------------------------
;Dauer Minuten stellen
DauMin:
DauMin10:
  rcall Anzei1    ; Werte anzeigen
  ldi  Temp1, 1
  ldi  Temp2, 7
  rcall  lcd_cursor   ; Cursor positionieren
  ldi  Temp1, 0b00001111 ; Cursor blinken
  rcall lcd_command
DauMin11:
  ldi  KeyPressed, 0b00000011
  rcall TastLos      ; Tasten abfragen
  mov  Temp1, KeyPressed   ; und Ergebnis in Temp1
  mov  Temp2, Temp1    ; und Temp2 speichern

  andi Temp1, 0b00000001
  brne DauMin12   ; 'weiter' wurde gedrückt, Stunden erhöhen
  andi Temp2, 0b00000010
  breq DauMin11   ; 'OK' wurde nicht gedrückt
; Umgekehrte Funktion
  ldi  Temp1, 0b00001100 ; Cursor blinken aus und Cursor aus
  rcall lcd_command
  rjmp DauSek    ; *********  AUSGANG nach 'Dauer Sekunden stellen' ********

DauMin12:
  lds  Temp1, Minuten
  inc  Temp1    ; Minuten um 1 erhöhen
  sts  Minuten, Temp1
  cpi  Temp1, 60
  brne DauMin10
  clr  Temp1
  sts  Minuten, Temp1
  rjmp DauMin10
;----------------------------------------------------------------------
;Dauer Sekunden stellen
DauSek:
DauSek10:
  rcall Anzei1    ; Werte anzeigen
  ldi  Temp1, 1
  ldi  Temp2, 10
  rcall  lcd_cursor   ; Cursor positionieren
  ldi  Temp1, 0b00001111 ; Cursor blinken
  rcall lcd_command
DauSek11:
  ldi  KeyPressed, 0b00000011
  rcall TastLos      ; Tasten abfragen
  mov  Temp1, KeyPressed   ; und Ergebnis in Temp1
  mov  Temp2, Temp1    ; und Temp2 speichern

  andi Temp1, 0b00000001
  brne DauSek12   ; 'weiter' wurde gedrückt, Stunden erhöhen
  andi Temp2, 0b00000010
  breq DauSek11   ; 'OK' wurde nicht gedrückt
; Umgekehrte Funktion
  ldi  Temp1, 0b00001100 ; Cursor blinken aus und Cursor aus
  rcall lcd_command
  rjmp IMenue    ; *********  AUSGANG nach 'Intervall-Menue' ********

DauSek12:
  lds  Temp1, Sekunden
  inc  Temp1    ; Sekunden um 1 erhöhen
  sts  Sekunden, Temp1
  cpi  Temp1, 60
  brne DauSek10
  clr  Temp1
  sts  Sekunden, Temp1
  rjmp DauSek10
;----------------------------------------------------------------------
;----------------------------------------------------------------------
start:
  sei
loop:

  sbrs Flag, 0    ; Bit0 in Flag im Interrupt gesetzt?
        rjmp    loop
        andi    Flag,0b11111110     ; Bit0 in Flag löschen
;----------------------------------------------------------------------
; Test ob Intervall abgelaufen ist.
  tst  IMin
  brne  Anzeige

  tst  ISek
  brne  Anzeige
  lds  ISek, IntvSekunden
  lds  IMin, IntvMinuten
;---------------------------------------------------
  rcall  Ausloesen
;---------------------------------------------------
Anzeige:
  rcall Anzei1
;-----------------------------------------------------------------------
; Test ob die Dauer abgelaufen ist
Test_Dauer:
  lds Temp1, Stunden
  tst Temp1
  brne loop

  lds Temp1, Minuten
  tst Temp1
  brne loop

  lds Temp1, Sekunden
  tst Temp1
  brne loop
; wenn ja, , Interrupt aus, Zähler speichern und warten.
  cli
  rcall Zaehler_write  ; Zählerstand ins EEPROM abspeichern
halt:
  rjmp  halt
;**************************************************************************
Abschalten:

   cli
  rcall Zaehler_write  ; Zählerstand ins EEPROM abspeichern
  ldi  Temp1, 0b00001000 ; Displaus aus; (Cursor nicht blinkend und aus)
  rcall  lcd_command
  ldi  Temp1, 0B00000101 ; Power Down und Sleep-mode Enable
  sts  SMCR, Temp1   ; Power Down und Sleep-mode Enable
  nop
  sleep
        rjmp    loop
;**************************************************************************
LoeschZaehler:
  clr  BilderL
  clr  BilderH
  rcall Anzei1
  ldi  temp1, 50
LoeschZLoop0:
  rcall  Twarten025
  dec  temp1
  brne  LoeschZLoop0

  rcall Zaehler_write    ; Zählerstand ins EEPROM abspeichern
  cli
  rjmp HMenue
;**************************************************************************
Fernsteuerung:
        clr  Temp1
  sts     Stunden, Temp1
  sts     Minuten, Temp1      ; Die Uhr auf 0 setzen
        sts     Sekunden, Temp1
        sts     SubCount, Temp1
        clr     Flag                ; Flag löschen
;  clr  BilderL    ; Anzahl Bilder löschen
;  clr  BilderH

  clr  Imin
  clr  ISek
  sts  IntvMinuten, Temp1
  sts  IntvSekunden, Temp1

Fernsteuerung10:     ; ***Fernsteuerung starten***
  rcall Anzei1    ; Werte anzeigen
Fernsteuerung11:
  ldi  KeyPressed, 0b00000111
  rcall TastLos    ; Tasten abfragen
  mov  Temp1, KeyPressed   ; und Ergebnis in Temp1

  andi Temp1, 0b00000001
  brne Fernsteuerung11          ; 'weiter' wurde gedrückt

  mov  Temp1, KeyPressed   ; und Ergebnis in Temp1
  andi Temp1, 0b00000010
  brne Fernsteuerung12    ; 'OK' wurde gedrückt Auslösen und anzeigen

  mov  Temp1, KeyPressed   ; und Ergebnis in Temp1
  andi Temp1, 0b00000100
  breq Fernsteuerung11    ; Ferbedienung wurde gedrückt Auslösen und anzeigen

Fernsteuerung12:
  rcall Ausloesen
  rcall Zaehler_write    ; Zählerstand ins EEPROM abspeichern
  cli
  rjmp Fernsteuerung10
;####################################################################################
timer1_compare:                     ; Timer 1 Output Compare Handler

        push    temp1               ; temp 1 sichern
        in      temp1,sreg          ; SREG sichern

  lds  Temp1,SubCount
        inc     Temp1
  sts  SubCount, Temp1     ; Wenn dies nicht der 200. Interrupt
        cpi     Temp1, 200        ; ist, dann passiert gar nichts
        brne    end_isr
  clr  Temp1    ; Überlauf
  sts  SubCount,Temp1  ; SubCount rücksetzen



        lds     Temp1,Sekunden
        dec     Temp1             ; minus 1 Sekunde
  sts  Sekunden, Temp1
  lds  Temp1, Sekunden
  cpi     Temp1, -1         ; sind 60 Sekunden vergangen?
        brne    Ausgabe             ; wenn nicht kann die Ausgabe schon
                                    ; gemacht werden

                              ; Überlauf
  ldi  Temp1, 59
  sts  Sekunden, Temp1  ; Sekunden wieder auf 59 und dafür
  lds  Temp1, Minuten
        dec     Temp1             ; minus 1 Minute
  sts  Minuten, Temp1
        cpi     Temp1, -1          ; sind 60 Minuten vergangen ?
        brne    Ausgabe             ; wenn nicht, -> Ausgabe

                                    ; Überlauf
  ldi  Temp1, 59
        sts     Minuten, Temp1      ; Minuten zurücksetzen und dafür
  lds  Temp1, Stunden
        dec     Temp1              ; minus 1 Stunde
  sts  Stunden, Temp1
  cpi     Temp1, -1          ; nach 24 Stunden, die Stundenanzeige
        brne    Ausgabe             ; wieder zurücksetzen

                                    ; Überlauf
  clr  Temp1
        sts     Stunden,Temp1       ; Stunden rücksetzen

Ausgabe:
        ori     flag,0b00000001     ; Flag setzen, LCD updaten
  dec  ISek
  cpi  ISek, -1   ; Intervall-Sekunden -1
  brne  end_isr

  ldi  ISek, 59
  dec  IMin    ; Intervall-Minuten -1
  cpi  IMin, -1
  brne  end_isr

  ldi  IMin, 59

end_isr:

        out     sreg,temp1          ; sreg wieder herstellen
        pop     temp1
        reti                        ; das wars. Interrupt ist fertig

;**************************************************************************
Ausloesen:
  push  Temp1
  push Temp2

  rcall Fernbedienung  ; Ein Bild auslösen
;---------------------------------------------------
; Anzahl der belichteten Bilder plus eins

  ldi  temp1, 1
  ldi  Temp2, 0
  add  BilderL, Temp1
  adc  BilderH, Temp2

  pop  Temp2
  pop  Temp1
  ret
;**************************************************************************
Anzei1:
        rcall   lcd_clear           ; das LCD löschen

  mov  Temp1, BilderL  ; Anzahl der belichteten Bilder ausgeben
  mov  Temp2, BilderH
   rcall  out_number

  ldi  Temp1, 0   ; Cursor auf Zeile 1
  ldi  Temp2, 11   ; und Spalte 11 setzen
  rcall lcd_cursor

        mov     temp1, IMin       ; Intervallzeit Minuten ausgeben
        rcall   lcd_zeit
        ldi     temp1, ':'          ; zwischen Minuten und Sekunden einen ':'
        rcall   lcd_data
        mov     temp1, ISEK       ; dann die Intervallzeit Sekunden ausgeben
        rcall   lcd_zeit
;----------------------------------------------------------------------------

  ldi  Temp1, 1   ; Cursor auf Zeile 2
  ldi  Temp2, 4   ; und Spalte 4 setzen
  rcall lcd_cursor

        lds     temp1, Stunden      ; und die Stunden ausgeben
        rcall   lcd_zeit
        ldi     temp1, ':'          ; zwischen Stunden und Minuten einen ':'
        rcall   lcd_data
        lds     temp1, Minuten      ; dann die Minuten ausgeben
        rcall   lcd_zeit
        ldi     temp1, ':'          ; und noch ein ':'
        rcall   lcd_data
        lds     temp1, Sekunden     ; und die Sekunden
        rcall   lcd_zeit

  ret
;**************************************************************************
Twarten025:
  push  Temp3     ; 25 mS warten
  push  Temp2
  push Temp1
  ldi  Temp2,255
TWarten025zwei:
  rcall  TWarten025eins
  dec  Temp2
  brne TWarten025zwei
  pop  Temp1
  pop  Temp2
  pop  Temp3
  ret
TWarten025eins:
  ldi  Temp3,255
TWarten025_loop:
  dec  Temp3     ; 1 cycle
  brne TWarten025_loop   ; 2 cycle if jump to label, 1 if not
  ret        ; 4 cycles
;**************************************************************************
; ACHTUNG Routine ist für PIN C mit NUR 7 Bits gedacht.
; Stehen 8 Bit zur Verfügung, dann den Term:
; ori Temp1,$80 entfernen (Zweimal)
; Keypressed übegibt das Bitmuster der abzufragenden Tasten.
; z.B. 0b00000011 (Bit0 und Bit1 des Ports). Erfolgt kein Tastendruck der,
; mit Keypressed selektierten Tasten, dann wird 'AbfrageTaste' mit dem Wert 0
; in 'Keypressed' verlassen. Wird eine der gegebenen Tasten gedrückt,
; erfolgt, nach der Entprellung, das Verlassen von 'AbfrageTaste'
; mit dem Eingangswert der gerückten Tasten. (log 1 heisst dabei Taste gedrückt)
TasteAbfragen:
  push Temp2
  push Temp1
TasteAbfragen1:
  in   Temp1, PINC
  ori  Temp1, $80   ; Weil auf PINC das 7.Bit fehlt.
  mov  Temp2, Temp1
  and  Temp1, Keypressed
  eor  Keypressed, Temp1 ; Welche von den Vorgabetasten gedrückt?
  breq TastAbfragenVerlassen ; nöö
TasteAbfragen2:      ; jau
  rcall TWarten025   ; 25 mS warten
  in   Temp1, PINC
  ori  Temp1, $80;   ; Weil auf PINC das 7.Bit fehlt.
  cp  Temp1, Temp2  ; Immer noch die gleichen Tasten gedrückt?
  brne TasteAbfragen1  ; nöö, musse noch mal abfragen
TastAbfragenVerlassen:
  pop  Temp1
  pop  Temp2
  ret
;**************************************************************************
; Tastaturabfrage wie 'TastAbfragen', jedoch wird gewartet bis die Taste
; wieder losgelassen wird. Übergabe mit 'KeyPressed'
TastLos:
  push Temp1
  mov  Temp1, Keypressed
TastLosloop:
  mov  KeyPressed, Temp1
  rcall TasteAbfragen   ; Tasten abfragen
  mov  Temp1, KeyPressed  ; und Ergebnis in Temp1
TastLosloop1:
  rcall TasteAbfragen
  tst  Keypressed
  brne TastLosloop1   ; Taste wieder losgelassen?

  mov  Keypressed, Temp1
  pop  Temp1

  ret
;**************************************************************************
Zaehler_read:
    ldi     ZL,low(daten)               ; Z-Zeiger laden
    ldi     ZH,high(daten)
ZR01:
    sbic    EECR,EEPE                   ; prüfe ob der vorherige Schreibzugriff
                                        ; beendet ist
    rjmp    ZR01                  ; nein, nochmal prüfen

    out     EEARH,  ZH                  ; Adresse laden
    out     EEARL,  ZL
    sbi     EECR,  EERE                ; Lesevorgang aktivieren
    in      BilderH, EEDR               ; Daten in CPU Register kopieren

 adiw    ZL,1       ; Z-Pointer um 1 eröhnen (f. 2.Byte)

ZR02:
    sbic    EECR,EEPE                   ; prüfe ob der vorherige Schreibzugriff
                                        ; beendet ist
    rjmp    ZR02                  ; nein, nochmal prüfen

    out     EEARH,  ZH                  ; Adresse laden
    out     EEARL,  ZL
    sbi     EECR,  EERE                ; Lesevorgang aktivieren
    in      BilderL, EEDR               ; Daten in CPU Register kopieren

    ret
;**************************************************************************
Zaehler_write:
 push Temp1
  ldi     ZL,low(daten)               ; der Z-Zeiger wird hier exclusiv
    ldi     ZH,high(daten)              ; für die Datenadressierung verwendet

ZW01:
    sbic    EECR, EEPE                  ; prüfe ob der letzte Schreibvorgang beendet ist
    rjmp    ZW01                  ; wenn nein, nochmal prüfen

    out     EEARH, ZH                   ; Adresse schreiben
    out     EEARL, ZL                   ;
    out     EEDR,BilderH                ; Daten  schreiben
    in      Temp1,sreg               ; SREG sichern
    cli                                 ; Interrupts sperren, die nächsten
                                        ; zwei Befehle dürfen NICHT unterbrochen werden
    sbi     EECR,EEMPE                  ; Schreiben vorbereiten
    sbi     EECR,EEPE                   ; Und los !

 ADIW  ZL,1      ; Z-Pointer um 1 erhöhen

ZW02:
    sbic    EECR, EEPE                  ; prüfe ob der letzte Schreibvorgang beendet ist
    rjmp    ZW02                  ; wenn nein, nochmal prüfen

    out     EEARH, ZH                   ; Adresse schreiben
    out     EEARL, ZL                   ;
    out     EEDR,BilderL                ; Daten  schreiben

    sbi     EECR,EEMPE                  ; Schreiben vorbereiten
    sbi     EECR,EEPE                   ; Und los !

 sei
    out     sreg, Temp1              ; SREG wieder herstellen
 pop  Temp1
    ret

;**************************************************************************
; Eine Menuezeile baut sich wie folgt auf:
; .db  "  Fernsteuerung ",0,255
; wobei die 0 das Ende der Menuezeile anzeigt und die 255(Zahl<>0), dass eine
; weitere Menuezeile folgt. Die letzte Menuezeile hat das Format:
; .db  "Zaehler loeschen",0,0
; Dabei zeigt die letzte 0 das Ende des Menues an.
; Die Variable 'MenPtr' gibt zurück welcher Menuepunkt 1,2,... gewählt wurde.
Menue:
  push Temp1
  push Temp2
  push Temp3
  mov  Temp2, ZL
  mov  Temp3, ZH
MenWarten00:
  ldi  MenPtr,1   ; Menuepointer auf 1. Eintrag setzen
  mov  ZL, Temp2
  mov  ZH, Temp3
MenWarten10:
  rcall   lcd_clear   ; LCD löschen
  rcall  lcd_flash_string  ; Menuepunkt anzeigen
MenWarten11:
  ldi  KeyPressed, 0b00000011
  rcall TastLos      ; Tasten abfragen
  mov  Temp1, KeyPressed   ; und Ergebnis in Temp1
  andi Temp1, 0b00000001
  brne weiter  ; 'weiter' wurde gedrückt
  mov  Temp1, Keypressed
  andi Temp1, 0b00000010
  brne ok   ; 'OK' wurde gedrückt AUSGANG Menue

  rjmp MenWarten11

weiter:
  inc  Menptr     ; Menuepointer um 1 erhöhen
        lpm    temp1, Z+
        cpi    temp1, 0    ; war das der letzte Eintrag?
  breq MenWarten00    ; Ja, von vorn beginnen
  rjmp MenWarten10    ; Nein, nächster Eintrag
ok:
  pop  Temp3
  pop  Temp2
  pop  Temp1
  ret
;**************************************************************************
.include "lcd-routines.asm"
.include "fernbedienung.asm"
;**************************************************************************
Menue10:
.db  "  Intervalluhr  ",0,255
.db  "  Fernsteuerung ",0,255
.db  "Zaehler loeschen",0,0
Menue20:
.db  "     starten    ",0,255
.db  "  Uhr stellen   ",0,0
Hilfe01:
.db  "weiter OK  RESET",0,0
Hilfe02:
.db  "       OK  RESET",0,0
Hilfe03:
.db  "           RESET",0,0
;**************************************************************************
           .DSEG
SubCount:  .byte 1    ; zählt 5mS hoch, bis 1 Sekunde erreicht ist
Stunden:  .byte 1    ; Stunden der Anzeige (Quarzuhr) = Dauer
Minuten:  .byte 1    ; Minuten der Anzeige (Quarzuhr) = Dauer
Sekunden:  .byte 1    ; Sekunden der Anzeige (Quarzuhr) = Dauer
IntvMinuten: .byte 1    ; eingestellte Intervallzeit Minuten
IntvSekunden: .byte 1    ; eingestellte Intervallzeit Sekunden
;**************************************************************************
; Daten im EEPROM definieren
.eseg
daten:
    .db     0,0