;****************************************************************
;                     McCoi II- Ketten Öler                     ;
;                                                               ;
;          AVR 90S2313, 4 MHz, externer Oszillator              ;
;                                                               ;
;      (c) 2001 MDvP                   mailto:MDvP@gmx.de		;
;      Änderungen für 90S2313: 12/2001 T. Ostermann             ;
;      Version 1.04   28.07.2002                                ;
;                                                               ;
;                                                               ;
;      Version 1.10   10.08.2003 Steffen Koberitz               ;
;      - Radkonstante auf 333m erhöht                           ;
;      - Bereich von 2650m bis 7650m erweitert                  ;
;      - Kontrolle Regenfunktion auf PD1 (bisher frei) gelegt   ;
;      - Pumpimpuls-Kontrolle auf PD0 (bisher frei) gelegt      ;
;        damit kann Kontrollschaltung ohne Relais angesteuert!  ;
;
; Version 1.20 19.09.2004 von Steffen Koberitz
; - Speziell für den neuen vergoldetetn Regensensor wurde
;   die Abfrage nach dem Regenstatus angepaßt. Sonst keine
;   Änderungen
;
; - Version 1.21 
;   vom 13.02.2005 by Steffen Koberitz
; - Bug beseitigt: Abfrage für Regenmodus war vertauscht,
;   nun korrekte Abfrage
;   Lieferungen ab inkl. Montag 14.02.05 haben die neue, 
;   korrekte Version!
;
;****************************************************************
; Version 1.22 
; - vom 22.12.2005 von Steffen Koberitz
;   Die Externe Regen-LED wird an PD1 angeschlossen
;   Der Minus-Pol der LED muß an PD1 
;   und der Plus-Pol an VCC (+5Volt) -> Vorwiderstand nicht vergessen!
;   Damit glimmt die LED nicht mehr wegen Leckstrom
;   Die LED wird auch im Sleepmodus abgeschaltet! :-)
; - Pumpensteuerzeit von bisher 50ms auf 150ms verlängert
;   damit sollte es keine Viskositätsprobleme mehr geben
;   ACHTUNG: im Testmodus weiterhin 50ms, im Betriebsmodus 150ms!!!
;
; - 14.02.2006 von Steffen Koberitz
;   BugFix: Externe Regen-LED wurde falsch angesteuert 
;	    (leuchtet bei Trockenheit)
;   Nun korrekt: Externe Regen-LED leuchtet bei Nässe!
;
; - 15.04.2006 von Steffen Koberitz
;   Anzahl der Pumpimpulse über "Cross-Schalter" an PD0 gegen Masse
;   wählbar: üblicherweise nur ein Impuls. Im Cross-Mode 8 Impulse
;   BETA!!!
;   Pumproutine wurde hierzu aus der Interruptroutine ausgegliedert!
; - 23.12.2006 Peter Büttner	
;   Bladefunktion eingefügt für BMW F650 GS Tachosignalabgriff
;
; - 06.01.2007 Steffen Koberitz
;   Umbenennung in "STK-T-03", damit die Nomenklatur beibehalten wird.
;   Löschen der alten Kommentare und Update auf McCoi-Platine 2.5.
;   LED für Crossmode auf PA0 gelegt: Schließe LED an VCC (PA0 als GND)
;   -> ist der Crossmode (8 Pumpimpulse) aktiv, leuchtet die LED.
;   die Konstante "Tachopulse" ist bei Reed-Betrieb auf 1 zu setzen!
;   Für andere Bikes kann sie angepaßt werden (z.B. bei Bandit auf 12).
;
; - 11.06.07, Martin Kirsch
;	Changelog kann im McCoi-Forum nachgelesen werden:
;	http://www.mccoi-forum.de/viewtopic.php?t=724
;	Stichworte:
;	- Extraölen nach Regen
;	- Notlaufmodus
;	- Geschwindigkeitsprogression
;	- Regenmodusverkürzung abhängig von Hex-Schalterstellung
;	- Programm um- und aufgeräumt
;	- Sleepmode im Ausnahmezweig (geschalteter Reed) ohne Controller-Reset
;	- Zusätzliche Konstanten, um Programm auf eigene Bedürfnisse anzupassen
;
; - 22.08.07, Martin Kirsch
;	Teachmodus hinzugefügt:
;	- McCoi kann Anzahl Tachopulse und Radkonstante lernen, kein Programmieraufwand mehr nötig
;	Wie funktionierts?
;	- McCoi anschließen
;	- Hexschalter auf eine beliebige Stellung drehen, AUSSER Hex0
;	- 2 Sekunden den Taster auf der Platine drücken -> Reed-LED auf der Platine leuchtet auf
;	  -> Teachmodus Tachopulse aktiv
;	- jetzt 10mal das Rad drehen, welches die Impulse liefert
;	- wieder 2 Sekunden den Taster drücken -> Reed-LED erlischt, Regen-LED leuchtet auf
;	  -> gelernte Tachokonstante wird im EEPROM gespeichert und ab sofort für
;		 die Ermittlung der Ölintervalle genutzt.
;	  -> Teachmodus Radkonstante aktiv
;	- jetzt möglichst exakt 1000 Meter fahren
;	- nochmal 2 Sekunden den Taster drücken -> Regen-LED erlischt
;	  -> Teachmodus deaktiviert, gelernte Radkonstante wird im EEPROM gespeichert und ab sofort für
;		 die Ermittlung der Ölintervalle genutzt.
;	Details: http://www.mccoi-forum.de/viewtopic.php?t=870
; 	ToDo: warten auf Bugreports
;****************************************************************
;****************************************************************

.include "tiny2313.inc"		; Definitionen für den tiny2313

.CSEG								; Code Segment

; -----Interrupts
.ORG 	RSTaddr
		rjmp	Reset				; Program Start
.ORG 	INT0addr
		rjmp	Reed				; Reed Impuls
.ORG	OC1Aaddr
		rjmp	timer1_comp_match	; Timer/Counter1 Compare Match A     
.ORG	OVF1addr
		reti						; Timer1 Overflow Handler
.ORG	OVF0addr
		reti						; Timer0 Overflow Handler
.ORG	ACIaddr
		reti
.ORG	OC0Aaddr
		rjmp	timer0_comp_match	; Timer/Counter0 Compare Match A
.ORG    OC0Baddr
		rjmp	timer0_comp_match_b	; Timer/Counter0 Compare Match B
.ORG	WDTaddr
		reti						; Watchdog Interrupt

.db $28,$63,$29,$20					;(c) 
.db $32,$30,$2e,$30,$37,$2e,$30,$32	;20.07.02
.db $20,$4D,$44,$76,$50,$20 		; MDvP 


;############################################################################
;##                                                                        ##
;##                   Anfang Konfigurationsabschnitt                       ##
;##                                                                        ##
;############################################################################

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Radkonstanten für 333m     #
.equ	Tachopulse	=1		; Anzahl Impulse pro Raddrehung
.equ	Rad			=168	; wie oft dreht sich das Rad während 333 m (quasi 333 / Radumfang)
							; 168 für 180/55-17 (Radumfang ca. 1,98 m)
.equ	ReedDelay	=15		; Delay zum Ausfiltern von Doppelimpulsen
							; des Reedsensors, Angabe in Millisekunden
							; maximal sind 55 ms möglich, Werte über 25-30 ms wenig sinnvoll
							; eine Radumdrehung bei 300 km/h und 2 Meter Radumfang dauert ca. 24 ms
.equ	Delay_automatic	=2		; Wert für die automatische Umschaltung Delay on/off
.equ	Intervall = 333
.equ	Hex_Offset = 8
#define Force_ReedDelay_On (0)
#define Force_ReedDelay_Off (0)
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;Einstellungen fürs "Nach dem Regen Extraölen"
;für die Strecken bitte nur Werte >0 verwenden
.equ	RStrecke	=6		; Mindeststrecke Regen in km
.equ	TStrecke	=1		; Mindeststrecke Trocken in km
.equ	Pumpstoesse =6		; nach mindestens $RStrecke Regen und anschließend $TStrecke Trockenheit
							; werden $Pumpstoesse ausgelöst, jeweils einer alle 333 Meter
							; ".equ Pumpstoesse = 0" setzen um Extraölen nach Regen zu deaktivieren
#define Enable_ExtraOelen (1)
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Einstellungen für den Notlaufmodus
; Zeitangaben in 15-Sekunden-Intervallen, d.h. eine Zeit von 1 Minute entspricht einem Wert von 4
; Maximalwert 255 nicht überschreiten und bitte nur Werte >0 verwenden
; NoSignal kann nicht kleiner sein als "NotIntervall"
; Update, 29.04.07:
; NotIntervall und NoSignal können jetzt auch dynamisch (abhängig von Hex-Schalterstellung)
; eingestellt werden. Dazu "NotIntervall" auf 0 setzen.
; Das Ölintervall entspricht dann ungefähr der Zeit, die man bei 100 km/h für die
; am Hexschalter eingestellte Strecke benötigt. Dabei wird auch der Regensensor berücksichtigt.
; Bei dynamischer Einstellung wird dann bei "NoSignal" auch keine feste Zeit mehr angegeben,
; sondern ein Vielfaches von Notintervall. NoSignal muß mindestens 1 betragen. Also z.B.
; .equ NoSignal			=4
; .equ NotIntervall		=0
; -> die Länge von "Notintervall" wird dynamisch, abhängig vom Hex-Schalter _und_ Regensensor
; berechnet, und die berechnete Zeit muß 4mal verstreichen (man verliert also bei normalem Tempo
; ca. 3 Pumpstöße, beim 4. Mal wird schon geölt), bevor der Controller in den Notlaufmodus geht
.equ	NoSignal	=40		; Zeit mit Zündung an und ohne Reed-Signal
.equ	NotIntervall=8		; Pumpintervall im Notbetrieb
#define Enable_Notlauf (0)
#define	Enable_BlinkNotlauf (1)	; auf 0 setzen, um das Blinken der Regen-LED im Notlauf zu deaktivieren
#define Enable_Notlauf_Dynamisch (1)
.equ	Sleepmode	=4		; Zeit bis Sleepmode, ebenfalls vielfache von 15 Sekunden (wie bei "NoSignal" und "NotIntervall")
							; sollte sinnvollerweise kleiner als "NoSignal" sein, sonst geht der McCoi in den Notlauf,
							; anstatt einzuschlafen
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<



;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Einstellungen Pumpe:
; - Anzahl Pumpimpulse (Normal, Regen, Cross, max. Pumpstöße im Testmode)
; - Dauer der Pumpimpulse + Pause im Normal- und Testmode
.equ PumpCross		=6		; Anzahl Pumpstößte im Crossmode
.equ WegCross		=75		; Angabe der Wegstrecke im CrossMode, x% der normalen Wegstrecke
							; WegCross=50 -> im Crossmode ist Wegstrecke nur 50% der normalen Wegstrecke
.equ PumpNormal		=1		; im Normalmode 1 Pumpstoß

.equ WegRegen		=66		; Angabe der Wegstrecke im RegenMode, x% der normalen Wegstrecke
.equ PumpRegen		=2		; Pumpstöße im Regen
.equ RegenDelay		=5		; mindestzeit Regen vor Umschalten in Sekunden

#define Add_Rain (0)		; 1: Pumpstöße Regen zusätzlich zu den normalen ausführen
							; 0: Pumpstöße Regen anstatt der normalen ausführen	

.equ PumpTest		=50		; maximale Anzahl Pumpstöße im Testmode

.equ PumpOnTest		=50		; Einschaltzeit Pumpe im Testmodus (Hex0), max 255, Angabe in Millisekunden
.equ PumpOffTest	=50		; Ausschaltzeit Pumpe im Testmodus (Hex0), max 255, Angabe in Millisekunden

.equ PumpOn			=250	; Einschaltzeit Pumpe im Betriebsmodus, max 255, Angabe in Millisekunden
.equ PumpOff		=250	; Ausschaltzeit Pumpe im Betriebsmodus, max 255, Angabe in Millisekunden
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Einstellungen geschwindigkeitsabhängiges Ölen
;
; Geschwindigkeiten (0 bis maximal 255 km/h) in die Tabelle eintragen
; und dazu einen Wert, wieviel Prozent die Streckenlänge bei dieser Geschwindigkeit betragen soll
; Prozentwert sollte üblicherweise zwischen 0 (Pumpintervalle auf 0% verkürzt) und 100 (keine Verkürzung) liegen.
; Werte über 100 (Verlängerung der Pumpintervalle, z.B. bei niedrigen Geschwindigkeiten) sind auch möglich,
; ABER: Radkonstante * Prozentwert kann nicht größer als 255 werden.
; bei ca. 150% Verlängerung ist für die übliche Radkonstante von 168 also Schluß:
; 168 * 150% = 252
;
; eine gültige Tabellenzeile besteht aus
;
; .db	Geschwindigkeit, Prozentwert
;
; wenn dann schneller als "Geschwindigkeit" gefahren wird, beträgt die Streckenlänge zwischen
; den Pumpstößen nur noch den entsprechenden Prozentwert der normalen Streckenlänge
;
; Bsp:
; .db	130, 75
;
; Hexschalter steht auf 7 -> normal 5 km zwischen 2 Pumpstößen
;
; Geschwindigkeit > 130 km/h -> nur noch 75% von 5 km = 3,75 km zwischen 2 Pumpstößen

; Die Tabelle kann quasi beliebig erweitert werden (solange noch Speicherplatz vorhanden,
; aktuell ist noch für über 200 Einträge Platz), zu beachten aber: die Geschwindigkeiten müssen
; der Größe nach sortiert sein, damits ordentlich funktioniert
; für Geschwindigkeiten, die unterhalb des kleinsten in der Tabelle angegeben Geschwindigkeitswertes liegen,
; erfolgt keine Wegveränderung

#define Enable_SpeedProgression (1)	; auf 1 setzen, um geschwindigkeitsabhängiges Ölen zu aktivieren
Speedprogression:
;	Geschwindigkeit		%wert Streckenlänge
.db 0, 120
.db 50, 100
.db 100, 94
.db 140, 87
.db 170, 80
.db 200, 72
.db 220, 64
.db 240, 55
end_speedprogression:	; diese Zeile nicht anfassen, ist wichtig für das Erkennen des Tabellenendes
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<



;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;Einstellungen für diverse LED-Blinkereien
; jeweils auf 1 setzen, um die Funktion zu aktivieren
#define Enable_LED_Test (1)				; alle LEDs bei Einschalten bzw. Aufwachen aus dem 
										; Sleepmode mal aufleuchten lassen
										; Regen/Cross-LED blinken 5mal
										; Kontroll-LED wird durch einen sehr kurzen (0,06 ms) Pumpimpuls eingeschaltet
										; der Pumpimpuls ist kurz genug, daß dabei kein Öl fließt
#define	Enable_BlinkRain_for_Cross (0)	; Crossmode durch blinkende RegenLED anzeigen lassen

#define	Enable_Blink2sek_CrossLED (0)	; CrossLED alle 2 Sekunden kurz aufleuchten lassen
#define	Enable_Blink15sek_CrossLED (0)	; CrossLED alle 15 Sekunden kurz aufleuchten lassen

#define	Enable_Blink2sek_extRegenLED (0); externe RegenLED alle 2 Sekunden kurz aufleuchten lassen
#define	Enable_Blink15sek_extRegenLED (0); externe RegenLED alle 15 Sekunden kurz aufleuchten lassen
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

;############################################################################
;##                                                                        ##
;##                    Ende Konfigurationsabschnitt                        ##
;##                                                                        ##
;############################################################################


.equ	Cross_SW	=PD0	; PD0 gegen Masse = Crossmode aktiv
.equ	ExternRegen	=PD1
.equ	ReedSW		=PD2	; (INT0)
.equ	Taste		=PD3
.equ	ReedLED		=PD4
.equ	RegenLED	=PD5
.equ	Cross_LED	=PA0	; gegen VCC anschließen!
.equ	Zuendung	=PA1	; Signal von Zündung+

.equ	EntprellTimer	=4*Reeddelay

.equ	CntTicksHigh=0xE4	; Gesamt 0xE4E2 = 58594 Counterticks
.equ	CntTicksLow	=0xE2	; entspricht ca. 15 Sekunden, bis zu 10% Abweichung aufgrund
							; Ungenauigkeit des Quarzes sind möglich

.equ	FlagRegister=GPIOR0 ; GPIOR0 als Register für verschiedene Zustandsflags,
							; umbenannt um den Code leichter lesbar zu machen
.equ	Notbetrieb	=4		; Bit 4 in Flagregister für Notbetrieb genutzt
.equ	Learn_Tacho =6		; Bit 6 in Flagregister für Learnmode-Tachopulse genutzt
.equ	Learn_Rad	=7		; Bit 7 in Flagregister für Learnmode-Radkonstante genutzt
.equ	Regen		=0		; Bit 0 in Flagregister für Regen/kein Regen genutzt

.equ	RGrenze		=RStrecke*3
.equ	TGrenze		=RGrenze+TStrecke*3
.equ	PumpMax		=TGrenze+Pumpstoesse-1
.equ	halbes_intervall	=(intervall+1)/2
.equ	cntRegenGrenze	= (RegenDelay*15)+Regendelay

.equ	CntRad_prog =0x0060		; Speicherstelle Radumdrehung für Geschwindigkeitsprogression
.equ	CntRad_rain	=0x0061		; Speicherstelle Radumdrehungen für das Nachölen nach Regen
.equ	s_Tachopulse=0x0062		; Speicherstelle Tachopulse: am Programmstart aus EEPROM initialisiert
.equ	s_Rad		=0x0063		; Speicherstelle Radkonstante

.equ	RSchwelle	=0x0064			; Speicherstelle für Schwellwert überwiegend Regen
.equ	TSchwelle	=0x0065			; Speicherstelle für Schwellwert überwiegend Trocken

.equ	akt_speicherstelle_learnmode = 0x0066 ; Zeiger auf die aktuell zu nutzende SRAM-Addresse im Learnmode
.equ	s_learn_tacho_start	= 0x0067	; Start Speicherplatz für Learnmode Tachopulse
.equ	s_learn_tacho_eeprom= 0x006b	; enthält den nach dem Lernen zu speichernden Wert
.equ	s_learn_tacho_end	= 0x0070	; Ende Speicherplatz Learnmode Tachopulse
		; 10 Speicherplätze -> 10mal Rad drehen
.equ	s_learn_rad_start	= 0x0071	; Start Speicherplatz für Learnmode Radkonstante
.equ	s_learn_rad_eeprom	= 0x0072	; enthält den nach dem Lernen zu speichernden Wert
.equ	s_learn_rad_end		= 0x0073	; Ende Speicherplatz für Learnmode Radkonstante
		; 3 Speicherplätze -> 3mal 333 Meter = 1000 Meter fahren
; Speicherbelegung (SRAM) insgesamt:
; 0x0060 -> CntRad_prog -> Zähler für Radumdrehung in den letzten 2 Sekunden,
;			um die Geschwindigkeit berechnen zu können
; 0x0062 -> Tachopulse
; 0x0063 -> Radkonstante

; 0x0064 -> RSchwelle (berechnet)
; 0x0065 -> TSchwelle (berechnet)

; 0x0066 ->	Zeiger auf die aktuell zu nutzende SRAM-Speicherstelle im Learnmode
; 0x0067 -> Start Speicherplatz für Learnmode-Tachopulse, insgesamt 10 Speicherstellen -> 10 Radumdrehungen
; 0x006b ->	enthält den ins EEPROM zu übernehmenden Wert für die Tachopulse
; 0x0070 -> Ende Speicherplatz für Learnmode-Tachopulse
; 0x0071 -> Start Speicherplatz Learnmode Rad
; 0x0072 ->	enthält den ins EEPROM zu übernehmenden Wert für die Radkonstante
; 0x0073 -> Ende Speicherplatz für Learnmode Rad

;-----low Register
;.def	Time1		=r1
;.def	Time2		=r2
.def	cntRegenDelay=r2		; Zähler für die Umsetzung des Regendelays
.def	CntRad		=r3			; Zähler für je 333 m
.def	CntWert		=r4			; Zähler für x*333 m
.def	cPump		=r5			; Zähler Pumpenpulse beim Vorpumpen
.def	CntTacho	=r6 		; Zähler für Tachopulse
.def	Wert		=r7			; Vergleichswert
.def	Cr_cnt		=r8			; Zähl-Wert für Crossmode
.def	NotIntervallReg=r10		; Register für Länge von NotIntervall
.def	NoSignalReg =r11		; Register für Länge von NoSignal
.def	Cnt2Sek		=r12		; Zählregister, um das 2-Sekunden-Intervall zu realisieren
.def	Timer1Cnt	=r13		; Zähler für Timer1-CompMatches = 15sekunden-Zähler
;-----high Register
.def	c0			=r16		; Zähler delay-Schleife
.def	c1			=r17		; Zähler innere delay-Schleife
.def	c2			=r18		; Zähler Frequenz-Schleife
.def	temp		=r19		; Temporär-Register
.def	temp2		=r20		; zweites Temp-Register
.def	Cr_soll		=r21		; Soll-Wert für Crossmode
.def	Regenanteil	=r22		; bestimmt die Regenmenge der letzten 333m
								; (Anteil der Reed Impulse mit geschaltetem Regensensor)
								; (25%, 75% als Schwellenwert für Änderung)
.def	Regenmerker	=r23		; Zustandsmerker für Regensensor der letzten 333m-1666m
								; 0 - Regulärer Trockenzustand
								; 1 - letzten  333m Überwiegend nass
								; 2 - letzten  666m Überwiegend nass
								; ...
								; RGrenze - letzten RStreck km Überwiegend nass
								; RGrenze+1 -  333m überwiegend trocken nach ausreichend nass
								; RGrenze+2 -  666m überwiegend trocken nach ausreichend nass
								; ...
								; TGrenze - nach RStrecke km Regen jetzt für TStrecke km überwiegend trocken, Ölen!
								; TGrenze+1 - Ölen!
								; ...
								; PumpMax Anzahl Pumpstoesse erreicht, letztes Mal Ölen, danach Merker wieder auf 0

.def	faktor_1	=r24		; Faktor 1
.def	quot_l		=r24		; lowbyte Ergebnis der Division
.def	faktor_2	=r25		; Faktor 2
.def	quot_h		=r25		; highbyte Ergebnis der Division
.def	mul_help	=r28		; multiplikation Hilfsregister
.def	divisor		=r28		; Divisor
.def	prod_l		=r29		; lowbyte Ergebnis der Multiplikation
.def	div_l		=r29		; lowbyte des Dividends 
.def	prod_h		=r30		; highbyte Ergebnis der Multiplikation
.def	div_h		=r30		; highbyte des Dividends 
.def	div_help	=r31		; division Hilfsregister



;XL (R26) und XH (R27) bitte NICHT umdefinieren bzw. nur mit Vorsicht verwenden,
;da die regelmäßig für SRAM-Addressierung genutzt werden
;genaugenommen XH am besten garnicht anfassen, da es nur bei Programmstart
;einmal initialisiert wird und dann dauerhaft auf diesem Wert bleiben soll,
;um es nicht bei jedem Speicherzugriff neu setzen zu müssen.



;********************************************************************************************
.macro	delay
		push	c0
		ldi		C0,@0		
		rcall	do_delay
		pop		c0
.endmacro

do_delay:					; Warteschleife, x mal 1ms 
		push	c1
		push	c2		
WGLOOP0: 
		ldi		C1,$1F
WGLOOP1: 
		ldi		C2,$2A
WGLOOP2:
		dec		C2
		brne	WGLOOP2
		dec		C1
		brne	WGLOOP1
		dec		C0
		brne	WGLOOP0
		wdr
		pop		c2
		pop		c1
		ret
; delay-macro deutlich gekürzt, um Programmspeicher zu sparen
; macros werden jedesmal komplett an der verwendeten Stelle im Code eingefügt.
; per rcall aufgerufene Unterprogramm stehen nur einmal im Code und werden von
; verschiedenen Ausgangspunken aus angesprungen, daher
; eigentliche Delay-Schleifen in ein Unterprogramm ausgelagert, nur ein rudimentäres
; delay-macro behalten, um den bequemen Aufruf weiterhin zu ermöglichen


;********************************************************************************************
; für die Generierung der Umschaltfrequenz des Regensensors benögtigt
.macro	freq						; Warteschleife 0,25 ms
		ldi 	c2,250
f0:		nop
		dec 	c2
		brne 	f0
		wdr
.endmacro



;********************************************************************************************
;**** Unterprogramm LED-Test ****************************************************************
;********************************************************************************************
LED_Test:							; LEDs nach Startup/Wakeup blinken lassen, um Funktion zu prüfen/signalisieren
		push	temp

		sbi		PORTD,6				; Pumpe an, um die Kontrollschaltung zu triggern
		ldi 	c2,60		
LED_Test_triggerdelay:				; sehr kurze Verzögerung, damit die Kontrollschaltung Zeit hat zu reagieren
		dec 	c2
		brne 	LED_Test_triggerdelay
		cbi		PORTD,6				; Pumpe aus

		ldi		temp, 5				; LEDs 5mal blinken lassen
LED_Test_blink:		
		wdr
		cbi		PortA, Cross_LED
		cbi		PortD, Externregen	; LEDs an
		delay	200					; warten
		sbi		PortA, Cross_LED
		sbi		PortD, ExternRegen	; LEDs aus
		delay	200					; warten
		dec		temp				; Zähler um 1 verringern
		brne	LED_Test_blink		; Zähler <>0? Weiterblinken

		pop		temp
		ret


;********************************************************************************************
;************* Blink-Unterprogramm für externe RegenLED, Anzeige Notlauf ********************
;********************************************************************************************
blink_Regen:
		push	temp
		ldi		temp,10				; LED 10mal blinken lassen
Blink_Regen_Start:
		cbi		PortD,ExternRegen	; RegenLED an
		delay	200					; warten
		sbi		PortD,ExternRegen	; RegenLED aus
		delay	200					; warten
		dec		temp				; Zähler um 1 verringern
		brne	Blink_Regen_Start	; <>0? Weiterblinken

		pop		temp
		ret


;********************************************************************************************
;************** Blink-Unterprogramm für externe RegenLED, Anzeige Crossmode *****************
;********************************************************************************************
blink_CrossMode:
		cbi		PortD,ExternRegen		; RegenLED an
		delay	250
		delay	250						; 2 * 250 ms warten
		sbi		PortD,ExternRegen		; RegenLED aus
		sbic	Flagregister, Regen		; Regen?
		rjmp	blink_crossmode_rain	; dann nur verkürzte Aus-Zeit der LED
		delay	200
		delay	200						; 2 * 200 ms warten
blink_crossmode_rain:
		delay	100						; und nochmal 100 ms warten
		; im trockenen also 2*250 ms LED an, danach 2*200+100 ms LED aus -> 500 ms an, 500 ms aus
		; im nassen: 2*250 ms LED an, danach 100 ms LED aus -> 500 ms an, 100 ms aus
		ret


;********************************************************************************************
;***** Unterprogramm zur Berechnung der Schwellwerte für Extraölen nach Regen ***************
;********************************************************************************************
berechne_schwellwerte:
		push	temp
		push	temp2

		ldi		temp, 2				; radkonstante aus EEPROM laden
		rcall	read_eeprom
		mov		faktor_1, temp
		; Nachölen arbeitet nachwievor mit dem 333-Meter-Intervall, daher hier Anpassung an
		; möglicherweise geändertes Intervall des normalen Ölens
		; Radkonstante fürs Nachölen auf 333 meter normieren:
		; Rad * 333 / Intervall (bzw 167 und intervall/2, da ja zahlen größer 255 nicht möglich sind)
		ldi		faktor_2, 167
		rcall 	multipliziere
		ldi		divisor, halbes_intervall
		rcall	dividiere

		sts		cntrad_rain, quot_l	; Umdrehungszähler für Nachölen initialisieren, es wird
									; auf 0 heruntergezählt
		mov		temp2, temp			; Radkonstante auch in temp2 laden
		lsr		temp2
		lsr		temp2				; temp2 enthält jetzt Radkonstante * 0,25
		sub		temp, temp2			; temp = Radkonstante * 0,75

		sts		RSchwelle, temp		; temp (RSchwelle) im SRAM ablegen
		sts		TSchwelle, temp2	; temp2 (TSchwelle) im SRAM ablegen

		pop		temp2
		pop		temp
		ret


;*************** Unterprogramm Multiplikation ********************
;*** geklaut von: http://www.avr-asm-tutorial.net/avr_de/rechnen/multiplikation.html
;*** berechnet aus zwei 8-Bit-Werten (Register "faktor_1" und "faktor_2"
;*** einen 16-Bit-Wert (Register prod_h, prod_l)
;*** Schade, daß der Tiny2313 keinen Multiplikator hat, würde das etwas vereinfachen ;-)
multipliziere:
		clr		mul_help	; Hilfsregister leeren
		clr		prod_l		; Ergebnisregister leeren
		clr		prod_h
mult_a:
		clc
		ror		faktor_2
		brcc	mult_b
		add		prod_l, faktor_1
		adc		prod_h, mul_help
mult_b:	
		clc
		rol		faktor_1
		rol		mul_help
		tst		faktor_2
		brne	mult_a
		ret

;*************** Unterprogramm Division ********************
;*** geklaut von: http://www.avr-asm-tutorial.net/avr_de/rechnen/division.html
;*** dividiert 16 bit (div_h, div_l) durch 8 bit (divisor), liefert als Ergebnis
;*** einen 16-Bit-Wert (Register "quot_h", "quot_l")
dividiere:	
		clr		div_help
		ldi		quot_l, 1
		clr		quot_h

div_a:
		clc
		rol		div_l
		rol		div_h
		rol		div_help
		brcs	div_b
		cp		div_help, divisor
		brcs	div_c

div_b:
		sub		div_help, divisor
		sec
		rjmp	div_d
div_c:
		clc
div_d:
		rol		quot_l
		rol		quot_h
		brcc	div_a
		ret


;*** EEPROM einlesen, zu lesende Speicherstelle muß bei ****************
;*** Aufruf in temp stehen, Ergebnis dann auch in temp zu finden *******
read_eeprom:
		; EEPROM-Schreibvorgänge brauchen 3.4 ms zum beenden. Während dieser Zeit ist 
		; weder Schreiben noch Lesen auf dem EEPROM möglich, 
		; zur Kontrolle: EEPE = 1, während Schreibvorgang aktiv
		sbic	EECR, EEPE			; EEPE = 1? -> letzter Schreibvorgang nicht beendet
		rjmp	read_eeprom			; auf Beendigung warten

		out		EEAR, temp			; Addresse von EEPROM-Speicherstelle in EEAR laden
		sbi		EECR, EERE			; read-enable in EECR setzen
		in 		temp, EEDR			; Inhalt in temp lesen
		ret

;*** EEPROM schreiben, zu schreibende Speicherstelle muß bei ************
;*** Aufruf in temp stehen, zu schreibender Inhalt in temp2 *************
write_eeprom:
		; EEPROM-Schreibvorgänge brauchen 3.4 ms zum beenden. Während dieser Zeit ist 
		; weder Schreiben noch Lesen auf dem EEPROM möglich, 
		; zur Kontrolle: EEPE = 1, während Schreibvorgang aktiv
		sbic	EECR, EEPE			; EEPE = 1? -> letzter Schreibvorgang nicht beendet
		rjmp	write_eeprom		; auf Beendigung warten

		out		EEAR, temp			; Addresse von EEPROM-Speicherstelle in EEAR laden
		out		EEDR, temp2			; zu schreibenden Inhalt in EEDR laden
		sbi		EECR, EEMPE			; EEPROM_master_program_enable setzen
		sbi		EECR, EEPE			; Schreibvorgang durch setzen von EEPROM_program_enable starten
		ret

;********************************************************************************************
;********************** Programmparameter im EEPROM ablegen *********************************
;********************************************************************************************
save_params_in_eeprom:
		
		; programmparameter im EEPROM ablegen
		ldi		temp, 32
		ldi		temp2, ReedDelay
		rcall	write_eeprom

		inc		temp
		ldi		temp2, Delay_automatic
		rcall	write_eeprom

		inc		temp
		ldi		temp2, high(intervall)
		rcall	write_eeprom
		
		inc		temp
		ldi		temp2, low(intervall)
		rcall	write_eeprom

		inc		temp
		ldi		temp2, Hex_Offset
		rcall	write_eeprom

		inc		temp
		ldi		temp2, Rstrecke
		rcall	write_eeprom

		inc		temp
		ldi		temp2, TStrecke
		rcall	write_eeprom

		inc		temp
		ldi		temp2, Pumpstoesse
		rcall	write_eeprom

		inc		temp
		ldi		temp2, NoSignal
		rcall	write_eeprom

		inc		temp
		ldi		temp2, NotIntervall
		rcall	write_eeprom

		inc		temp
		ldi		temp2, PumpCross
		rcall	write_eeprom

		inc		temp
		ldi		temp2, WegCross
		rcall	write_eeprom

		inc		temp
		ldi		temp2, Pumpnormal
		rcall	write_eeprom

		inc		temp
		ldi		temp2, PumpRegen
		rcall	write_eeprom

		inc		temp
		ldi		temp2, WegRegen
		rcall	write_eeprom

		inc		temp
		ldi		temp2, RegenDelay
		rcall	write_eeprom

		inc		temp
		ldi		temp2, PumpTest
		rcall	write_eeprom

		inc		temp
		ldi		temp2, PumpOnTest
		rcall	write_eeprom

		inc		temp
		ldi		temp2, PumpOffTest
		rcall	write_eeprom

		inc		temp
		ldi		temp2, PumpOn
		rcall	write_eeprom

		inc		temp
		ldi		temp2, PumpOff
		rcall	write_eeprom

		inc		temp
		ldi		temp2, sleepmode
		rcall	write_eeprom

; on/off-optionen in 2 Byte zusammenfassen
; 1. Byte: Reeddelayon/off/Notlauf/Notlauf_dynamisch/Extraölen(nach Regen)/Pumpimpulse im Regen/Speedprogression
		ldi		temp2,0

#if Force_ReedDelay_On
		sbr		temp2,128
#endif

#if Force_ReedDelay_Off
		sbr		temp2,64
#endif
		
#if Enable_Notlauf
		sbr		temp2,32
#endif

#if Enable_Notlauf_Dynamisch
		sbr		temp2,16
#endif

#if Enable_ExtraOelen
		sbr		temp2,8
#endif

#if Add_Rain
		sbr		temp2,4
#endif

#if Enable_SpeedProgression
		sbr		temp2,2
#endif

;platz für ein weiteres Flag auf Bit0

		ldi		temp, 64
		rcall	write_eeprom

; 2. Byte: LED-Blinkereien
		ldi		temp2, 0

#if	Enable_BlinkNotlauf
		sbr		temp2,128
#endif

#if Enable_LED_Test
		sbr		temp2,64
#endif

#if	Enable_BlinkRain_for_Cross
		sbr		temp2,32
#endif

#if	Enable_Blink2sek_CrossLED
		sbr		temp2,16
#endif

#if	Enable_Blink15sek_CrossLED
		sbr		temp2,8
#endif

#if	Enable_Blink2sek_extRegenLED
		sbr		temp2,4
#endif

#if	Enable_Blink15sek_extRegenLED
		sbr		temp2,2
#endif

;platz für ein weiteres Flag auf Bit0

		ldi		temp, 65
		rcall	write_eeprom


		ldi		ZH, high (Speedprogression*2)
		ldi		ZL, low (Speedprogression*2) ; Startaddresse der Tabelle laden
		ldi		temp, 96
save_speedtab:
		lpm		temp2, Z+			; ersten Wert aus der Tabelle in temp2 laden
		rcall	write_eeprom

		subi	temp, -16
		lpm		temp2, Z+
		rcall	write_eeprom

		subi	temp, 15
		
		cpi		temp, 112
		brsh	end_save_speedtab

		ldi		temp2, low(end_speedprogression*2)
		cpse	Zl, temp2 ; Ende der Tabelle erreicht?

		rjmp	save_speedtab	; Tabelle weiter durchsuchen

end_save_speedtab:
		ret


;**************************************************************** 
; Timer0 Compare Match A        ; 
;**************************************************************** 
; Einlesen des Hexschalters,
; Berechnen möglicher Intervallverkürzungen aufgrund:
; Geschwindigkeitsprogression, Regen, Crossmode
; die Wegverkürzungen erfolgen über Manipulation (prozentuale Verringerung) der Radkonstante

timer0_comp_match:

		push	temp				; Temp-Reg sichern
		push	temp2				
		in		temp,SREG			; Status-Reg sichern 
		push	temp

		sbis	PORTB,PB2			; richtige Sensorpolarität prüfen
		rjmp	Sensor_positiv
		cbi		PORTB,PB2			; nötigenfalls richtig setzen
		sbi		PORTB,PB3
		freq						; 0,25ms warten
Sensor_positiv:
; Regenstatus im FlagRegister speichern
		ldi		temp, 1
		sbic	ACSR,ACO			; Regen?
		add		cntRegenDelay, temp	; -> Regendelay-Zähler um 1 erhöhen
		sbis	ACSR, ACO			; kein Regen
		sub		cntRegenDelay, temp ; ->Regendelay-Zähler um 1 verringern

		cp		cntRegenDelay, temp	; temp immer noch = 1 -> Vergleich Regenzähler mit 1
		brsh	kein_statuswechsel_trocken ; >=1? Status wird nicht auf trocken gesetzt
		cbi		Flagregister, Regen	; <1 -> status trocken abspeichern
		mov		cntRegenDelay, temp ; cntRegenDelay wieder auf 1 setzen, um einen Unterlauf 0 zu 255 zu verhindern
kein_statuswechsel_trocken:
		ldi		temp, cntRegenGrenze; Grenzwert für Statuswechsel Regen laden
		cp		cntRegenDelay, temp ; Vergleich mit cntRegendelay, Grenzwert erreicht?
		brlo	kein_statuswechsel_nass ; Grenzwert nicht erreicht -> kein Statuswechsel
		sbi		FlagRegister, regen	; grenzwert erreicht -> statuswechsel Naß durchführen
		mov		cntRegenDelay, temp	; cntRegenDelay auf grenzwert setzen, um es nicht zu groß werden zu lassen

kein_statuswechsel_nass:
		inc		Cnt2sek				; Zählregister erhöhen
		ldi		temp, 31			; Vergleichswert für 2-Sekunden-Intervall laden
		cpse	Cnt2sek, temp		; Timerintervall 31 mal abgelaufen = 2 Sekunden vergangen?
		rjmp	T0_CM_End			; nein: Routine beenden
		clr		Cnt2Sek				; Zählreg. zurücksetzen

#if Enable_Blink2sek_CrossLED
		cbi		PortA,Cross_LED
		delay	10
		sbi		PortA,Cross_LED
#endif
#if Enable_Blink2sek_extRegenLED
		cbi		PortD,ExternRegen
		delay	10
		sbi		PortD,ExternRegen
#endif
		clr		temp				; Hexschalter einlesen
		sbis	PINB,4
		sbr		temp,1
		sbis	PINB,5				; Bit 1 und 2 des Hex-Schalters
		sbr		temp,4				; im Layout vertauscht
		sbis	PINB,6				; also zurücktauschen
		sbr		temp,2
		sbis	PINB,7
		sbr		temp,8

		subi	temp,-Hex_Offset	; Offset addieren (min 8 x 333m = 2666m)
		mov		wert,temp			; berechneten Vergleichswert im richtigen Reg. speichern
									; Umweg über Temp nötig, da Wert ein Low-Register

		sbic	FlagRegister,Notbetrieb	; Notbetriebsmodus?
		rjmp	T0_CM_End			; dann Routine beenden

		ldi		temp, 2				; Inhalt von EEPROM-Speicherstelle 2 (=Radkonstante) laden
		rcall	read_eeprom			; und in SRAM speichern, um für die möglicherweise gleich erfolgende
		sts		s_Rad, temp			; Verkürzung der Radkonstante (Regen, Crossmode) den richtigen Ausgangswert
									; im Speicher stehen zu haben. Wenn alleine mit der im SRAM gespeicherten
									; Radkonstante gearbeitet würde, dann wird die bei jedem neuen Durchlauf immer
									; weiter verkürzt -> Fehler

#if Enable_SpeedProgression
		; Geschwindigkeitsprogression berechnen
		; dazu: erst die Geschwindigkeit aus der Anzahl der Radumdrehungen berechnen
		; danach die Progressionstabelle nach passendem Eintrag durchsuchen
		; und die Radkonstante mit dem gefundenen Wert anpassen

		; Berechnung der Geschwindigkeit:
		; Radumdrehung * 333/Radkonstante * 1,8
		; da ich aber nicht mit Zahlen > 255 multiplizieren kann, genausowenig mit gebrochen Zahlen
		; erfolgt die Berechnung im Programm etwas anders:
		; Radumdrehung * 167 (333:2)/Radkonstante * 36 (1,8*20) / 10
		lds		faktor_1, CntRad_prog		; Umdrehungsanzahl als ersten Faktor aus dem SRAM laden
		clr		temp2
		sts		CntRad_prog, temp2	; Umdrehungsanzahl im SRAM wieder auf 0 setzen
		ldi		faktor_2, halbes_intervall	; halbe Intervalllänge als 2. Faktor setzen
		rcall	multipliziere		
		; erster Teil: Umdrehung * 167 ist erledigt
		; Ergebnis der Multiplikation steht schon in den richtigen Registern, um gleich als Dividend
		; für die folgende Division genutzt zu werden
		lds		divisor, s_Rad		; Radkonstante laden
		rcall	dividiere
		; zweiter Teil, Division durch Radkonstante ist erledigt
		; ergebnis der Division steht gleich im Faktor_1 - Register
		ldi		faktor_2, 36		; 36 als nächsten Faktor setzen
		rcall	multipliziere
		; dritter Teil: Multiplikation mit 36 erledigt
		ldi		divisor, 10			
		rcall	dividiere			; vierter Teil: Division durch 10 erledigt
		; Berechnung der Geschwindigkeit aus der Anzahl der Radumdrehungen abgeschlossen
		; noch zu prüfen, ob Ergebnis kleiner 255, falls nicht, auf 255 setzen
		cpi		quot_h, 0			; enthält das High-Byte des Divisionsergebnisses
									; irgendetwas <>0, war das Ergebnis größer als 255
		breq	speed_in_range		; falls =0 -> mit der Progressionsberechnung weitermachen
		ldi		quot_l, 255			; sonst auf 255 setzen
speed_in_range:
		mov		temp, quot_l		; Temp enthält jetzt die aktuelle Geschwindigkeit

		; Geschwindigkeit berechnet, jetzt korrekten Wegfaktor
		; aus der "Speedprogression"-Tabelle suchen
		ldi		ZH, high (Speedprogression*2)
		ldi		ZL, low (Speedprogression*2) ; Startaddresse der Tabelle laden
		ldi		faktor_2, 100		; Der passende Verkürzungswert aus der Tabelle wird gleich ins entsprechende
									; Register für die anschließende Multiplikation geladen. 
									; Daher mit 100 (%) = keine Verkürzung initialisieren,
									; falls kein passender Wert in der Tabelle gefunden wird.
durchsuche_speedtab:
		lpm		temp2, Z+			; ersten Wert aus der Tabelle in temp2 laden
		cp		temp, temp2			; und mit berechneter Geschwindigkeit vergleichen
		brlo	berechne_speedprogression ; Geschwindigkeit (temp) < als Geschwindigkeit aus Tabelle (temp2)
									; dann zur Berechnung der Verkürzung springen
		cpi		ZL, Low(end_speedprogression*2) ; Ende der Tabelle erreicht?
		brsh	berechne_speedprogression	; Verkürzung berechnen

		lpm		faktor_2, Z+		; zur Geschwindigkeit gehörenden Prozentwert laden
									; die Geschwindigkeit für diesen Wert ist kleiner als die aktuell gefahrene
									; wird beim nächsten Durchlauf dann eine größere Geschwindigkeit aus der Tabelle
									; gelesen, als gerade gefahren wird, dann haben wir den passenden Prozentwert gefunden
									; Bsp: Tabelle:
									; 100, 88
									; 130, 75
									; 160, 66
									; gefahren wird 140 km/h, richtiger Verkürzungswert ist also 75
									; 1. Durchlauf: - aus Tabelle gelesene Geschwindigkeit = 100 km/h
									;				- ist kleiner als aktuell gefahrene (140)
									;				-> Prozentwert (88) aus Tabelle laden
									;				-> Tabelle weiter durchsuchen
									; 2. Durchlauf:	- aus Tabelle gelesene Geschwindigkeit = 130 km/h
									;				- ist kleiner als aktuell gefahrene (140)
									;				-> Prozentwert (75) aus Tabelle laden
									;				-> Tabelle weiter durchsuchen
									; 3. Durchlauf:	- aus Tabelle gelesene Geschwindigkeit = 160 km/h
									;				- ist größer als aktuell gefahrene (140)
									;				-> zur Berechnung der Verkürzung springen, als Verkürzungswert
									;					wird die im 2. Durchlauf gelesene 75 verwendet

		rjmp	durchsuche_speedtab	; Tabelle weiter durchsuchen
berechne_speedprogression:
		lds		faktor_1, s_Rad		; Radkonstante als ersten Faktor laden
									; Faktor_2 ist ja schon passend belegt
 		rcall	multipliziere
		ldi		divisor, 100		; und noch die Division durch 100, wir wollen ja eine prozentuale Verkürzung erreichen
		rcall	dividiere
		cpi		quot_h, 0			; falls das High-Byte des Quotienten nach der Division <> 0 ist,
									; dann war "Radkonstante * Progressionsfaktor" > 255
									; damit kann nicht sinnvoll gearbeitet werden.
		breq	progression_in_range  ; falls =0, ist das Ergebnis höchstens 255 -> alles bestens, weitermachen
		ldi		quot_l, 255			; sonst auf 255 setzen -> maximale Intervallänge
progression_in_range:

		sts		s_Rad, quot_l		; angepaßte Radkonstante im SRAM ablegen
#endif

		sbis	Flagregister, Regen	; Regen?
		rjmp	NoRain				; Nein -> Sprung zu NoRain

		lds		faktor_1, s_Rad		; Regenverkürzung der Radkonstante berechnen
		ldi		faktor_2, WegRegen
		rcall	Multipliziere

		ldi		divisor, 100
		rcall	dividiere

		sts		s_Rad, quot_l		; neue, gekürzte Radkonstante im SRAM ablegen

NoRain:
		sbic	PIND,Cross_SW		; PD0 Kontakt geschlossen? 
		rjmp	T0_CM_End			; ja, dann keine Crossmode-Wegverkürzung
	
		lds		faktor_1, s_Rad		; Radkonstante
		ldi		faktor_2, WegCross	; Multiplikation vorbereiten, Faktoren laden
		rcall 	multipliziere		; Multiplikation durchführen

		ldi		divisor, 100		; Divisor mit 100 laden
		rcall	dividiere			; Division durchführen

		sts		s_rad, quot_l		; Low-Register des Ergebnisses übernehmen, High-Reg muß sowieso 0 sein

T0_CM_End:
		pop		temp
		out		SREG,temp			; Status Reg zurückschreiben 
		pop		temp2
		pop		temp				; Temp zurückschreiben
		reti

;**************************************************************** 
; Timer0 Compare Match B        ; 
; für Reed-Entprellung benutzt	;
;**************************************************************** 
timer0_comp_match_B:

		push	temp				; Temp-Reg sichern
		in		temp,SREG			; Status-Reg sichern 
		push	temp
		
		ldi		temp, 255			; Compare_Match_Reg wieder auf 255 setzen
		out		OCR0B, temp			; um keine weiteren Interrupts zu erhalten
									; erst bei Aufruf des Reed_Interrupts wird dann
									; das Compare_Match_Register passend zum ReedDelay geladen

		ldi		temp, 0b01000000	
		out		GIMSK,temp			; ReedInterrupt wieder aktivieren
		out		EIFR,temp			; Interrupt-Flag zurücksetzen, da Interrupts innerhalb des Delays nur von
									; prellendem Sensor stammen können

		pop		temp
		out		SREG,temp			; Status Reg zurückschreiben 
		pop		temp				; Temp zurückschreiben
		reti

;**************************************************************** 
; Timer1 Compare Match         ; 
; für das 15-Sekunden-Intervall (Basisintervall Notlauf)
;**************************************************************** 
timer1_comp_match:

		push	temp				; Temp-Reg sichern
		push	temp2
		in		temp,SREG			; Status-Reg sichern 
		push	temp

#if Enable_Blink15sek_CrossLED
		cbi		PortA,Cross_LED
		delay	10
		sbi		PortA,Cross_LED
#endif
#if Enable_Blink15sek_extRegenLED
		cbi		PortD,ExternRegen
		delay	10
		sbi		PortD,ExternRegen
#endif



		brts	T1_CM_End			; Testmode? -> Interrupt beenden

		inc		Timer1Cnt			; dann 15-Sek-Zähler erhöhen

#if Enable_Notlauf
		sbis	PinA, Zuendung		; wenn Zuendung aus
		rjmp	T1_CM_End			; -> Interrupt beenden


		ldi		temp, NoSignal      ; Umweg über Temp, da NoSignalReg ein Low-Register
		mov		NoSignalReg,temp	; NoSignal ins Register laden
		ldi		temp, NotIntervall
		mov		NotIntervallReg,temp; NotIntervall ins Register laden


#if Enable_Notlauf_Dynamisch
		; NotIntervall dynamisch berechnen

		; zuerst: Anpassung an Entfernungsintervall und 100 km/h
		; Register "wert" gibt an, wie oft das Entfernungsintervall zurückgelegt
		; werden muß, und enthält damit quasi die Wegstrecke, die aktuell am McCoi eingestellt ist
		; daraus läßt sich berechnen, welche Zeit vergehen muß, um diese Strecke
		; bei (ganz grob) 100 km/h zu bewältigen
		; Umrechnung erfolgt nach dem Schema:
		; wert * halbes_intervall / 208
		
		mov		faktor_1, wert
		ldi		faktor_2, halbes_intervall
		rcall	multipliziere

		ldi		divisor, 208
		rcall 	dividiere
		; das Ergebnis der Division kann (theoretisch) auch > 255 sein, aber praktisch glaube ich nicht,
		; das jemand den McCoi so extrem einstellt (es wären Ölentfernungen über 100 km nötig, damit das passiert)
		; also spare ich mir hier den Vergleich
		mov		NotIntervallReg, quot_l ; angepaßtes NotIntervall speichern

// Verkürzung des NotIntervalls für Regen- und Crossmode berechnen
		sbis	Flagregister, Regen	; Regen?
		rjmp	NoRain_Notlauf		; Nein -> Sprung zu NoRain_Notlauf

		; Regenverkürzung des Notlauf-Intervalls berechnen
		; faktor_1 ist schon mit dem Ergebnis der ersten Berechnung passend belegt
		ldi		faktor_2, WegRegen
		rcall	Multipliziere

		ldi		divisor, 100
		rcall	dividiere

		mov		Notintervallreg, quot_l	; angepaßtes Notintervall speichern

NoRain_Notlauf:
		sbic	PIND,Cross_SW		; PD0 Kontakt geschlossen? 
		rjmp	T1_CM_Weiter			; ja, dann keine Crossmode-Wegverkürzung
	
		; Crossmodeverkürzung des Notlauf-Intervalls berechnen
		; faktor_1 von vorherigen Berechnungen schon passend geladen
		ldi		faktor_2, WegCross	; Multiplikation vorbereiten, Faktoren laden
		rcall 	multipliziere		; Multiplikation durchführen

		ldi		divisor, 100		; Divisor mit 100 laden
		rcall	dividiere			; Division durchführen

		mov		Notintervallreg, quot_l		; Low-Register des Ergebnisses übernehmen, High-Reg muß sowieso 0 sein
#endif ; Ende berechnungen dynamischer Notlauf

T1_CM_Weiter:
		ldi		temp2, 1
		ldi		temp,0
		cp		temp, notintervallreg	; Notintervall auf = 0 überprüfen
		in		temp, sreg				; sreg nach temp laden
		sbrc	temp, ze				; überprüfen, ob Zero-Flag gesetzt
		add		notintervallreg, temp2  ; falls ja, dann temp2(=1) zu NotIntervallReg addieren
	
		sbic	FlagRegister,Notbetrieb	; Notbetrieb?
#if Enable_BlinkNotlauf
		rcall	blink_Regen				; wenn ja dann RegenLED blinken lassen, sonst normal weiter
#endif

		cp		Timer1Cnt, NotIntervallReg	; Notpumpintervall abgelaufen?
		brlo	T1_CM_End			; wenn nein -> Interrupt beenden

		sbic	FlagRegister,Notbetrieb	; Notbetrieb-Flag gesetzt?
		rjmp	Activate_Pump_T1

		cp		Timer1Cnt, NoSignalReg	; mehr Zeit als $NoSignal ohne Reedimpuls verstrichen?
		brlo	T1_CM_End			; nein -> Interrupt beenden
		sbi		FlagRegister, Notbetrieb	; ja -> Notbetrieb-Flag setzen

#if Enable_BlinkNotlauf
		rcall	blink_Regen
#endif
Activate_Pump_T1:
		clr		Timer1cnt
		ldi		Cr_soll,PumpNormal	; $PumpNormal laden
#if !Add_Rain
		sbic	FlagRegister, Regen ; Regen?
		ldi		Cr_soll, PumpRegen	; ja, und Add_Rain nicht  gesetzt -> PumpRegen laden
									; falls Add_Rain gesetzt erfolgt die Addition der Regenimpulse
									; erst am Ende, weil sie ja zu den Cross-Impulsen auch
									; dazugerechnet werden sollen
#endif
		sbis	PIND,Cross_SW		; PD0 Kontakt geschlossen? 
		ldi		Cr_soll,PumpCross	; ja, dann $PumpCross Impulse 
#if Add_Rain
		sbic	FlagRegister, Regen ; Regen?
		subi	Cr_soll, -PumpRegen	; ja, und Add_Rain gesetzt -> PumpRegen addieren
#endif
		;Pumpe aktivieren 
		clr		Cr_cnt				; damit startet die Pumpe im Hauptprogramm
#endif
T1_CM_End:
		pop		temp
		out		SREG,temp			; Status Reg zurückschreiben 
		pop		temp2
		pop		temp				; Temp zurückschreiben
		reti
;****************************************************************
; Initialisierung						;
;****************************************************************
Reset:	ldi		temp,low(ramend)	; initialize stackpointer <T.O.>
		out		spl,temp			;
	
		ldi		temp,0b00000000		; 
		out		MCUSR,temp			; Resetinformationen zurücksetzen

		out		WDTCR,temp			; Watchdogeinstellung vorbereiten
		ldi		temp,0b00001111		; 
		out		WDTCR,temp			; Watchdog 2s

		ldi		temp, 16
wait_startup:						; 16*250 ms = 4 sekunden verzögerung, um sauberes anklemmen 
									; an die Stromversorgung zu gewährleisten
		delay	250		
		dec		temp
		brne	wait_startup


		ldi		temp,0b00111111
		out		PORTD,temp			; Pull-ups einschalten, LEDs aus
		ldi		temp,0b01110010
		out		DDRD,temp			; PD0 (CrossSW), PD2(Int0, Reed)
									; und PD3 (Taster) als Eingang
		sbi		PORTA,Cross_LED		; LED aus
		ldi		temp,0b00000001
		out		DDRA,temp			; Port A0 als Ausgang für Cross-LED, PA1/PA2 als Inputs

		ldi		temp,0b11110000		; 
		out		PORTB,temp			; Port B Pull-ups im oberen Nibble ein
		ldi		temp,0b00001100		; Komparator und
		out		DDRB,temp			; oberes Nibble Port B als Eingang 


		ldi		temp,0b00110010		; Int 0 fallende Flanke, Powerdown
		out		MCUCR,temp 

		ldi		Cr_soll,0			; Standardwerte 0 Impulse
		ldi		temp,0x0F
		mov		Cr_cnt,temp			; Soviele wurde gepumpt
									; damits beim Reset nicht pumpt

		ldi		temp,0b01000000
		out		GIMSK,temp			; Int 0 Enable

		ldi		temp,252			; Compare Register A laden, 252*31*1024 CPU-Clocks = ca. 2 sekunden
		out		OCR0A,temp
		ldi		temp,255
		out		OCR0B,temp			; Compare-Register B für Entprell-Delay vorbereiten

		ldi		temp,0b00000010		; Timer 0 konfigurieren
		out		TCCR0A,temp			; Prescaler 1024, CTC-Mode
		ldi		temp, 0b00000101	; weiteres Zählregister für T0-Compare-Matches, so daß 
		out		TCCR0B,temp			; insgesamt 252*31*1024 CPU-Clocks = 2 Sekunden gezählt werden können
			
		ldi		temp,CntTicksHigh	; CompareRegister laden (15 sek Timerlaufzeit), High-Wert
		out		OCR1AH,temp
		ldi		temp,CntTicksLow	; CompareRegister laden (15 sek Timerlaufzeit), Low-Wert
		out		OCR1AL,temp

		ldi		temp, 0b00000000	; Timer1 konfigurieren:
		out		TCCR1A, temp		; Prescaler 1024, Clear Timer on Compare Match-(CTC)-Mode
		ldi		temp, 0b00001101	; keine Compare-Outputs, da für uns nur der
		out		TCCR1B, temp		; Compare-Match Interrupt interessant ist, um die
		ldi		temp, 0b00000000	; 15 Sekunden messen zu können
		out		TCCR1C, temp

		ldi		temp, 0b11000111	; TOIE0/OCIEA0/OCIEB0: Interrupt bei Timer0 Overflow/Compare Match
									; TOIE1/OCIEA1: Interrupt bei Timer1 Overflow/Compare Match
		out		TIMSK, temp			; Interrupt bei Compare Match zum Zählen ermitteln der Intervalle

		clr		Timer1Cnt			; 15-Sek-Zähler auf 0 setzen
		sts		CntRad_prog,Timer1Cnt	; an 'CntRad_prog' eine 0 speichern

		ldi		temp,16
		mov		Wert,temp			; erstmal mit 5333m initialisieren (bis auslesen)

		; EEPROM testen, ob schon ordentliche Werte für Tachopulse + Radkonstante gespeichert wurden
		ldi		temp, 0				; Addresse von EEPROM-Speicherstelle 0 in temp laden		
		rcall	read_eeprom			; und dann Inhalt von der Speicherstelle lesen
									; Ergebnis der Leseoperation auch in temp
		cpi		temp, 0				; falls Inhalt der Speicherstelle ungleich 0,			
		breq	init_SRAM_aus_EEPROM

		ldi		temp, 1
		rcall	read_eeprom			
		cpi		temp, 0xff			; und Speicherstelle 1 (Tachokonstante) = 0xff und
		brlo	init_SRAM_aus_EEPROM									
									
		ldi		temp, 2
		rcall	read_eeprom
		cpi		temp, 0xff			; und Speicherstelle 2 (Radkonstante) = 0xff
		brlo	init_SRAM_aus_EEPROM

		; muß EEPROM mit den Vorgabewerten für Tacho- und Radkonstante neu beschrieben werden.
		; Annahme dabei: das EEPROM ist _standardmäßig_ komplett mit 0xff initialisiert, solange nichts
		; weiter hinein geschrieben wurde
		ldi		temp, 0				; Addresse für EEPROM-Schreibvorgang in temp laden (0 = EEPROM-Startaddresse)
		ldi		temp2, 0			; Wert für EEPROM-Schreibvorgang in temp2 laden
									; wird auf 0 gesetzt, als Fehlerkontrollmöglichkeit
		rcall	write_eeprom		

		ldi		temp, 1				; Addresse laden (1 = Tachokonstante)
		ldi		temp2, Tachopulse	; Wert laden (aus den Angaben am Programmanfang)
		rcall	write_eeprom

		ldi		temp, 2				; Addresse laden (2 = Radkonstante)
		ldi		temp2, Rad			; Wert laden
		rcall	write_eeprom
					
		rcall	save_params_in_eeprom


init_SRAM_aus_EEPROM:
		ldi		temp, 1				
		rcall	read_eeprom			; Inhalt von EEPROM-Speicherstelle 1 (=Tachokonstante) laden
		sts		s_Tachopulse, temp	; und in SRAM speichern


		ldi		temp, 2				
		rcall	read_eeprom			; Inhalt von EEPROM-Speicherstelle 2 (=Radkonstante) laden
		sts		s_Rad, temp			; und in SRAM speichern

		rcall	berechne_schwellwerte ; Schwellwerte "naß" und "trocken" fürs Nachölen berechnen und den Zähler initialisieren

		ldi		temp, 1
		mov		cntRegenDelay, temp ; Regendelayzähler initialisieren
		
		cbi		ACSR,ACD			; Komparator an

		clr		temp				; alle zuletzt verwendeten Register für den Start des
		clr		temp2				; eigentlichen Programmes wieder zurücksetzen
		clr		c0
		clr		c1
		clr		c2
		clr		CntTacho			; Tachopulszähler zurücksetzen
		ldi		temp,9
		rcall	read_eeprom
		mov		cPump, temp				; Pumpimpulszähler zurücksetzen
		clr		CntRad				; Umdrehungszähler löschen
		clr		CntWert				; 333m-Zähler zurücksetzen

		clr		XL
		clr		XH
#if Enable_LED_Test	
		rcall	LED_Test
#endif

		rjmp	Loop				; zum Anfang der Hauptschleife springen


Learnmode_Tacho:
		sbi		PortD, RegenLED
		cbi		PortD, ReedLed
		rjmp	Loop_end_Learnmode

Learnmode_Rad:
		cbi		PortD, RegenLED
		sbi		PortD, ReedLed

Loop_end_Learnmode:
		sbi		PORTB,PB2			; Regensensor an
		cbi		PORTB,PB3
		freq
;****************************************************************
; Hauptschleife liest den Wegstrecken-Wert ein			;
;****************************************************************
Loop:	sei

		cbi		PORTB,PB2			; Regensensor an
		sbi		PORTB,PB3
		freq						; 0,25ms warten

		in		temp,PinB			; Einlesen Hex-Schalter verkürzt,
		com		temp				; da nur Hex0 = Testmode an dieser
		andi	temp,0xF0			; Stelle festgestellt werden muß
		tst		temp
		brne	NoTest				; Testmode?

		set

		clr		Timer1Cnt			; 15 Sekunden-Zähler resetten

		in		temp, FlagRegister	; Inhalt FlagRegister in temp laden
		andi	temp, 0b00001111	; oberes Nibble (Lernmodi, Notlaufmodus) auf 0 setzen, damit diese abschalten
		out		FlagRegister, temp	; geänderte Flags zurückschreiben

		sbi		PORTD,ReedLED		; LED aus
		sbic	PIND,ReedSW			; Reed kontakt offen?
		cbi		PORTD,ReedLED		; LED an

		Sbi		PORTA,Cross_LED		; Cross-LED aus
		sbiS	PIND,Cross_SW		; Schalter geschlossen (on GND)?
		Cbi		PORTA,Cross_LED		; Cross-LED an

#if Enable_BlinkRain_for_Cross
		sbis	PIND,Cross_SW		; Schalter geschlossen (on GND)?
		rcall 	blink_CrossMode
#endif

; Regenanzeige nach Status aus dem FlagRegister setzen
		sbi		PortD, RegenLED		; LED (intern) aus
		sbis	Flagregister, Regen	; kein Regen?
		cbi		PORTD,RegenLED		; LED (intern) an
		sbi		PortD, ExternRegen	; LED (extern) aus
		sbic	Flagregister, Regen	; Regen?
		cbi		PORTD,ExternRegen	; LED (extern) an

		ldi		temp,PumpTest		; Anzahl Pumpimpulse in Temp laden
		sbic	PIND,Taste			; Wenn Taste gedrückt
		mov		cPump,temp			; Anzahl Pumpimpulse von Temp nach cPump kopieren

Pump:	tst		cPump				; Anzahl Pulse abgelaufen?
		breq	jump_to_offset		; Ja, dann weiter
		sbic	PIND,Taste			; Taste gedrückt?
jump_to_offset:						; Hilfslabel, weil das Sprungziel für das "breq Offset"
									; (2 zeilen weiter oben) außer Reichweite war
		rjmp	Offset				; Nein -> Weiter, sonst
		cli
		dec		cPump				; Pulszähler 
		sbi		PORTD,6				; Pumpe an
		delay	PumpOnTest
		cbi		PORTD,6				; Pumpe aus
		delay	PumpOffTest
		sei
		rjmp	Pump				; Weiter solange Taster gedrückt

NoTest:	clt							; Flag löschen
		; im folgenden der Abschnitt für die Auswertung des Tasters im Betriebsmode
		; und das setzen des Learnmode
		sbic	PinD, Taste			; Taste gedrückt
		rjmp	End_Tastenauswertung; nein -> Tasterauswertung überspringen

		ldi		temp, 0				; Timer0 (2 Sekunden-Timer) reseten
		out		tcnt0, temp
		clr		cnt2sek

Wait_Taste:
		mov		temp, cnt2sek		
		cpi		temp, 30			; 30 * Timer abgelaufen -> knapp 2 Sekunden vorbei
		brsh	set_Learnmode		; dann zum Setzen des Learnmod springen
		sbis	PinD, Taste			; ansonsten: solange Taste gedrückt
		rjmp	Wait_Taste			; weiterwarten, bis 2 sekunden vorbei
		rjmp	End_Tastenauswertung; falls Taste vorher losgelassen -> beenden, keinen Learnmode setzen
set_Learnmode:		
		in		temp, FlagRegister
		cpi		temp, 0b01000000	; Bit 6 gesetzt? -> aktueller Zustand: Learnmode-Tacho
		brsh	enable_learn_rad	; zu Learnmode-Rad springen
enable_learn_tacho:
		sbi		FlagRegister, Learn_Tacho	; falls Bit 6 nicht gesetzt war -> jetzt setzen -> Learnmode-Tacho an
		ldi		XL, low (s_learn_tacho_start)	; Startaddresse für Learnmode-Tacho laden
		sts		akt_speicherstelle_learnmode,XL ; und Learnmode-Speicherzeiger initialisieren
		clr		temp
clr_sram_learnmode:
		st		X+, temp
		cpi		XL, low(s_learn_rad_end)+1
		brlo	clr_sram_learnmode	; Speicherbereich für Learnmode inititialisieren
		rjmp	End_Tastenauswertung
enable_learn_rad:
		cpi		temp, 0b10000000	; Bit 7 gesetzt? ja: aktueller Zustand: Learnmode-Rad
		brsh	disable_learnmodes	; falls ja: -> fertig mit lernen, Learnmode deaktivieren
									; falls nein: aktueller Zustand: Learnmode-Tacho
		;gelernte Anzahl der Tachopulse in EEPROM und SRAM speichern:
		ldi		XL, Low (s_learn_tacho_eeprom) ; X-Register (Speicherzeiger) initialisieren, Lowbyte
		ld		temp2, X			; temp2 (ins EEPROM zu schreibenden Wert) aus SRAM laden
		cpi		temp2, 1			; Überprüfen, ob mindestens 1 Tachopuls pro Radumdrehung ermittelt wurde
		brlo	nosave_Tacho		; falls nicht -> irgendein Fehler aufgetreten, keine Tachopulse speichern
		ldi		temp, 1				; EEPROM-Addresse in temp laden (1 = Tachopulse)
		rcall	write_eeprom		; Wert ins EEPROM schreiben
		sts		s_Tachopulse, temp2	; Wert im SRAM aktualisieren
nosave_tacho:
		cbi		FlagRegister, Learn_Tacho ; dann: Learnmode-Tacho deaktivieren
		sbi		FlagRegister, Learn_Rad	; Learnmode-Rad aktivieren
		ldi		XL, low (s_learn_rad_start)	; Startaddresse für Learnmode-Rad laden
		sts		akt_speicherstelle_learnmode,XL ; und Learnmode-Speicherzeiger initialisieren
		rjmp	End_Tastenauswertung
disable_learnmodes:
		cbi		FlagRegister, Learn_Rad	; Learnmodes deaktivieren

; debug: alle während der Learnmodes ermittelten Werte nochmal im EEPROM ablegen, um sie hinterher 
; per Ponyprog auslesen und kontrollieren zu können
		ldi		XL, Low (s_learn_tacho_start) ; X-Register (Speicherzeiger) initialisieren, Lowbyte
		ldi		temp, 16			; Startaddresse EEPROM laden
debug_save_sram:
		ld		temp2, X+			; Speicher in Reg laden, postinkrement X-Pointer
		rcall	write_eeprom		; in EEPROM schreiben
		inc		temp				; Speicherstelle EEPROM eins weitersetzen
		cpi		XL, low (s_learn_rad_end)+1 ; Ende der Speicherstellen Learn-Mode erreicht?
		brlo	debug_save_sram		; wenn nein, weiterspeichern
; /debug

		; gelernte Daten für Radkonstante in EEPROM und SRAM speichern
		ldi		XL, Low (s_learn_rad_eeprom) ; X-Register (Speicherzeiger) initialisieren, Lowbyte
		ld		faktor_1, X			; temp2 (ins EEPROM zu schreibenden Wert) aus SRAM laden
		cpi		faktor_1, 50			; Überprüfen, ob mindestens 50 Radumdrehungen pro 333 m ermittelt wurden
		brlo	End_Tastenauswertung; falls nicht -> irgendein Fehler aufgetreten, nix speichern
		; ermittelte Radkonstante (in faktor_1) basiert auf 333 Meter -> Umrechnen in anderes Basisintervall nötig
		; Rad * Intervall / 333 (bzw. Rad * Intervall/2 / 167
		ldi		faktor_2, halbes_intervall
		rcall	multipliziere
		ldi		divisor, 167
		rcall	dividiere
		mov		temp2, quot_l
		ldi		temp, 2				; EEPROM-Addresse in temp laden (2 = Tachopulse)
		rcall	write_eeprom		; Wert ins EEPROM schreiben
		sts		s_Rad, temp2		; Wert im SRAM aktualisieren
		rcall	berechne_Schwellwerte ; an die neue Radkonstante angepaßte Schwellwerte fürs Nachölen berechen

End_Tastenauswertung:
		sbic	FlagRegister, Learn_Tacho
		rjmp	Learnmode_Tacho		
		sbic	FlagRegister, Learn_Rad
		rjmp	Learnmode_Rad
		sbi		PORTD,ReedLED		; LED aus
		sbi		PORTD,RegenLED		; LED aus

		sbi		PORTD,ExternRegen	; LED aus an PD1
		sbic	FlagRegister, Regen	; Regen?
		cbi		PORTD,ExternRegen	; LED an an PD1


		Sbi		PORTA,Cross_LED		; Cross-LED aus
		sbis	PIND,Cross_SW		; Schalter geschlossen (on GND)?
		Cbi		PORTA,Cross_LED		; Cross-LED an

#if Enable_BlinkRain_for_Cross
		sbis	PIND,Cross_SW		; Schalter geschlossen (on GND)?
		rcall 	blink_CrossMode
#endif

Offset:
		cp		Cr_cnt,Cr_soll
		brge	OffsPumpOK

AutoPump:
		cli
		sbi		PORTD,6				; Pumpe an
		delay	PumpOn				; warten
		cbi		PORTD,6				; Pumpe aus
		delay	PumpOff				; warten
		sei
		inc		Cr_cnt				; und 1 drauf
		cp		Cr_cnt,Cr_soll		; Fertig ?
		brlo	AutoPump			; Wenn kleiner, dann nochmal
		ldi		Cr_soll,0			; wieder auf Def 0 Impulse

OffsPumpOK:
		sbi		PORTB,PB2			; Regensensor negativ
		cbi		PORTB,PB3
		freq						; 0,25ms warten


		sbic	PinA,Zuendung		; Zündung an?
		rjmp	LoopEnd				; Wenn ja -> LoopEnd (nicht einschlafen lassen)

		mov		temp, Timer1Cnt
		cpi		temp, sleepmode
		brlo	LoopEnd				; wenn Timer1 2mal abgelaufen (=30 sek), dann
									; vorbereitungen zum einschlafen treffen
		sbic	FlagRegister,Notbetrieb	; im Notbetrieb?
		rjmp	Ausnahme			; dann einschlafen in der Ausnahme-Routine

		sbis	PIND,ReedSW			; wenn's Rad genau auf dem Reed steht
		rjmp	Ausnahme			; Sonderbehandlung

		sbi		PortA, cross_LED	; Cross-LED aus
		ldi		temp,0b00110110
		out		PORTD,temp			; Pull-ups für Taster + Cross-SW
									; ausschalten, Pull-Ups für LEDs (=LED aus)
									; und Reed bleiben aktiviert
		clr		temp
		out		PORTB,temp			; Port B Pull-ups aus
		sbi		ACSR,ACD			; Komparator aus
		ldi		temp,0b00011000		; 
		out		WDTCR,temp			; Watchdog aus vorbereiten
		clr		temp
		out		WDTCR,temp			; Watchdog aus
		ldi		temp,0b00110000		; Int 0 Level, Powerdown
		out		MCUCR,temp 

		sleep						; power down

		ldi		temp,0b00011000		; 
		out		WDTCR,temp			; Watchdog Änderung vorbereiten
		ldi		temp,0b00001111		; 
		out		WDTCR,temp			; Watchdog an 2s
		ldi		temp,0b00110010		; Int 0 fallende Flanke, Powerdown
		out		MCUCR,temp
		cbi		ACSR,ACD			; Komparator an
		ldi		temp,0b11110000		; 
		out		PORTB,temp			; Port B Pull-ups im oberen Nibble ein
		ldi		temp,0b00111111
		out		PORTD,temp			; Port D Pull-ups einschalten

#if Enable_LED_Test
		rcall	LED_Test
#endif


LoopEnd:
		rjmp	Loop				; wieder von vorne beginnen

Ausnahme:
		clr		temp
		out		GIMSK,temp			; Int0/1 disable
		out		PORTB,temp			; Port B Pull-ups aus
		ldi		temp,0b00110110		; LEDs aus und Taste/Cross-SW auschalten
		out		PORTD,temp
		sbi		PortA,Cross_LED		; CrossLED aus
		sbi		ACSR,ACD			; Komparator aus
		
		wdr
		ldi		temp,0b00011000		; 
		out		WDTCR,temp			; Watchdogänderung vorbereiten
		ldi		temp,0b01000111		; 
		out		WDTCR,temp			; Watchdog an 2s, Interruptmode

WD_Sleep:		; Sprungpunkt für Watchdog-überwachtes Schlafen
		wdr

		sbic	FlagRegister,Notbetrieb	; im Notbetrieb?
		rjmp	Notlauf_Sleep		; dann Notlauf-Sleeproutine abarbeiten

		sbic	PIND,ReedSW			; Reed geschaltet
		rjmp	WakeUp				; Nein, dann aufwachen, sonst
		rjmp	Schlafen		

Notlauf_Sleep:

		ldi		temp,0b00110000		; Int 0 Level, Powerdown
		out		MCUCR,temp 
		ldi		temp,0b01000000
		out		GIMSK,temp			; Int 0 Enable

		sbic	PinA,Zuendung		; Zündung an?
		rjmp	WakeUp				; Ja -> aufwachen

Schlafen:
		sleep

		rjmp	WD_Sleep

WakeUp: 		; aufwachen und zurück zum regulären programmablauf
		ldi		temp,0b00110010		; Int 0 fallende Flanke, Powerdown
		out		MCUCR,temp
		ldi		temp,0b00111111		; PortD Pull-ups ein
		out		PORTD,temp
		cbi		ACSR,ACD			; Komparator ein
		ldi		temp,0b11110000		; 
		out		PORTB,temp			; Port B Pull-ups im oberen Nibble ein

		wdr
		ldi		temp,0b00011000		; 
		out		WDTCR,temp			; Watchdogänderung vorbereiten
		ldi		temp,0b0001111		; 
		out		WDTCR,temp			; Watchdog an 2s, Resetmode

		ldi		temp,0b01000000
		out		GIMSK,temp			; Int 0 Enable

#if Enable_LED_Test
		rcall	LED_Test
#endif
		
		rjmp	Loop				; und wieder von vorne

;**************************************************************** 
; Reed Impuls, Zählen         ; 
;**************************************************************** 
Reed:
		push	temp				; Temp-Reg sichern
		push	temp2
		in		temp,SREG			; Status-Reg sichern 
		push	temp

		clr		Timer1Cnt			; 15 Sekunden-Zähler resetten
		
		sbis	PIND,Taste			; Taste gedrückt? 
		rjmp	Reed_end

		brts	Reed_End_halfway	; Testmode -> Zurück

#if Force_ReedDelay_Off
		rjmp	no_reeddelay		; ReedDelay immer ausgeschaltet -> überspringen
#endif


		lds		temp, s_Tachopulse	; Anzahl Tachopulse laden
#if Force_ReedDelay_On
		ldi		temp, delay_automatic	; ReedDelay immer angeschaltet -> temp passend laden, so daß der nachfolgende Vergleich
										; immer dazu führt, das Delay zu aktivieren
#endif
		cpi		temp, delay_automatic+1
		brsh	no_reeddelay		; Anzahl Tachopulse > Umschaltschwelle? -> kein Delay nötig, da vermutlich Tacho verwendet

		; ansonsten: Timer passend setzen, um den den Reedinterrupt für die
		; gewünschte Zeit zu deaktivieren
		clr		temp
		out		GIMSK,temp			; Reed-Interrupt ausschalten

		in		temp,TCNT0			; aktuellen Zählerstand (Counter0) laden
		ldi		temp2,EntprellTimer	; Anzahl Zählerschritte für Entprelldelay laden
		add		temp,temp2				; zu aktuellem Zählerstand addieren
		brcs	Add_Overflow		; bißchen Rechnerei, um Sonderfälle: Overflow
		cpi		temp,252				; oder Wert größer als 252 abzufangen,
		brsh	ueber_252			; da der Timer0 ja nur bis 252 läuft und nicht bis
		rjmp	Load_Entprelltimer	; zum überlauf bei 255
Add_Overflow:
		subi	temp, -3
		rjmp	Load_Entprelltimer
Ueber_252:
		subi	temp,252
Load_EntprellTimer:
		out		OCR0B,temp			; Timer0 Comp_Match_Reg_B mit Zählerstand + Entprelldelay laden
									; beim Compare-Match (also nach Ablauf des Delays) wird dann der
									; Reed-Interrupt wieder eingeschaltet
no_reeddelay:
		cbi		FlagRegister,Notbetrieb	; kein Notbetrieb mehr

		sbic	FlagRegister,Learn_Tacho	; im Learnmode-Tachopulse? -> zur Speicherroutine springen
		rjmp	Lerne_Tachopulse

		inc		CntTacho   			; Zähler für Tachopulse erhöhen
		lds		temp,s_Tachopulse	; mit Vorgabewert für Tachopulse vergleichen
		cp		CntTacho,temp		; wenn größer, weitermachen (umdrehungszähler erhöhen...)
		brne	Reed_end_halfway	; sonst Reed-Routine beenden

		clr		CntTacho			; Zähler für Tachopulse zurücksetzen

		sbic	FlagRegister,Learn_Rad	; im Learnmode-Radkonstante? -> zur Speicherroutine springen
		rjmp	Lerne_Radkonstante

		; bestimmen der Regenmenge in den letzten 333 m
		sbic	FlagRegister, Regen	; wenn Regen
		inc		Regenanteil			; dann Regenanteilszähler erhöhen

		lds		temp, CntRad_prog	; Radumdrehungszähler für Geschwindigkeitsprogression laden
		inc		temp				; um 1 erhöhen
		sts		CntRad_prog, temp	; und wieder speichern
		rjmp	No_ReedEnd
Reed_End_halfway:					; Hilfs-Sprungmarke für Reed_end
		rjmp	Reed_End
No_ReedEnd:

#if Enable_ExtraOelen
		lds		temp, CntRad_rain	; Zähler fürs Nachölen laden
		dec		temp				; um 1 verringern
		breq	Nachoelen			; falls temp = 0 -> zum nachölen springen
		sts		CntRad_rain, temp	; sonst: Zählerstand wieder speichern
		rjmp	Normal_Reed			; normal weitermachen



Nachoelen:
		rcall	berechne_Schwellwerte ; damit wird der Zähler fürs Nachölen wieder passend gesetzt
		mov		temp2, Regenanteil	; da "Regenanteil" noch benötigt, gleich jedoch zurückgesetzt wird
									; den wert in "temp2" speichern
		clr		Regenanteil			; Regenanteil wieder auf 0 setzen, um die Regenmenge im nächsten 
									; Intervall zu bestimmen
;####################################################################
;########### Code zum Ölen ---->NACH<---- Regen #####################

Regenpruefung:
		lds		temp, RSchwelle	
		cp		temp2,temp			; temp2 = Regenanteil, temp = Schwellwert naß
									; letzte 333m überwiegend Regen?
									
		brlo	Trocken				; nein, auf überwiegend trocken prüfen
		cpi		Regenmerker,RGrenze	; ja, deshalb Prüfung auf mindestens 3000m Regen
		breq	Normal_Reed			; es hat (in der vergangenheit) mind. 3000m überwiegend
									; geregnet und regnet noch!
		inc		Regenmerker			; es regnet, aber noch keine 3000m Regenmerker erhöhen!
		cpi		Regenmerker,RGrenze+1	; Hat es während dem ZusatzÖlen nach dem Regen
									; wieder angefangen zu Regnen?
		brlo	Normal_Reed			; nein, kein Eingriff nötig
		ldi		Regenmerker,RGrenze	; ja, Merker wird auf 3000m Regen gesetzt
		rjmp	Normal_Reed			; Programm normal weitermachen

Trocken:
		cpi		Regenmerker,0		; ist Regenmerker ungleich 0?
		breq	Normal_Reed			; gleich 0 (es IST und WAR überwiegend trocken)=> normal weitermachen
		cpi		Regenmerker,RGrenze	; ungleich 0 (es WAR überwiegend nass) => Hat es mindestens 3000m geregnet?
		brsh	Oelen				; ja, und es ist jetzt nicht mehr überwiegend nass (=> evtl. ölen)
		ldi		Regenmerker,0		; nein (max 2666m überwiegend Regen)
									; => Regenmerker wieder auf Trocken setzen!
		rjmp	Normal_Reed			; normal weiter, da nur kurz geregnet

Oelen:
		lds		temp, TSchwelle
		cp		temp2,temp			; temp2 = Regenanteil, temp = Schwellwert trocken
									; Ist es nach Regen schon abgetrocknet?
		brsh	Normal_Reed			; Regenanteil > TSchwelle -> noch nichts tun, da noch zu nass

		inc		Regenmerker			; Regenmerker wird auf 10-15 erhöht!
									; (nach Regen ist es jetzt ziemlich trocken)
		cpi		Regenmerker,TGrenze	; 333m - 666m Trocken nach 1000m Regen?
		brlo	Normal_Reed			; ja, noch warten, [1000m oder mehr trocken => wird geölt]

		cpi		Regenmerker,PumpMax+1	; sind wir schon beim letzten. Mal Pumpen?
		brlo	Pumpen				; weniger als Pumpmax gepumpt: Pumpe aktivieren
		ldi		Regenmerker,0		; genug gepumpt: Regenmerker auf Trockenzustand setzen

;########### Code zum Ölen ---->NACH<---- Regen #####################
;####################################################################
#endif
Normal_Reed:
		inc		CntRad				; Umdrehungszähler erhöhen 
		lds		Temp,s_Rad
		cp		CntRad,temp			; Radkonstante erreicht? 
		brlo	Reed_end

		clr		CntRad				; Umdrehungszähler löschen 
		inc		CntWert				; 333m-Zähler erhöhen 

		cp		CntWert,Wert		; Vergleichswert erreicht? 
		brlo	Reed_end 

Pumpen:
		ldi		Cr_soll,PumpNormal	; $PumpNormal laden
#if !Add_Rain
		sbic	FlagRegister, Regen ; Regen?
		ldi		Cr_soll, PumpRegen	; ja, und Add_Rain nicht  gesetzt -> PumpRegen laden
									; falls Add_Rain gesetzt erfolgt die Addition der Regenimpulse
									; erst am Ende, weil sie ja zu den Cross-Impulsen auch
									; dazugerechnet werden sollen
#endif
		sbis	PIND,Cross_SW		; PD0 Kontakt geschlossen? 
		ldi		Cr_soll,PumpCross	; ja, dann $PumpCross Impulse 
#if Add_Rain
		sbic	FlagRegister, Regen ; Regen?
		subi	Cr_soll, -PumpRegen	; ja, und Add_Rain gesetzt -> PumpRegen addieren
#endif

		clr		CntWert				; 333m-Zähler zurücksetzen 
		;Pumpe aktivieren 
		clr		Cr_cnt				; damit startet die Pumpe im Hauptprogr 
Reed_end:
		pop		temp
		out		SREG,temp			; Status Reg zurückschreiben 
		pop		temp2
		pop		temp				; Temp zurückschreiben
		reti						; Reed-Interrupt beenden

lerne_tachopulse:
		lds		XL, akt_speicherstelle_learnmode	; Speicherzeiger initialisieren
		ld		temp, X								; Inhalt von aktueller Speicherstelle laden
		inc		temp								; um eins erhöhen
		brne	lerne_tachopulse_no_overflow		; falls nach dem Erhöhen der Wert 0 ist,
													; trat ein Overflow aus
		ldi		temp, 255							; dann wieder den Wert auf 255 setzen
													; mehr als 255 Tachopulse pro Radumdrehungen geht halt nicht
lerne_tachopulse_no_overflow:
		st		X+, temp							; Wert wieder speichern, Speicherzeiger um 1 erhöhen
		cpi		XL, Low (s_learn_tacho_end) + 1		; zeigt er noch auf eine Addresse innerhalb des gewünschten Bereichs?
		brlo	end_lerne_tachopulse				; ja -> beenden
		ldi		XL, low(s_learn_tacho_start)		; nein -> auf Anfang des Bereichs setzen
end_lerne_tachopulse:
		sts		akt_speicherstelle_learnmode, XL	; Speicherzeiger sichern
		rjmp	Reed_end							; Ende

lerne_radkonstante:
		lds		XL, akt_speicherstelle_learnmode	; Speicherzeiger initialisieren
		ld		temp, X								; Inhalt von aktueller Speicherstelle laden
		inc		temp								; um eins erhöhen
		brne	lerne_radkonstante_no_overflow		; falls nach dem Erhöhen der Wert 0 ist,
													; trat ein Overflow aus
		ldi		temp, 255							; dann wieder den Wert auf 255 setzen
													; mehr als 255 Radumdrehungen in 333 Metern geht halt nicht
lerne_radkonstante_no_overflow:
		st		X+, temp							; Wert wieder speichern, Speicherzeiger um 1 erhöhen
		cpi		XL, Low (s_learn_rad_end) + 1		; zeigt er noch auf eine Addresse innerhalb des gewünschten Bereichs?
		brlo	end_lerne_radkonstante				; ja -> beenden
		ldi		XL, low(s_learn_rad_start)			; nein -> auf Anfang des Bereichs setzen
end_lerne_radkonstante:
		sts		akt_speicherstelle_learnmode, XL	; Speicherzeiger sichern
		rjmp	Reed_end							; Ende
;************************************** 
;################# PROGRAMM ENDE #########################
;#########################################################
;#########################################################
