;****************************************************************
;                     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


;################################################################
;##                                                            ##
;##             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	=10		; 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
#define Enable_ReedDelay (1); auf 1 setzen, um das ReedDelay zu aktivieren
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;Einstellungen fürs "Nach dem Regen Extraölen"
;für die Strecken bitte nur Werte >0 verwenden
.equ	RStrecke	=5		; Mindeststrecke Regen in km
.equ	TStrecke	=1		; Mindeststrecke Trocken in km
.equ	Pumpstoesse =5		; 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
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 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			=3
; .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 (40 x 15 Sek. = 10 Minuten)
.equ	NotIntervall=8		; Pumpintervall im Notbetrieb (8x15 = 2 Minuten)
#define	Enable_BlinkNotlauf (1)	; auf 0 setzen, um das Blinken der Regen-LED im Notlauf zu deaktivieren
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Einstellungen Pumpe:
; - Anzahl Pumpimpulse (Normal, Regen, Cross, max. Pumpstöße im Testmode)
; - Dauer der Pumpimpulse + Pause im Normal- und Testmode
.equ PumpCross		=8		; im Crossmode 8 Pumpstöße
.equ PumpNormal		=1		; im Normalmode 1 Pumpstoß
.equ ExtraRegen		=1		; ZUSÄTZLICHE Pumpstöße im Regen, 0: keine Extrapumpstöße
; bei .equ ExtraRegen = 1 werden also aus 1 Pumpstoß im Normalmode 2 im Regen,
; und aus 8 Pumpstößen im Crossmode 9 im Regen.
.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			=200	; Einschaltzeit Pumpe im Betriebsmodus, max 255, Angabe in Millisekunden
.equ PumpOff		=200	; Ausschaltzeit Pumpe im Betriebsmodus, max 255, Angabe in Millisekunden
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Einstellungen geschwindigkeitsabhängiges Ölen
; Geschwindigkeitsangabe theoretisch zulässig im Bereich 4-500 km/h
#define Enable_SpeedProgression (1)	; auf 1 setzen, um geschwindigkeitsabhängiges Ölen zu aktivieren
.equ speed_12_5		=100	; Geschwindigkeit, ab der um 12,5% verkürzt wird
.equ speed_25		=130	; Geschwindigkeit, ab der um 25% verkürzt wird
.equ speed_37_5		=160	; Geschwindigkeit, ab der um 37,5% verkürzt wird
.equ speed_50		=190	; Geschwindigkeit, ab der um 50% verkürzt wird
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;Einstellungen für blinkende LEDs als kleine
;Statusmeldungen über die Arbeit des McCoi
;im Sleepmode bleiben die LEDs natürlich aus
#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	Meter_12_5	=speed_12_5/3.6+1	; Hilfswerte für die Berechnung der Radumdrehung in 2 Sekunden
.equ	Meter_25	=speed_25/3.6+1		; Hilfswerte für die Berechnung der Radumdrehung in 2 Sekunden
.equ	Meter_37_5	=speed_37_5/3.6+1	; Hilfswerte für die Berechnung der Radumdrehung in 2 Sekunden
.equ	Meter_50	=speed_50/3.6+1		; Hilfswerte für die Berechnung der Radumdrehung in 2 Sekunden
; eigentlich Umrechnung von km/h in m/s, die Addition von 1 erfolgt, um die Werte zwangsweise aufzurunden
; weil die Division, für die sie später benötigt werden, konsequent abrundet, so gleicht sich der Fehler
; ein bißchen aus

.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	Notbetrieb	=0		; Bit 0 in GPIOR0 wird als Flag für den Notbetrieb genutzt
.equ	Learn_Tacho =1		; Bit 1 in GPIOR0 wird als Flag für den Learnmode-Tachopulse genutzt
.equ	Learn_Rad	=2		; Bit 2 in GPIOR0 wird als Flag für den Learnmode-Radkonstante genutzt

.equ	RGrenze		=RStrecke*3
.equ	TGrenze		=RGrenze+TStrecke*3
.equ	PumpMax		=TGrenze+Pumpstoesse-1


.equ	CntRad_alt  =0x0060		; Speicherstelle Radumdrehung bei letzte Messung -> für Geschwindigkeitsprogression
.equ	s_Tachopulse=0x0061		; Speicherstelle Tachopulse: am Programmstart aus EEPROM initialisiert
.equ	s_Rad		=0x0062		; Speicherstelle Radkonstante
.equ	akt_Speicherstelle=0x0063 ; Speicherstelle aktuelle Position im Wertspeicher für Durchschnittsberechnung
.equ	Wertspeicher=0x0064		; 8 Speicherstellen: 0x0064 - 0x006b

.equ	RSchwelle	=0x006c			; Speicherstelle für Schwellwert überwiegend Regen
.equ	TSchwelle	=0x006d			; Speicherstelle für Schwellwert überwiegend Trocken

.equ	s_Umdrehung_12_5=0x006e		; Speicherstelle für die Radumdrehung für 12,5% Verkürzung
.equ	s_Umdrehung_25	=0x006f		; Speicherstelle für die Radumdrehung für 25% Verkürzung
.equ	s_Umdrehung_37_5=0x0070		; Speicherstelle für die Radumdrehung für 37,5% Verkürzung
.equ	s_Umdrehung_50	=0x0071		; Speicherstelle für die Radumdrehung für 50% Verkürzung

.equ	s_learn_tacho_start	= 0x0072	; Start Speicherplatz für Learnmode Tachopulse
.equ	s_learn_tacho_eeprom= 0x0077	; enthält den nach dem Lernen zu speichernden Wert
.equ	s_learn_tacho_end	= 0x007b	; Ende Speicherplatz Learnmode Tachopulse
		; 10 Speicherplätze -> 10mal Rad drehen
.equ	s_learn_rad_start	= 0x007c	; Start Speicherplatz für Learnmode Radkonstante
.equ	s_learn_rad_eeprom	= 0x007d	; enthält den nach dem Lernen zu speichernden Wert
.equ	s_learn_rad_end		= 0x007e	; Ende Speicherplatz für Learnmode Radkonstante
		; 3 Speicherplätze -> 3mal 333 Meter = 1000 Meter fahren
.equ	akt_speicherstelle_learnmode = 0x007f ; Zeiger auf die aktuell zu nutzende SRAM-Addresse im Learnmode
; Speicherbelegung (SRAM) insgesamt:
; 0x0060 -> CntRad_alt -> alter Stand Raddrehzahl, um aus aktueller Raddrehzahl die Anzahl der Umdrehung
;			in den letzten 2 Sekunden (und damit die Geschwindigkeit) berechnen zu können
; 0x0061 -> Tachopulse
; 0x0062 -> Radkonstante
; 0x0063 -> zeigt die aktuell zu ändernde Position im Wertspeicher an
; 0x0064-0x006b -> 8 Speicherstellen: die jeweils letzten 8 berechneten Verkürzungswerte werden hier
;			zyklisch gespeichert und dann der Durchschnitt daraus als tatsächliche Intervallverkürzung benutzt
; 0x006c -> RSchwelle (berechnet)
; 0x006d -> TSchwelle (berechnet)
; 0x006e -> berechnete Anzahl Raddrehung in 2 Sekunden für 12,5% Verkürzung
; 0x006f -> berechnete Anzahl Raddrehung in 2 Sekunden für 25% Verkürzung
; 0x0070 -> berechnete Anzahl Raddrehung in 2 Sekunden für 37,5% Verkürzung
; 0x0071 -> berechnete Anzahl Raddrehung in 2 Sekunden für 50% Verkürzung
; 0x0072 -> Start Speicherplatz für Learnmode-Tachopulse, insgesamt 10 Speicherstellen -> 10 Radumdrehungen
; 0x0076 ->	enthält den ins EEPROM zu übernehmenden Wert für die Tachopulse
; 0x007b -> Ende Speicherplatz für Learnmode-Tachopulse
; 0x007c -> Start Speicherplatz Learnmode 

;-----low Register
.def	Time1		=r1
.def	Time2		=r2
.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	TimeP		=r9
.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

.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 

;****************************************************************
.macro delay						; Warteschleife, x mal 1ms 

		ldi		C0,@0
WGLOOP0: 
		ldi		C1,$1F
WGLOOP1: 
		ldi		C2,$2A
WGLOOP2:
		dec		C2
		brne	WGLOOP2
		dec		C1
		brne	WGLOOP1
		dec		C0
		brne	WGLOOP0
.endmacro
;########################## NEUES DELAY-MAKRO '''''''''''''''

.macro	freq						; Warteschleife 0,25 ms
		ldi 	c2,250
f0:		nop
		dec 	c2
		brne 	f0
.endmacro

;************** Blink-Unterprogramm für externe RegenLED *******
blink:
		push	temp
		ldi		temp,10
BlinkStart:
		sbis	PortD,ExternRegen
		rjmp    ExtRegenAn
		rjmp	ExtRegenAus
ExtRegenAn:
		sbi		PortD,ExternRegen
		rjmp	BlinkDelay
ExtRegenAus:
		cbi		PortD,ExternRegen
BlinkDelay:
		delay	200
		dec		temp
		brne	BlinkStart
		pop		temp
		ret


;*** Unterprogramm zur Berechnung der Radumdrehungen für's geschwindigkeitsabhängige Ölen ***
;********************************************************************************************
;*** Voraus ein Wort zur geschwindigkeitsabhängigen Wegverkürzung:
;*** das ganze wird realisiert, indem 2 Sekunden lang die Radumdrehungen gezählt werden,
;*** und dieser Wert dann mit den aus den gegebenen Verkürzungsgeschwindigkeiten
;*** berechneten Raddrehzahlen verglichen wird. Dieses Zählen und vergleichen passiert in der 
;*** "timer0_comp_match"-Routine
;*** hier werden die Radumdrehungen für die 4 Geschwindigkeiten berechnet
;*** und im SRAM abgelegt, damit sie dann in der Vergleichsroutine zur Verfügung stehen.
;*** Die Formel für die Umrechnung ist:
;*** ("km/h" / 3,6) * (Radkonstante / 333 Meter) * 2
;*** also erst Umrechnung in m/sek,
;*** dann Multiplikation mit 1/Radumfang ("333 Meter / Radkonstante" entspricht ja dem Radumfang)
;*** und zum Schluß nochmal eine Multiplikation mit 2, weil ja 2 Sekunden lang Radumdrehungen gezählt
;*** werden sollen. Aus 100 km/h ergibt sich so: 27,78 m/s * 168/333 -> 14 Radumdrehungen in 1 Sekunde * 2
;***  -> 28 Radumdrehungen in 2 Sekunden. Paßt, Radkonstante 168 entspricht ja knapp 2 Metern Radumfang.
;*** Würde ich z.b. mit der Radkonstante 183 rechnen, wie ich sie verwende (Reed am Vorderrad) kämen
;*** erhalte ich ca. 30 Radumdrehungen in 2 Sekunden bei 100 km/h
;***
;*** Der erste Teil der Rechnung (km/h -> m/s) erfolgt schon im Programmkopf in den Zeilen:
;*** .equ	Meter_12_5	=speed_12_5/3.6 + 1...
;*** der Compiler berechnet beim Übersetzen des Programmes die entsprechenden Werte		
;***
;*** da allerdings die Radkonstante durch den Learnmode beim Compilieren nichtmehr als bekannt voraus-
;*** gesetzt werden kann, muß der Teil der Berechnung, der sich auf sie bezieht, jetzt dynamisch erfolgen
;*** dieses passiert in der folgenden Routine:

		; zuerst werden die m/s-Werte in den Speicher geladen, und zwar in die 4 Speicherstellen, 
		; die direkt im Anschluß nach TSchwelle liegen, und später dann die Anzahl der entsprechenden
		; Radumdrehung enthalten sollen (siehe auch die Kommentare am Anfang des Quelltextes zur Speicherbelegung
berechne_radumdrehungen:
		ldi		XH, high (s_Umdrehung_12_5)
		ldi		XL, low (s_Umdrehung_12_5) 	; X-Register initialisieren
		ldi		temp, Meter_12_5
		st		X+, temp
		ldi		temp, Meter_25
		st		X+, temp
		ldi		temp, Meter_37_5
		st		X+, temp
		ldi		temp, Meter_50
		st		X+, temp

		; ab hier beginnt die Berechnung: "m/s" * Radkonstante / 333 * 2
		; da ich aber nicht durch 333 dividieren kann, sondern maximal durch 255 (8 Bit)
		; wird aus (Radkonstante / 333) * 2 -> Radkonstante / 166
		; der Rundungsfehler ist angesichts der sowieso vorhandenen Ungenauigkeiten völlig irrelevant
		
		ldi		XL, Low(s_Umdrehung_12_5)	; Speicherzeiger initialisieren, so daß er auf die
											; Speicherstelle für die 12,5%-Verkürzung zeigt
		
start_multiplikation:
		lds		faktor_1,s_Rad		; Faktor1 laden = Radkonstante
		ld		faktor_2,X			; Faktor2 laden = Meter/Sekunde

		rcall	multipliziere 		; multipliziert den Inhalt der Register faktor_1 und faktor_2,
									; Ergebnis steht danach in prod_l und prod_h (aka temp und temp2)

		; ab hier Division des Ergebnisses der Multiplikation durch 166
		; laden des Dividends entfällt, da dafür die gleichen Register wie für das Ergebnis der
		; Multiplikation genutzt werden, die sind also schon korrekt belegt

		ldi		divisor, 166		; 333 Meter / 2

		rcall	dividiere

		st		X+,quot_l			; Lowbyte des Ergebnisses (= Radumdrehungen in 2 Sekunden bei
									; entsprechender Geschwindigkeit) speichern
									; Highbyte ist sowieso 0, entfällt daher

		cpi		XL, Low(s_Umdrehung_50)+1 ; schon alle 4 Werte berechnet?
		brlo	start_multiplikation	; wenn nein, zur Berechnung des nächsten Wertes springen

;debug: Werte ins EEPROM schreiben zur kontrolle per Ponyprog
;		nach Beendigung der Speicherns kurz die internen LEDs aufblinken lassen
		ldi		temp, 8
		ldi		temp2, speed_12_5
		rcall	write_eeprom
		ldi		temp, 9
		lds		temp2, s_umdrehung_12_5
		rcall	write_eeprom

		ldi		temp, 10
		ldi		temp2, speed_25
		rcall	write_eeprom
		ldi		temp, 11
		lds		temp2, s_umdrehung_25
		rcall	write_eeprom

		ldi		temp, 12
		ldi		temp2, speed_37_5
		rcall	write_eeprom
		ldi		temp, 13
		lds		temp2, s_umdrehung_37_5
		rcall	write_eeprom

		ldi		temp, 14
		ldi		temp2, speed_50
		rcall	write_eeprom
		ldi		temp, 15
		lds		temp2, s_umdrehung_50
		rcall	write_eeprom
		cbi		PortD,ReedLED
		cbi		PortD,RegenLED
		delay	25
		sbi		PortD,ReedLED
		sbi		PortD,RegenLED
;/debug

		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_) 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

;**************************************************************** 
; Timer0 Compare Match A        ; 
;**************************************************************** 
; alle Prozentangaben der Streckenverkürzung (12,5/25/37,5/50) sind nur ca. Werte
; durch das grobe Basisintervall (333 Meter) ist eine exakte Angabe garnicht möglich
; die Berechnungsvorschriften für die einzelnen Verkürzungen wurden mit Hilfe von
; OO-Calc so zurechtgebogen, daß die Ergebnisse sinnvoll gerundet sind.

timer0_comp_match:

		wdr
		push	temp				; Temp-Reg sichern
		push	temp2				
		in		temp,SREG			; Status-Reg sichern 
		push	temp
		push	c0					; c0 sichern, da es in der Routine als drittes Temp-Reg
									; "mißbraucht" wird
		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,-8				; Offset addieren (min 8 x 333m = 2666m)
		sbic	PORTD,ExternRegen	; RegenLED an?
		rjmp	NoRain				; Nein -> Sprung zu NoRain
		lsr		temp				; sonst: Weg = Weg / 2
		subi	temp,-1				; + 1 x 333m
NoRain:
		mov		wert,temp			; berechneten Vergleichswert im richtigen Reg. speichern

		sbic	GPIOR0,Notbetrieb	; Notbetriebsmodus?
		rjmp	T0_CM_End			; dann Routine beenden

#if Enable_SpeedProgression
		lds		temp, CntRad_alt	; alte Umdrehungsanzahl laden
		mov		c0, CntRad			; Radumdrehung ermitteln, c0 enthält dann die
		sub		c0, temp			; Anzahl der Radumdrehungen in den letzten 2 Sekunden
		sts		CntRad_alt, CntRad	; Radumdrehungen speichern, um sie dann beim nächsten Mal benutzen zu können

		mov		temp, wert			; temp wird jetzt zur Berechnung der Verkürzung genutzt
		lsr		temp				; 50% Wert berechnen, wird sowieso jedesmal benötigt
		lds		temp2, s_Umdrehung_50
		cp		c0,temp2			; Radumdrehung mit Mindestumdrehung für 50% Verkürzung vergleichen
		brsh	Sub_Verkuerzung		; gleich oder mehr -> zum Abzug von 50% springen
		lds		temp2, s_Umdrehung_37_5
		cp		c0,temp2			; Radumdrehung mit Mindestumdrehung für 37,5% Verkürzung vergleichen
		brsh	Verkuerzung_37_5	; gleich oder mehr -> zum Abzug von 37,5% springen
		lds		temp2, s_Umdrehung_25
		cp		c0,temp2			; Radumdrehung mit Mindestumdrehung für 25% Verkürzung vergleichen
		brsh	Verkuerzung_25		; gleich oder mehr -> zum Abzug von 25% springen
		lds		temp2, s_Umdrehung_12_5
		cp		c0,temp2			; Radumdrehung mit Mindestumdrehung für 12,5% Verkürzung vergleichen
		brsh	Verkuerzung_12_5	; gleich oder mehr -> zum Abzug von 12,5% springen
		rjmp	Speichere_Wert		; keine Verkürzung nötig, zur Durchschnittsbildung springen

Verkuerzung_12_5:					; Wegverkürzung um ca. 12,5%
		lsr		temp				; /2
		lsr		temp				; /2 -> insgesamt teilen durch 8 = 12,5%
		sbrc	wert,2				; wenn Bit2 im Ausgangwert gesetzt
		inc		temp				; denn die errechnete Verkürzung um 1 erhöhen
									; um mathematisch korrekte Rundung des Ergebnisses
									; zu erreichen
		rjmp	Sub_Verkuerzung		; zum Subtrahieren der Verkürzung springen

Verkuerzung_25:						; Wegverkürzung um ca. 25%
		lsr		temp				; /2 -> insgesamt teilen durch 4 = 25%
		sbrs	wert,1				; Bit 1 in Ausgangswert gesetzt?
		rjmp	Sub_Verkuerzung		; Nein, zum Subtrahieren der Verkürzung springen
		sbrc	wert,0				; Ja, und Bit0 im Ausgangswert gesetzt?
		inc		temp				; Ja, errechnete Verkürzung um 1 erhöhen -> Rundung verbessern
		rjmp	Sub_Verkuerzung		; zum Subtrahieren der Verkürzung springen

Verkuerzung_37_5:					; Wegverkürzung um ca. 37,5%
									; 100% + 12,5% - 50% = 37,5%
		push	temp				; 50%-Wert zwischenspeichern
		lsr		temp				; /2
		lsr		temp				; /2 -> insgesamt durch 8 = 12,5%
		sbrs	wert,2				; wenn Bit2 in Ausgangswert gesetzt
		rjmp	add_37_5
		sbrc	wert,0				; wenn Bit0 im Ausgangswert nicht gesetzt
		rjmp	add_37_5
		inc		temp				; 12,5%-Wert korrigieren -> Rundung verbessern
add_37_5:
		add		wert,temp			; 12,5%-Wert addieren
		pop		temp				; 50% Wert vom Stack laden

Sub_Verkuerzung:
		sub		wert, temp			; errechneten Verkürzungswert abziehen

		; Berechnung des Ölintervalles auf Basis der letzten 8 ermittelten Werte
		; mit dem Ziel, die Wegverkürzungsfunktion etwas zu glätten und nicht so stark auf
		; kurzzeitige Spitzenwerte reagieren zu lassen.
Speichere_Wert:
		lds		XL,akt_Speicherstelle	; Aktuelle Speicherstelle laden (0x64-0x6b)
		st		X+,Wert					; Wert an passender Speicherstelle sichern
		cpi		XL,0x6c					; aktuelle Speicherstelle =0x6c
		brlo	Obergrenze_nicht_erreicht	; Nein, zu "Obergrenze_nicht_erreicht" springen
		ldi		XL,Low(Wertspeicher)	; ja: auf Untergrenze (0x64) setzen
Obergrenze_nicht_erreicht:
		sts		akt_Speicherstelle,XL	; Speicherstelle sichern für nächsten Berechnungsdurchlauf
		ldi		XH,High(Wertspeicher)	; Addresse Wertspeicher laden, High-Anteil
		ldi		XL,Low(Wertspeicher)	; Addresse Wertspeicher laden, Low-Anteil
		clr		c0						; c0 = 0 (wird gleich benötigt)
Durchschnittsberechnung:
		ld		temp,X+					; die 8 gespeicherten Werte laden
		add		c0,temp					; und in c0 aufsummieren
		cpi		XL,0x6c
		brne	Durchschnittsberechnung
	
		lsr		c0						; /2
		lsr		c0						; /2						
		lsr		c0						; /2 -> /8, Durchschnitt der letzen 16 Sekunden bestimmt
		mov		Wert,c0					; Wert auf den Durchschnitt der letzten 16 sek. setzen
#endif

T0_CM_End:
		pop		c0					; c0 zurückschreiben
		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
		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

		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
		cpi		temp, 0				; temp (entspricht Notintervall) gleich 0?
		brne	T1_CM_Weiter		; wenn ungleich 0: statische Zeiten, Berechnung der
									; dynamischen Intervalle überspringen

		mov		NotIntervallReg, wert	; Entfernungswert (aus Hauptprogramm) laden
									; 333 Meter bei 80 km/h = 15 sekunden.
									; Gewünschte Geschwindigkeit aber ca. 100 km/h, daher
									; im folgenden noch eine Verkürzung des Notinvervalles
		mov		temp, wert			; Wert in temp laden, für die Berechnung der Intervallverkürzung
		lsr		temp
		lsr		temp				; temp = Wert / 4
		sub		NotIntervallReg, temp	; Intervall um Wert/4 verkürzen -> entspricht ca. 100 km/h
		ldi		temp, NoSignal
		clr		NoSignalReg
Calc_NoSignal:
		add		NoSignalReg, NotIntervallReg
		dec		temp
		brne	Calc_NoSignal

T1_CM_Weiter:
		sbic	GPIOR0,Notbetrieb	; Notbetrieb?
#if Enable_BlinkNotlauf
		rcall	blink				; wenn ja dann RegenLED blinken lassen, sonst normal weiter
#endif
		inc		Timer1Cnt			; dann 15-Sek-Zähler erhöhen

		cp		Timer1Cnt, NotIntervallReg	; Notpumpintervall abgelaufen?
		brlo	T1_CM_End			; wenn nein -> Interrupt beenden

		sbic	GPIOR0,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		GPIOR0, Notbetrieb	; ja -> Notbetrieb-Flag setzen

#if Enable_BlinkNotlauf
		rcall	blink
#endif
Activate_Pump_T1:
		clr		Timer1Cnt
		sbis	PIND,Cross_SW		; PD0 Kontakt geschlossen? 
		ldi		Cr_soll,PumpCross	; ja, dann $PumpCross Impulse 
		sbic	PIND,Cross_SW		; PD0 Kontakt offen? 
		ldi		Cr_soll,PumpNormal	; ja dann $PumpNormal Impulse 
		sbis	PORTD,ExternRegen	; wenn RegenLED an
		subi	Cr_Soll, - ExtraRegen	; eventuelle zusätzliche Pumpstöße addieren
		;Pumpe aktivieren 
		clr		Cr_cnt				; damit startet die Pumpe im Hauptprogramm


T1_CM_End:
		pop		temp
		out		SREG,temp			; Status Reg zurückschreiben 
		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

		ldi		temp,0b00011000		; 
		out		WDTCR,temp			; Watchdogeinstellung vorbereiten
		ldi		temp,0b00001111		; 
		out		WDTCR,temp			; Watchdog 2s

		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

#if Enable_ReedDelay
		ldi		temp, 0b11000111	; TOIE0/OCIEA0/OCIEB0: Interrupt bei Timer0 Overflow/Compare Match
									; TOIE1/OCIEA1: Interrupt bei Timer1 Overflow/Compare Match
#else
		ldi		temp, 0b11000011	; TOIE0/OCIEA0: Interrupt bei Timer0 Overflow/Compare Match
									; TOIE1/OCIEA1: Interrupt bei Timer1 Overflow/Compare Match
#endif
		out		TIMSK, temp			; Interrupt bei Compare Match zum Zählen ermitteln der Intervalle

		clr		Timer1Cnt			; 15-Sek-Zähler auf 0 setzen
		sts		CntRad_alt,Timer1Cnt	; an 'CntRad_alt' eine 0 speichern

		ldi		temp,16
		mov		Wert,temp			; erstmal mit 5333m initialisieren (bis auslesen)

		ldi		XL,Low(Wertspeicher)
		ldi		XH,High(Wertspeicher)	; X-Pointer mit Startaddresse für Wertspeicher laden
		sts		akt_Speicherstelle,XL	; Speicherstelle für Durchschnittsberechnung initialisieren
init_Durchschnitt:
		st		X+,Wert				; an jeder der 8 Speicherstellen für die Durchschnittsberechnung
		cpi		XL,0x6c				; den aktuellen Wert speichern
		brne	init_Durchschnitt

		; 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
					
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

		mov		wert, temp			; Radkonstante auch ins Wert-Register laden
		lsr		wert
		lsr		wert				; wert enthält jetzt Radkonstante durch 4
		sub		temp, wert			; temp = Radkonstante * 0,75
		st		X+, temp			; temp an Stelle 0x6c im SRAM ablegen -> Speicherstelle für Schwellwert naß
		st		X+, wert			; wert an Stelle 0x6d ablegen -> Speicherstelle für Schwellwert trocken		

		rcall	berechne_radumdrehungen ; die für die geschwindigkeitsabhängige Ölung notwendigen Werte
									; für die Raddrehzahlen berechnen und speichern

		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		cr_soll	
		clr		Time1				; Zeit zurücksetzen
		clr		Time2
		clr		CntTacho			; Tachopulszähler zurücksetzen
		clr		cPump				; Pumpimpulszähler zurücksetzen
		clr		CntRad				; Umdrehungszähler löschen
		clr		CntWert				; 333m-Zähler zurücksetzen
		clr		TimeP
		clr		XL
		clr		XH
		rjmp	Loop				; zum Anfang der Hauptschleife springen


Learnmode_Tacho:
		sbi		PORTB,PB2			; Regensensor an
		cbi		PORTB,PB3
		freq						; 0,25ms warten
		sbi		PortD, RegenLED
		cbi		PortD, ReedLed
		
		rjmp	Loop
Learnmode_Rad:
		sbi		PORTB,PB2			; Regensensor an
		cbi		PORTB,PB3
		freq						; 0,25ms warten
		cbi		PortD, RegenLED
		sbi		PortD, ReedLed
		rjmp	Loop
		

;****************************************************************
; Hauptschleife liest den Wegstrecken-Wert ein			;
;****************************************************************
Loop:	wdr							; watchdog reset
		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
		out		GPIOR0, Timer1Cnt	; GPIOR0 -> 0, kein Notbetrieb, kein Learnmode

		sbic	PIND,ReedSW			; Reed kontakt offen?
		cbi		PORTD,ReedLED		; LED an
		sbis	PIND,ReedSW			; Reed kontakt geschlossen?
		sbi		PORTD,ReedLED		; LED aus


		sbic	PIND,Cross_SW		; Schalter offen?
		Sbi		PORTA,Cross_LED		; Cross-LED aus
		sbiS	PIND,Cross_SW		; Schalter geschlossen (on GND)?
		Cbi		PORTA,Cross_LED		; Cross-LED an


		sbis	ACSR,ACO			; kein Regen?
		cbi		PORTD,RegenLED		; LED (intern) an
		sbis	ACSR,ACO			; kein Regen?
		sbi		PORTD,ExternRegen	; LED (extern) aus


		sbic	ACSR,ACO			; Regen?
		sbi		PORTD,RegenLED		; LED (intern) aus
		sbic	ACSR,ACO			; Regen?
		cbi		PORTD,ExternRegen	; LED (extern) an


		sbic	PIND,Taste			; Wenn Taste nicht gedrückt
		ldi		temp,PumpTest		; Anzahl Pumpimpulse in Temp laden
		sbic	PIND,Taste			; Wenn Taste nicht 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
		wdr
		cli
		clr		Time1				; Zeit zurücksetzen
		clr		Time2
		dec		cPump				; Pulszähler 
		sbi		PORTD,6				; Pumpe 50 ms 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, GPIOR0
		cpi		temp, 0b00000010	; Bit 1 gesetzt? -> aktueller Zustand: Learnmode-Tacho
		brsh	enable_learn_rad	; zu Learnmode-Rad springen
enable_learn_tacho:
		sbi		GPIOR0, Learn_Tacho	; falls Bit 1 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, 0b00000100	; Bit 2 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		XH, High (s_learn_tacho_eeprom) ; X-Register (Speicherzeiger) initialisieren, Highbyte
		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		GPIOR0, Learn_Tacho ; dann: Learnmode-Tacho deaktivieren
		sbi		GPIOR0, 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		GPIOR0, 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		XH, High (s_learn_tacho_start) ; X-Register (Speicherzeiger) initialisieren, Highbyte
		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		XH, High (s_learn_rad_eeprom) ; X-Register (Speicherzeiger) initialisieren, Highbyte
		ldi		XL, Low (s_learn_rad_eeprom) ; X-Register (Speicherzeiger) initialisieren, Lowbyte
		ld		temp2, X			; temp2 (ins EEPROM zu schreibenden Wert) aus SRAM laden
		cpi		temp2, 50			; Überprüfen, ob mindestens 100 Radumdrehungen pro 333 m ermittelt wurden
		brlo	End_Tastenauswertung; falls nicht -> irgendein Fehler aufgetreten, nix speichern
		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_radumdrehungen ; die für die geschwindigkeitsabhängige Ölung notwendigen Werte
									; für die Raddrehzahlen berechnen und speichern
End_Tastenauswertung:
		sbic	GPIOR0, Learn_Tacho
		rjmp	Learnmode_Tacho		
		sbic	GPIOR0, Learn_Rad
		rjmp	Learnmode_Rad
		sbi		PORTD,ReedLED		; LED aus
		sbi		PORTD,RegenLED		; LED aus

		cli
		sbis	ACSR,ACO			; kein Regen?
		sbi		PORTD,ExternRegen	; LED aus an PD1
		sbic	ACSR,ACO			; Regen?
		cbi		PORTD,ExternRegen	; LED an an PD1
		sei

		cli
		sbic	PIND,Cross_SW		; Schalter offen?
		Sbi		PORTA,Cross_LED		; Cross-LED aus
		sbis	PIND,Cross_SW		; Schalter geschlossen (on GND)?
		Cbi		PORTA,Cross_LED		; Cross-LED an
		sei

Offset:
		cp		Cr_cnt,Cr_soll
		brge	OffsPumpOK

AutoPump:
		wdr
		cli
		sbi		PORTD,6				; Pumpe 150 ms an
		delay	PumpOn					; bessere Befüllung bei dickem Öl (Winter)
		cbi		PORTD,6				; Pumpe aus
		delay	PumpOff	
		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
		brts	LoopEnd				; Testmode, weitermachen
		inc		Time1				; Zeitzähler ~32sec
		brne	LoopEnd
		sbrs	TimeP,7				; bis 128 zählen
		inc		TimeP				; Zeitzähler erhöhen

		sbic	PinA,Zuendung		; Zündung an?
		rjmp	LoopEnd				; Wenn ja -> LoopEnd (nicht einschlafen lassen)

		inc		Time2
		brne	LoopEnd				; wenn Zeit abgelaufen, dann

		sbic	GPIOR0,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

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	GPIOR0,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

		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

		sbis	PIND,Taste			; Taste gedrückt? 
		rjmp	Reed_end

#if Enable_ReedDelay				; Timer passend setzen, um den den Reedinterrupt für die gewünschte
									; Zeit zu deaktivieren
		out		GIMSK,Time2			; Reed-Interrupt ausschalten
		in		XL,TCNT0			; aktuellen Zählerstand (Counter0) laden
		ldi		XH,EntprellTimer	; Anzahl Zählerschritte für Entprelldelay laden
		add		XL,XH				; zu aktuellem Zählerstand addieren
		brcs	Add_Overflow		; bißchen Rechnerei, um Sonderfälle: Overflow
		cpi		XL,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	XL, -3
		rjmp	Load_Entprelltimer
Ueber_252:
		subi	XL,252
Load_EntprellTimer:
		out		OCR0B,XL			; 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
#endif

		clr		Timer1Cnt			; 15 Sekunden-Zähler resetten
		cbi		GPIOR0,Notbetrieb	; kein Notbetrieb mehr
		clr		Time2				

		sbic	GPIOR0,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			; sonst Reed-Routine beenden

		clr		CntTacho			; Zähler für Tachopulse zurücksetzen

		brts	Reed_End			; Testmode -> Zurück

		sbic	GPIOR0,Learn_Rad	; im Learnmode-Radkonstante? -> zur Speicherroutine springen
		rjmp	Lerne_Radkonstante

		; bestimmen der Regenmenge in den letzten 333 m
		sbis	PORTD,ExternRegen	; wenn RegenLED an
		inc		Regenanteil			; dann Regenanteilszähler erhöhen

		inc		CntRad				; Umdrehungszähler erhöhen 
		lds		Temp,s_Rad
		cp		CntRad,temp			; Radkonstante erreicht? 
		brlo	Reed_end

		clr		CntRad				; Umdrehungszähler löschen 
		out		TCNT0,CntRad		; Zähler 0 resetten
		clr		Cnt2Sek				; 2-Sekunden-Zählregister resetten
		sts		CntRad_alt,CntRad	; Umdrehungszähler im Speicher löschen
		inc		CntWert				; 333m-Zähler erhöhen 

;####################################################################
;########### Code zum Ölen ---->NACH<---- Regen #####################

Regenpruefung:
		lds		temp, RSchwelle	
		cp		Regenanteil,temp	; 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		Regenanteil,temp	; 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	; sind wir schon beim letzten. Mal Pumpen?
		brlo	Pumpen_ohne_Cross	; weniger als Pumpmax gepumpt: Pumpe aktivieren, und zwar mit 1 Pumpstoß, unabhängig vom Cross-SW
		breq	Pumpen_mit_Cross	; letzes Mal pumpen: Pumpe aktivieren, abhängig vom Cross-Switch
		ldi		Regenmerker,0		; genug gepumpt: Regenmerker auf Trockenzustand setzen

;########### Code zum Ölen ---->NACH<---- Regen #####################
;####################################################################

Normal_Reed:
		ldi		Regenanteil,0		; gemessene Regenmenge der letzten 333m zurücksetzen
		cp		CntWert,Wert		; Vergleichswert erreicht? 
		brlo	Reed_end 

		mov		temp, TimeP
		cpi		temp,70				; nach etwa 10 s darf wieder gepumpt werden 
		brlo	Reed_end 

Pumpen_mit_Cross:
		sbis	PIND,Cross_SW		; PD0 Kontakt geschlossen? 
		ldi		Cr_soll,PumpCross	; ja, dann $PumpCross Impulse 
		sbic	PIND,Cross_SW		; PD0 Kontakt offen? 
Pumpen_ohne_Cross:
		ldi		Cr_soll,PumpNormal	; ja dann $PumpNormal Impulse 
		sbis	PORTD,ExternRegen	; wenn RegenLED an
		subi	Cr_Soll, - ExtraRegen	; eventuelle zusätzliche Pumpstöße addieren

		clr		CntWert				; 333m-Zähler zurücksetzen 
		clr		TimeP				; Zeitzä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:
		ldi		XH, high (s_learn_tacho_start)
		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:
		ldi		XH, high (s_learn_rad_start)
		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 #########################
;#########################################################
;#########################################################
