;************************************************************************************
;*	Universal Count-Down Timer														*
;*	----------------------------													*
;*																					*
;*	Specialversion für Manni:     													*
;*  Zuletzt gestartete Zeit im EEprom speichern	und bei Neustart wieder laden		*
;*	Presettabelle 0:30 ... 9:90 alle 30 Sekunden									*
;*																					*
;*	Specialversion für Leon:     													*
;*	Die letzten 5 Counts, werden mit einem kurzen Beep begleitet					*
;*																					*
;*																					*
;*	Hardware: 																		*
;*	Portview-Modul mit AT-Mega8/48 http://www.avr-projekte.de/portview.htm			*
;*	5V Summer mit GND an PD2														*
;*	evtl. Relais + NPN Treiber und/oder LED an PD3									*
;*	Drehgeber mit Taster an PC3/PC4, Taster an PC0 oder ...							*
;*	3 Taster an PC0..3. (Enter) PC0, (-) PC1, (+) PC2								*
;*	Dezimalpunkt über 120R an PC5													*
;*																					*
;*	Version vom 21.11.2012 															*
;*																					*
;*	Autor: J.Woetzel / juergen@avr-projekte.de										*
;************************************************************************************
;.list
;*******************************************************************************************************														
;Parameter
;------------------------
#define mega48				;Einen der beiden AVRs auskommentieren
;#define mega8
;---------------------------------------------------------------------------------------------------
;Der CountmS Wert bestimmt wieviele Millisekunden gezählt werden, bis eine Zeiteinheit um ist.
;Beispiele: 1000 = 1 Sekunde Auflösung = max. "9.59" Min. oder "999" Sekunden 
;60000 = 1 Minute Auflösung = max. "9.59" Std. 
;100 = 0,1 Sek. Auflösung = max. "99.9" Sekunden | 10 = 0,01 Sek. Auflösung = max. "9.99" Sekunden
.equ	countms		= 1000	;Zeit in  Millisekunden. 
;---------------------------------------------------------------------------------------------------
.equ	overf		= 60	;60 bei "9:59" Minuten oder Stunden. 100 bei "99.9" oder "999" Sekunden
.equ	korrektur	= 45	;Macht die Uhr ca. Wert*1mS pro Sekunde langsamer, negativ=schneller
.equ	premin		= 0		;Preset Minuten. Bei Power on
.equ	presek		= 0		;Preset Sekunden. Dito
.equ	buzztime	= 6		;Summer: Dauer in 1/2 Sekunden (*512mS)
.equ	rep_kurz	= 25	;Tastenwiederholung, Verzögerung *2 Millisekunden
.set	encoder 	= 0		;Geschwindigkeit Drehimpulsgeber 0=1/4 (langsam), 1=1/2(mittel), 2=(schnell)
.set	scroll		= 1		;Spielerei bei Count Down Ende. 0/1 = Aus/Ein
;*******************************************************************************************************
#if defined mega48
#include "m48def.inc"
#endif
;-------------------------------------------------------------------------------------------------------
#if defined mega8
#include "m8def.inc"
#endif
;-------------------------------------------------------------------------------------------------------
;Register
.def	icnt	=	r0		;ISR-Zähler für div. Timings
.def	taste1	=	r1		;Taster
.def	taste2	=	r2
.def	taste3	=	r3
.def	richtung=	r4		;Variable für Drehimpulsgeber
.def	tick	=	r5		;ISR-Zähler für Sekunden
.def	repeat	=	r6		;Zähler für Tastenrepeatfunktion
.def	sekl	=	r7		;16-Bit ISR-Zähler für Millisekunden
.def	sekh	=	r8
.def	buzz	=	r9		;Summer/Zeit
.def	null	=	r10		;Konstanten
.def	eins	=	r11
.def	sechzig	=	r12
.def	s		=	r15		;S-Register
.def	temp1	=	r16		;Trash       
.def	temp2	=	r17       
.def	enc		=	r19		;Drehimpulsgeber
.def	sek		=	r20		;Sekunden
.def	min		=	r21		;Minuten
.def	seg0	=	r22		;7Seg. Digits, Hunderter
.def	seg1	=	r23		;Zehner
.def	seg2	=	r24		;Einer
;R18, X und Y sind (noch) unbenutzt
;----------------------
.def	flags	=	r25		;Programmflags
;----------------------		;Die einzelnen Bits 
.equ	enter	=	7		;Tasten (Flanken)
.equ	up		=	6
.equ	down	=	5
.equ	Relais	=	3		;Relais Ein/Aus
.equ	buzzer	=	2		;Summer Ein/Aus
.equ	isrx	=	1		;ISR-Flag. 1= Multiplexen / 0= Tasten abfragen
;-----------------------
;*************************************************************************************************
;AVR Sprungvektoren
;*************************************************************************************************
	.org 0
	rjmp	reset
	.org	OC1Aaddr
	rjmp	isr
;*************************************************************************************************
;*	Presettabelle.
;*	--------------
;*	Minuten, Sekunden. Beliebig erweiterbar.
;*	Bei Doppelclick auf Start (oder Drehgeberbutton) können die 
;*	Zeiten mit Up/Down oder Drehgeber rechts/links ausgewählt werden.
;*************************************************************************************************
;Beispiel
PreTab:	.db	0,10,\
			0,30,\
			1,00,\
			1,30,\
			2,00,\
			2,30,\
			3,00,\
			3,30,\
			4,00,\
			4,30,\
			5,00,\
			5,30,\
			6,00,\
			6,30,\
			7,00,\
			7,30,\
			8,00,\
			8,30,\
			9,00,\
			9,30,\
			0, 0
;*************************************************************************************************
;ISR, alle 1mS
;*************************************************************************************************
ISR:in		s,sreg
	push	temp1
	ldi		temp1,1<<isrx			;ISR-Bit toggeln
	eor		flags,temp1
	sbrc	flags,isrx				;Abwechselnd Tasten abfragen / Display Multiplexen
	rjmp	debounce
	;-----------------------------
	;ISR, Teil 1. Ab hier alle 2 mS
	;-----------------------------
	dec		icnt					;Zähler
	brne	_mux0
	dec		buzz					;Summerzeit -1
	brne	_mux0
	cbr		flags,1<<buzzer			;Summer aus
	;-----------------------
	;Multiplexen vorbereiten
	;-----------------------
_mux0:
	ser		temp1			
	out		PortB,temp1				;Display-Segmente aus
	;--------------------------------------------------------------------------------------------
	;Relais & Summer (an PortD2 & 3, Programmflags an gleicher Stelle) nach dem muxen mitschalten
	;--------------------------------------------------------------------------------------------
	mov		temp1,flags					;temp1 vorbereiten, kommt später zusammen ..
	andi	temp1,1<<relais|1<<buzzer	;..mit dem PNP (gem. Anode) nach PortD
	;--------------------------------------------------------------------------------------------
	;Display Multiplexen
	;-------------------
	;Bei3 Anzeigen *2mS sind das 6mS für einen Durchlauf. Die Muxfreq. ist 1/6mS = 166.6 Hz
	;--------------------------------------------------------------------------------------------
	;--------------------------------------------------------------------------------------------
	sbic	PortD,PD5				;War zuletzt die 3. Anzeige eingeschaltet, 1. Anzeige einschalten
	rjmp	_mux1
	ori		temp1,1<<pd5|1<<pd6		;PNP Transistor, gem. Anode, Stelle 1, Einschalten (PD7=0)
	push    seg0					;Kathoden auf den Stack, erst gem. Anode schalten
	rjmp	exit0
_mux1:
	sbic	PortD,PD7				;War D1 an, D2 einschalten
	rjmp	_mux2
	ori		temp1,1<<pd5|1<<pd7		;Stelle 2(PD6=0)
	push    seg1	   				;Kathoden
	rjmp	exit0
_mux2:
	ori		temp1,1<<pd6|1<<pd7		;Stelle 3(PD5=0)
	push	seg2					;Kann nur noch Stelle 3 sein
exit0:
	out		PortD,temp1				;Alles auf einen Wisch in PortD schreiben
	nop								;Kurz warten (wg. Geisterleuchten)
	nop
	pop		temp1
	out		PortB,temp1
;*****************************************************************************************************
	rjmp	enc1					;Sprung, mS zählen, ISR Ende
;*****************************************************************************************************
;ISR Teil 2. Alle 2 mS
;*****************************************************************************************************
debounce:
;----------------------------------------------------------------------------------------------------
;Tasten 1-3 entprellen & Drehgeber einlesen
;----------------------------------------------------------------------------------------------------
	in		temp1,pinc				;Tasten (PinC 0..2) & Drehimpulsgeber (PinC 3..4) nach Temp1 holen
	;---------------------
	;Taste <Enter>
	;---------------------
	lsr		temp1					;PinC0 (Enter-Taste) ins Carry und in Taste1 schieben
	rol		taste1					;Ist Taste1=0, war der Taster die letzten 8 ISRs gedrückt.
	brcc	db1						;Ist eine 1 (nicht gedrückt) im Carry und eine 0 (= 8* gedrückt)
	brne	db1						;in Taste1, wird das Flankenbit gesetzt.          
	sbr		flags,1<<enter			;Flag (Flanke) setzen, wird in der Main, nach Auswertung wieder gelöscht.
	;----------------------------------------------------------------------------------------------------
	;Um die Repeatfunktion zu aktivieren, muss der Anwender die entspr. Taste gedrückt halten, bis die
	;Repeatzeit LANG (in diesem Beispiel 512 mS) um ist. Wird die Taste weiterhin gehalten wird die Taste
	;andauernd durch die Repeatfunktion gedrückt. Der Intervall wird oben in "rep_kurz" definiert.
	;----------------------------------------------------------------------------------------------------
	;--------------------
	;Taste <-> mit Repeat
	;--------------------
db1:lsr		temp1					;PinC1 (Minus-Taste) ins Carry
	rol		taste2					;und in Taste schieben
	brne	db2						;Taste ist 0 wenn die letzten 8 Durchläufe gedrückt war			
	dec		repeat					;Repeatzähler-1
	brne	rp0						;Wenn Repeatzeit noch nicht abgelaufen, auf neuen Tastendruck testen
	mov		repeat,sechzig			;Repeatwert (kurz) neu laden
	sec								;Tastenflag durch Repeat setzen
rp0:brcc	db2						;Das Carry setzt das Tastenflag durch Repeat oder ersten Tastendruck				
	sbr		flags,1<<down	
	;--------------------
	;Taste <+> mit Repeat
	;--------------------
db2:lsr		temp1					;PinC2 (Plus-Taste) ins Carry .....
	rol		taste3					;wie oben
	brne	db3		
	dec		repeat
	brne	rp1
	mov		repeat,sechzig
	sec
rp1:brcc	db3
	sbr		flags,1<<up	
	;----------------------------------------------------------------------
	;Wenn keine Taste gedrückt ist Repeatwert (1. Tastendruck = lang) laden
	;----------------------------------------------------------------------
db3:tst		taste2
	breq	db4
	tst		taste3
	breq	db4
	clr		repeat			;512 mS (= ca.1/2 Sekunde)
	;-------------------------------------------------------------------
	;Encoder einlesen, ist verbunden mit PinC3 und 4
	;-------------------------------------------------------------------
db4:lsr		temp1			;pinc3 ins Carry...
	rol		enc				;.. und in bit0 
	lsr		temp1			;pinc4 ins Carry
	rol		enc				;und nochmal schieben
	andi	enc,$0f			;die beiden Bits der letzten ISR steht nun in bit2 und 3
	;-----------------		;die neuen Werte in Bit0 und 1
	cpi		enc,0b1011		;bei den folgenden 4 kombis wurde nach links gedreht.
	breq	links
.if	encoder >0
	cpi		enc,0b0100		;Wird nur assembliert wenn oben encoder auf 1 oder 2 gesetzt wird	
	breq	links
.endif
.if	encoder >1				;dito bei 2
	cpi		enc,0b1101
	breq	links
	cpi		enc,0b0010
	breq	links
.endif
	;-----------------
	cpi		enc,0b0001		;rechts
	breq	rechts
.if encoder >0
	cpi		enc,0b0111
	breq	rechts
.endif
.if	encoder >1
	cpi		enc,0b1110
	breq	rechts
	cpi		enc,0b1000
	breq	rechts
.endif
	rjmp	enc1			;bei allen anderen Kominationen wurde nicht gedreht,
rechts:
	inc		richtung
	rjmp	enc1
links:
	dec		richtung
;-------------------------------------------------------------------------------------------------
;Ab hier wieder alle 1 mS
;-------------------------------------------------------------------------------------------------
	;----------------------------------
	;Bei "0:00", Relais aus
	;----------------------------------
enc1:cp		sek,null
	cpc		min,null
	brne	sms
	cbr		flags,1<<relais;
	;-----------------------
	;1 Millisekunde abziehen
	;-----------------------
sms:sub		sekl,eins		;16Bit-Zähler (Millisekunden)-1
	sbc		sekh,null	
	brne	is1
	;----------------------------------------------
	;Zähler neu laden, Sekunde+1
	;----------------------------------------------
	ldi		temp1,low(countms+korrektur);1000 mS in den Zähler
	mov		sekl,temp1
	ldi		temp1,high(countms+korrektur)
	mov		sekh,temp1
	inc		tick					;Sekunde +1
	;--------------------------------
	;ISR Ende
	;--------------------------------
is1:pop		temp1
	out		sreg,s					;Statusbits zurücklesen
	reti							;in der Main weitermachen
;***************************************************************************************************************
;									--- ENDE ISR ---
;***************************************************************************************************************														


;***************************************************************************************************************														
;										Init
;***************************************************************************************************************
reset:
	;-------------------------------------
	;Stack
	;-------------------------------------
	ldi		temp1, LOW(RAMEND)	
	out		SPL, temp1
	ldi		temp1, HIGH(RAMEND)
	out		SPH, temp1
	;-------------------------------------
	;Ports init
	;-------------------------------------
	ldi		temp1,$ff
	out		ddrb,temp1				;Segmente (Kathoden) Ausgang
	sbi		ddrc,pc5				;Dezimalpunkt Ausgang
	ldi		temp1,$3f
	out		portc,temp1				;Pullups Bit 1..5
	ldi		temp1,0b11101100
	out		ddrd,temp1				;gem. Anoden,Summer & Relais = Ausgang
	ldi		temp1,$ff
	out		portd,temp1				;gem. Anoden Aus
	;-------------------------------------
	;Timer1 CTC anwerfen
	;-------------------------------------
	#if defined mega48
		ldi		temp1,high(8000-1)		;Vergleichswert =8000 ergibt
		sts		OCR1AH,temp1			;bei 8MHz genau 1000Hz (ISR alle 1mS)
		ldi		temp1,low(8000-1)
		sts		OCR1AL,temp1
		ldi		temp1,1<<WGM12|1<<CS10	;Prescaler=1 Timer Compare ein	
		sts		tccr1b,temp1
		ldi		temp1,1<<ocie1a			;Interrupt bei Timer Compare ein
		sts		TIMSK1,temp1
	#else
		ldi		temp1,high(8000-1)		;Vergleichswert =8000 ergibt
		out		OCR1AH,temp1			;bei 8MHz genau 1000Hz (ISR alle 1mS)
		ldi		temp1,low(8000-1)
		out		OCR1AL,temp1
		ldi		temp1,1<<WGM12|1<<CS10	;Prescaler=1 Timer Compare ein	
		out		tccr1b,temp1
		ldi		temp1,1<<ocie1a			;Interrupt bei Timer Compare ein
		out		TIMSK,temp1
	#endif			
	;-------------------------------------
	;Programmvariable init
	;-------------------------------------
	ldi		temp1,rep_kurz			;Konstante laden
	mov		sechzig,temp1			
	ldi		temp1,1
	mov		eins,temp1
	clr		null
	clr		flags
	clr		enc
	ldi		temp1,$ff
	mov		taste1,temp1
	mov		taste2,temp1
	mov		taste3,temp1
pm:	cbi		portc,pc5				;Dezimalpunkt ein
    rcall   load_eep
pm1:andi	flags,1<<buzzer			;Variable
	clr		richtung
	rcall	printtime				;Zeit aufs Display
	sei								;ISR Los
;************************************************************************************************
;*	Hauptschleife.
;************************************************************************************************
main:
	tst		richtung				;Drehimpulsgeber gedreht ?
	brne	m0						;Wenn ja, Sprung
	sbrc	flags,up				;Taste Plus
	rjmp	m1
	sbrc	flags,down				;Taste Minus
	rjmp	m2
	sbrc	flags,enter				;Taste Enter, (oder Taste am Drehgeber)
	rjmp	m3						;Zählen
	rjmp	main					;Nix passiert, wieder nach oben
;************************************************************************************************
;*	Zeiteinstellung
;************************************************************************************************
	;---------------------------------------------------------------------------
	;Drehgeber, Richtung bestimmen
	;---------------------------------------------------------------------------
m0:	brpl	m01						;Bei positiv, Rechtsdreh
	;----------------------
	;Es wurde links gedreht
	;----------------------
	inc		richtung				;Den Linksdreh abziehen
	rjmp	m2						;Selbe Funktion wie Minustaste
	;-----------------------
	;Es wurde rechts gedreht
	;-----------------------
m01:dec		richtung				;Den Rechtsdreh abziehen
	;-----------------------
	;Taste Plus gedrückt
	;-----------------------
m1:	cbr		flags,1<<up				;Tastenflag löschen
	rcall	inctime					;Sekunde +1
	rjmp	m21
	;-----------------------
	;Taste Minus gedrückt
	;-----------------------
m2:	cbr		flags,1<<down			;Tastenflag löschen		
	cp		sek,null				;Sind wir schon bei "0.00"?
	cpc		min,null
	breq	main
	rcall	dectime					;Sekunde -1
m21:rcall	printtime				;Neue Zeit aufs Display
	rjmp	main
	;----------------------------------------------
	;Auf Doppelclick oder langen Tastendruck testen
	;----------------------------------------------
m3:	cbr		flags,1<<enter			;Enter löschen
	ldi		temp1,200				;In 0,4 Sekunden testen ob Enter nochmal gedrückt wurde
	mov		icnt,temp1
m31:tst		icnt
	brne	m31
	sbrc	flags,enter				;Bei Doppelclick, Sprung Minuten einstellen
	rjmp	m36
	tst		taste1					;Wenn taste=0 und Tastenflag=0, dann wurde die Taste gehalten
	breq	preset_time
	rjmp	cnt						;Ansonsten Count Down starten
;-----------------------------------------------------------------------------------------
;Zeit aus Tabelle
;-----------------------------------------------------------------------------------------
preset_time:
	rcall	beep
	clr		temp2
prt1:
	clr		richtung
	cbr		flags,1<<up|1<<down
	ldi		zl,low(PreTab<<1)		;Z auf Tabelle im Flash
	ldi		zh,high(PreTab<<1)
	mov		temp1,temp2				;temp2 ist index
	add		temp1,temp1				;*2, da 2 Byte (Minuten,Sekunden) in der Tab.
	add		zl,temp1
	adc		zh,null
	lpm		min,z+					;Tabeintrag -> Variable
	lpm		sek,z
	cp		min,null				;0 = Tabellenende
	cpc		sek,null
	brne	prt4
	dec		temp2					;Wenn letzter Tabeintrag, Index-1
	rjmp	prt1					
prt4:
	push	temp2
	rcall	printtime				;Variable auf Display				
	pop		temp2
	;------------------------------
	;Tasten und Drehgeber auswerten
	;und entspr. verzweigen
	;------------------------------
prt2:
	sbrc	flags,enter				
	rjmp	rpm1			;Bei Enter, Sprung zur Main
	sbrc	flags,up
	rjmp	prt3			;Nächster Tabeintrag
	sbrc	flags,down
	rjmp	prt5			;Vorhergehender Tabeintrag
	tst		richtung
	breq	prt2			;Nix passiert, neue Runde
	brpl	prt3
prt5:
	dec		temp2			;Index -1
	brpl	prt1
prt3:
	inc		temp2			;Index +1
	rjmp	prt1
rpm1:
	rcall	beep
	rjmp	pm1
;---------------------------------------------------------------------------------
;Minuten separat stellen
;---------------------------------------------------------------------------------
m36:cbr		flags,1<<enter
	ldi		seg1,g_					;Segment g (Minuszeichen) in die Sekundenanzeige
	ldi		seg2,g_
	rcall	beep
	;------------------------------------------------------------------
	;Drehimpulsgeber und Tasten auswerten und Minuten hoch/runterzählen
	;------------------------------------------------------------------
m35:clr		richtung				;Drehgeber Reset
	cbr		flags,1<<up|1<<down		;Tasten Reset
m32:rcall	printm					;Minuten auf Display
	sbrc	flags,enter
	rjmp	rpm1						;Bei Enter, Sprung Main
	sbrc	flags,up
	rjmp	m33						;Taste Plus, Minuten +1
	sbrc	flags,down
	rjmp	m34						;Taste Minus, Minuten -1
	tst		richtung
	breq	m32						;Drehgeber =0, neue Runde
	brpl	m33						;Drehgeber positiv, Minuten+1
	;-----------------------		;ansonsten Minuten -1
	;Minuten Down
	;-----------------------
m34:dec		min
	brpl	m35
	ldi		min,0
	rjmp	m35
	;-----------------------
	;Minuten Up
	;-----------------------
m33:inc		min
	cpi		min,10
	brne	m35
	ldi		min,9
	rjmp	m35
;************************************************************************************************
;*	Zählen
;************************************************************************************************
	;-----------------------
	;Timer vorbereiten
	;-----------------------
cnt:cp		sek,null				;Sind wir schon bei "0.00"?
	cpc		min,null
	breq	wt1						;Bei 0:00, nix machen
	cbr		flags,1<<enter			;Tastenflag löschen
    rcall   Save_EEP
	cli								;ISR STOP
	clr		tick					;Alle ISR Zähler auf Startwert setzen
	ldi		temp1,low(countms+korrektur)
	mov		sekl,temp1
	ldi		temp1,high(countms+korrektur)
	mov		sekh,temp1
	sbr		flags,1<<relais			;Relais ein
	sei								;ISR Los
	;-----------------------
	;Timer Count-down
	;-----------------------
wt:	sbrc	flags,enter				;Enter gedrückt?
	rjmp	wt1						;Wenn ja, Unterbrechung
	tst		tick					;Ist eine Sekunde vergangen ?
	breq	wt						;Wenn nein, weiter pollen
	dec		tick					;Die Sekunde von der ISR-Variable abziehen
	rcall	dectime					;Zeit-1
	rcall	printtime				;Neue Zeit aufs Display
	rcall	testbeep				;Testet ob Count down <6, wenn ja piepsen
	cp		sek,null				;Sind wir schon bei "0.00"?
	cpc		min,null
	brne	wt
	;-----------------------
	;Timer Abgelaufen
	;-----------------------
	sbr		flags,1<<buzzer			;Summer einschalten (ISR prüft Flag)
	ldi		temp1,buzztime			;Tondauer in Sekunden
	clr		icnt					;ISR-Zähler, geht alle 512mS auf 0
	mov		buzz,temp1
	sbi		portc,pc5				;DP aus			
.if	scroll	==0
	ldi		seg0,_A					;"AUS" aufs Display				
	ldi		seg1,_U
	ldi		seg2,_S
wt2:sbrs	flags,enter				;Mit Enter gehts zurück
	rjmp	wt2
	rjmp	pm						;Setzt Variable zurück und springt ins Main
.else
	rjmp	scrolling
.endif
wt1:rjmp	pm1						;dito. nur ohne Zeitpreset
;************************************************************************************************
;	Unterprogramme
;************************************************************************************************
Beep:
	sbr		flags,1<<buzzer			;Buzzer in ISR einschalten
	mov		icnt,sechzig			;60 ISRs *2 mS eingeschaltet lassen
	mov		buzz,eins				;Wird decrementiert (=0)
	ret
Testbeep:
	tst		min
	brne	exbep
	cpi		sek,6					;Wenn die Zeit <6, Piepsen
	brcs	beep
exbep:
	ret
;---------------------------------------------------
;Zeit -1 Sekunde
;---------------------------------------------------
dectime:
	dec		sek						;Sekunden -1
	brpl	dt2
	ldi		sek,overf-1				;Bei Unterlauf, Sekunden=59 Minuten-1
	dec		min
dt2:ret
;---------------------------------------------------
;Zeit +1 Sekunde
;---------------------------------------------------
inctime:
	inc		sek						;Sekunden+1
	cpi		sek,overf				;Bei 60, Sekunden=0 Minuten+1
	brne	it1
	clr		sek
	inc		min
	cpi		min,10					;Bei Minuten=10, Maximalzeit "9:59" setzen 
	brne	it1
	ldi		min,9
	ldi		sek,overf-1
it1:ret
;---------------------------------------------------
;Zeit aufs Display
;---------------------------------------------------
printtime:
	;---------------------------------------------------
	;Sekunden
	;--------
	;Die Ziffer in sek (0..59) durch 10 dividieren
	;Der Quotient sind die Zehner
	;Rest der Division sind die Einer
	;---------------------------------------------------
	mov		temp1,sek			
	ser		temp2					;Zehner = -1
pt1:inc		temp2					;Zehner +1				
	subi	temp1,10 				;Rest -10
	brcc	pt1						;Solange Wiederholen bis Unterlauf
	subi	temp1,-10				;Rest +10
	;---------------------------------------------------
	;Sekunden 10er ausgeben
	;---------------------------------------------------
	ldi		zl,low(segtab<<1)
	ldi		zh,high(segtab<<1)
	add		zl,temp2
	adc		zh,null
	lpm		seg1,z
	;---------------------------------------------------
	;Sekunden 1er ausgeben
	;---------------------------------------------------
	ldi		zl,low(segtab<<1)
	ldi		zh,high(segtab<<1)
	add		zl,temp1
	adc		zh,null
	lpm		seg2,z
	;---------------------------------------------------
	;Minuten
	;---------------------------------------------------
Printm:
	ldi		zl,low(segtab<<1)		;Z auf 7Segmenttabelle
	ldi		zh,high(segtab<<1)
	add		zl,min					;Minuten (0..9) addieren
	adc		zh,null
	lpm		seg0,z					;7Segmentcode Minuten ins die erste Anzeige
	ret



Load_EEP:
    clr     temp2
    rcall   ReadEE
    mov     min,temp1
    inc     temp2
    rcall   ReadEE
    mov     sek,temp1
    ret

Save_EEP:
    clr     temp2
    mov     temp1,min
    rcall   WriteEE
    inc     temp2
    mov     temp1,sek
    rcall   WriteEE
    ret


;------------------------------------
;EEprom	lesen Adr.temp2 Daten temp1 (1 Byte)
ReadEE:								;Adresse 0x01
nxtEE:	sbic	EECR,EEWE			;Bereit ?
		rjmp	nxtEE
		out		EEARL,temp2			;Adresse setzen
		sbi		EECR,EERE			;ReadEnable in Controllregister
		in		temp1,EEDR			;Daten Holen
		ret
;------------------------------------
;EEprom	schreiben Adr.temp2 Daten temp1 (1 Byte)
WriteEE:
		cli
WriteEE1:
		sbic	EECR,EEWE			;Bereit ?
		rjmp	WriteEE1
		out		EEARL,temp2			;Adresse
		out		EEDR,temp1			;Daten
		cli
		sbi		EECR,EEMWE			;Master Write Enable
		sbi		EECR,EEWE			;Write Enable
		sei
		ret
;**********************************************************************************************
;Spielerei am Ende des Count Down
;**********************************************************************************************
.if	scroll ==1
	;------------------------------------------------
	;Textscrolling
	;------------------------------------------------
scrolling:
	ldi		temp1,120
	ldi		zl,low(text<<1)				;Z-Pointer auf Text im 7Segment Code
	ldi		zh,high(text<<1)
sc1:lpm		seg0,z+						;3 Chars auf Display
	lpm		seg1,z+
	lpm		seg2,z
	tst		seg2						;Ende des Text erreicht ?
	breq	animation					;Wenn ja, Sprung
	sbiw	z,1							;Z auf nächsten Char
	mov		icnt,temp1
sc2:tst		icnt
	brne	sc2
	sbrs	flags,enter					;Wurde Taste gedrückt ?
	rjmp	sc1							;Wenn nein, scrollen
	rjmp	pm							;Srung in die Main (vorher INIT)
	;------------------------------------------------
	;Anim-Sequenzen spielen
	;------------------------------------------------
animation:
	inc		temp2						;Nach der Laufschrift abwechselnd Snake oder Ani spielen
	cbr		temp2,$fe					;Bit0 in temp2 entscheidet was gespielt wird
	breq	an0
	ldi		zl,low(snake<<1)			;Z auf Sequenz
	ldi		zh,high(snake<<1)
	rjmp	an1
an0:
	ldi		zl,low(ani<<1)				;Z auf Sequenz
	ldi		zh,high(ani<<1)
an1:lpm		seg0,z+						;3 Bytes aus der Tab. ins Display
	lpm		seg1,z+
	lpm		seg2,z+
	lpm		icnt,z+
	tst		seg2						;Ende ?
	breq	scrolling					;Wenn ja, Text scrollen
an2:tst		icnt
	brne	an2
	sbrs	flags,enter					;Taste ?
	rjmp	an1							;Wenn nein; Weiterspielen
	rjmp	pm							;Zur Main
.endif
;**********************************************************************************************
;Ende Code
;**********************************************************************************************
;Segment | Portpin
;-----------------------------------------------------------------------------------------------
;	a		6		|-a-|	Die 7 Segmenttabelle (a..g) ist dem Layout angepasst
;	b		5		f   b	Durch den gemeinsamen Anodenanschluss, ist eine Null am Port nötig
;	c		4		|-g-|	damit ein Segment leuchtet
;	d		3		e   c
;	e		2		|-d-|
;	f		1
;	g		0
;-------------------------------------------------------------------
;Die Zeichen 0..F als 7Segmentcode
segtab: 
.db $81,  $CF,\
	$92,  $86,\
	$CC,  $A4,\
	$A0,  $8F,\
	$80,  $84,\
	$88,  $E0,\
	$B1,  $C2,\
	$B0,  $B8
;-------------------------------------------
;Animsequenz
;-------------------------------------------
.equ	a_ = 0b0111111
.equ	b_ = 0b1011111
.equ	c_ = 0b1101111
.equ	d_ = 0b1110111
.equ	e_ = 0b1111011
.equ	f_ = 0b1111101
.equ	g_ = 0b1111110
;-------------------------------------------
.if	scroll ==1			;Nur Assemblieren, wenn scroll =1
;**************************************************************************************************
;Jede Zeile enthält 4 Bytes. Die ersten 3 Einträge werden ins Display geschrieben.
;Das 4. Byte enthält die Zeit (*2mS) wie lange die Zeile angezeigt wird.
;"_" = Leerzeichen, "a_" = Segment a usw.
;Man kann auch odern z.B "d_&f_&c_". Da invers mit Log. AND, das Bsp. zeigt die Segmente d,f und c
;Man kann auch (fast alle) Chars einfügen (Equates unten)
;Beispiel"_O,_F,_F,200,\" (Unterstrich vorn) schreibt 0,4 Sekunden "OFF" auf das Display
;**************************************************************************************************
;Tabelle für das Daumenkino
ani:
.db	d_,_,_,75,\
	d_,d_,_,75,\
	d_,d_,d_,75,\
	g_,g_,g_,75,\
	a_,a_,a_,75,\
	g_,g_,g_,75,\
	a_,g_,d_,75,\
	_,g_&a_&d_,_,75,\
	d_,g_,a_,75,\
	g_,g_,g_,75,\
	a_,g_,d_,75,\
	_,g_&a_&d_,_,75,\
	d_,g_,a_,75,\
	g_,g_,g_,75,\
	a_,g_,d_,75,\
	_,g_&a_&d_,_,75,\
	d_,g_,a_,75,\
	g_,g_,g_,75,\
	a_,g_,d_,75,\
	_,g_&a_&d_,_,75,\
	d_,g_,a_,75,\
	g_,g_,g_,75,\
	a_,a_,a_,75,\
	g_,g_,g_,75,\
	d_,d_,d_,75,\
	d_,d_,d_,75,\
	d_,d_,_,75,\
	d_,_,_,130,\
	_,_,_,130,\
	d_,_,_,130,\
	_,_,_,130,\
	d_,_,_,130,\
	_,_,_,130,\
	d_,_,_,130,\
	_,_,_,130,\
	_A,d_,_,130,\
	_A,_,_,40,\
	_A,_U,d_,130,\
	_A,_U,_,40,\
	_A,_U,_S,255,\
	_A,_U,_S,255,\
	_A,_U,d_,130,\
	_A,_U,_,40,\
	_A,d_,_,130,\
	_A,_,_,40,\
	d_,_,_,130,\
	_,_,_,130,\
	d_,_,_,130,\
	_,_,_,130,\
	d_,_,_,130,\
	_,_,_,130,\
	e_,_,_,50,\
	f_,_,_,50,\
	a_,_,_,50,\
	_,a_,_,50,\
	_,_,a_,50,\
	_,_,b_,50,\
	_,_,c_,50,\
	_,_,d_,50,\
	_,d_,_,50,\
	d_,_,_,50,\
	e_,_,_,50,\
	f_,_,_,50,\
	a_,_,_,50,\
	_,a_,_,50,\
	_,_,a_,50,\
	_,_,b_,50,\
	_,_,g_,50,\
	_,g_,_,50,\
	g_,_,_,50,\
	e_,_,_,50,\
	d_,_,_,50,\
	_,d_,_,50,\
	_,_,d_,50,\
	_,_,c_,50,\
	_,_,g_,50,\
	_,g_,_,50,\
	g_,_,_,50,\
	e_,_,_,50,\
	d_,_,_,50,\
	_,d_,_,50,\
	_,_,d_,130,\
	_,_,_,2,\
	_,_,d_,130,\
	_,_,_,130,\
	_,_,d_,130,\
	_,_,_,130,\
	_,_,d_,130,\
	0,0,0,0
snake:
.db	d_,_,_,130,\
	_,_,_,130,\
	d_,_,_,130,\
	_,_,_,130,\
	d_,_,_,130,\
	_,_,_,130,\
	e_,_,_,130,\
	g_,_,_,130,\
	c_,_,a_,130,\
	_,d_,a_,75,\
	_,c_,a_,75,\
	_,b_,a_,75,\
	_,_,a_,75,\
	_,_,a_&b_,75,\
	_,_,b_&c_,75,\
	_,_,c_&d_,75,\
	_,d_,d_,75,\
	d_,d_,_,75,\
	d_&e_,_,_,75,\
	g_&e_,_,_,75,\
	g_&c_,_,_,75,\
	c_&d_,_,_,75,\
	d_&e_,_,_,75,\
	g_&e_,_,_,75,\
	g_&c_,_,_,75,\
	c_&d_,_,_,75,\
	d_&e_,_,_,75,\
	g_&e_,_,f_,75,\
	g_&c_,_,f_,75,\
	c_&d_,_,f_,75,\
	d_&e_,_,f_,75,\
	e_&f_,_,f_,75,\
	f_&a_,_,f_,75,\
	a_,a_,f_,75,\
	_,a_,f_,75,\
	_,a_,f_&e_,75,\
	_,_,f_&e_&d_,75,\
	_,_,c_&e_&d_,75,\
	_,_,c_&b_&d_,75,\
	_,_,c_&b_&a_,75,\
	_,a_,b_&a_,75,\
	a_,a_,a_,75,\
	a_&f_,a_,_,75,\
	a_&f_&a_,_,_,75,\
	f_&a_&g_,_,_,75,\
	f_&g_,g_,_,75,\
	g_,g_,g_,75,\
	_,g_,g_&b_,75,\
	_,_,g_&b_&a_&d_,75,\
	_,a_,a_&b_&d_,75,\
	_,a_&f_,a_&d_,75,\
	_,a_&f_&e_,d_,75,\
	_,d_&f_&e_,d_,75,\
	_,e_&d_,d_,75,\
	_,d_,d_&c_,75,\
	_,_,d_&c_&g_,75,\
	_,_,d_&c_&g_&e_,75,\
	_,_,_,130,\
	_,_,d_&c_&g_&e_,130,\
	_,_,_,130,\
	_,_,d_&c_&g_&e_,130,\
	_,_,_,130,\
	_,_,d_&c_&g_&e_,130,\
	_,_,_,130,\
	_,_,d_&c_&g_&e_,130,\
	_,_,d_&g_&e_,130,\
	_,_,d_&e_,130,\
	_,_,d_,130,\
	_,_,_,255,\
	_,_,_,255,\
	_,_,d_,130,\
	_,_,_,130,\
	_,_,d_,255,\
	0,0,0,0
;----------------------------------------------------------------------------------------------
;Scrolltext mit Null am Ende
;---------------------------
text:	.db	_,_,_,_A,_U,_S,_,_,_O,_F,_F,_,_,_F,_ii,_n,_ii,_t,_oo,_,_,_,_,0
//		.db _,_,_,_P,_u,_s,_h,_,_b,_uu,_t,_t,_oo,_n,_,_,_,0
;----------------------------------------------------------------------------------------------
.endif
;Equates der Chars
.equ _	 =  0xFF	// Space
.equ _0  = 	0x81 	// 0
.equ _1  =  0xCF	// 1
.equ _2  =  0x92	// 2
.equ _3  =  0x86	// 3
.equ _4  =  0xCC	// 4
.equ _5  =  0xA4	// 5
.equ _6  =  0xA0	// 6
.equ _7  =  0x8F	// 7
.equ _8  =  0x80	// 8
.equ _9  =  0x84	// 9
.equ _A  =  0x88	// A
.equ _B  =  0xE0	// B
.equ _C  =  0xF2	// C
.equ _D  =  0xC2	// D
.equ _E  =  0xB0	// E
.equ _F  =  0xB8	// F
.equ _gg =  0x84	// g
.equ _G  =  0xA1	// G
.equ _hh =  0xE8	// h
.equ _H  =  0xC8	// H
.equ _ii =  0xEF	// i
.equ _I  =  0xCF	// I
.equ _J  =  0xC3	// J
.equ _L  =  0xF1	// L
.equ _n  =  0xEA	// n
.equ _oo =  0xE2	// o
.equ _O  =  0x81	// O
.equ _P  =  0x98	// P
.equ _q  =  0x8C	// q
.equ _r  =  0xFA	// r
.equ _S  =  0xA4	// S
.equ _t  =  0xF0	// t
.equ _uu =  0xE3	// u
.equ _U  =  0xC1	// U
.equ _Y  =  0xD8	// Y

.eseg
.db     1,23

