;Demoprogramm zum Erzeugen von Sekundentakt und Tastenabfrage
;
;Zähler 0 wird im CTC-Modus betrieben. Der Wert in OCRA wird so eingestellt, dass 
;am Pin PD4 die LED im Sekundentakt mit variablem Dutycycle ein und aus geschaltet wird.
;
	.nolist
	.include "tn2313def.inc"
	.list
;
;	xtal-Frequenz dem Programm bekannt machen
	.equ xtal = 8000000				; 8 MHz

	.def temp1 = r16				; wird definieren zur Gaudi mal die Register
	.def temp2 = r17				; Namen neu, um zu zeigen, dass auch das geht
	.def temp3 = r18				; Die Register r16 bis r18 sind Mädchen für alles

	.def flag  = r19				; R19 nimmt Programmmerkerbits auf

	.def jiffies = r20				; Jiffies sind die Hundertstel-Sekundenbruchteile
	.def hundertstel = r21			; Hundertstelsekunden
	.def sekunden = r22				; selbstredend
	.def minuten = r23
	.def stunden = r24

	.def t1 = r25					; für wie viele Jiffies (200µs) gedrückt?
	.def t2 = r26
	.def t3 = r27
	.def ledan = r28				; Festlegen Dutycycle für LED
	.def hundert = r29				; Zeitpunkt für Anphase

	.equ p = portd					; portd für die LED
	.equ pin = 4					; pin 4
	.equ dr = ddrd					; ddrd
	.equ ledmask = (1<<pin)			; Maske zum Umschalten mit eor-befehl
									; Die Pseudoassembleranweisung 1<<pin bedeutet, dass 
									; in einem Byte eine 1 um so viele Stellen nach links
									; geschoben wird, wie der Wert in pin angibt.
									; 0b0000001 4 mal links schieben: 0b00010000 = 0x10
									; die 1 steht jetzt an der Bitnummer 4
									; Position: 76543210
									; Bytewert: 00010000
									; Das ist in der Tat die Leitung, welche die LED steuert.

	.equ tast_dr = ddrB				; Port für die Tasten
	.equ taste1	= 0					; Leitungen für die Tasten
	.equ taste2 = 1
	.equ taste3 = 2
	.equ tast_in = pinB				; Eingangsregister für die Tasten

	.equ vergleichswert = 200		; Wert für ocr1a-Vergleichsregister -> 200 µs
	.equ jfactor = 50				; Faktor zum Erreichen eines Jiffies -> 1 Jiffie=10ms=0,01s
;	.equ ledan = 1					; Festlegen des Dutycycles (Anzeit)

; ************************************************************************************************
; * IRQ-Vektoren
; ************************************************************************************************

	.org 0x0000						; Programmstart
	rjmp Start						; Resetvektor

	.org OC0Aaddr					; IRQ-Vektor für Timer 0
	rjmp Timer0_oc0a				; Sprung zur Serviceroutine

	.org 0x001A						; hinter allen IRQ-Vektoren
; ************************************************************************************************
; * Hauptprogramm Vorbereitungen
; ************************************************************************************************

Start:
	ldi temp1, low(ramend)			; Stackpointer setzen
	out spl, temp1					
	ldi temp1, (1<<pin) | (1<<(pin+1))			; Bit 4 von PortD als Ausgang
	out dr, temp1					; setzen
									; Wir haben jetzt noch eine ganze Menge weiterer
									; Vorbereitungen für die Zeitmessung zu treffen
									; Die Zeitmessung wird vom Hauptprogramm ausgeklinkt
									; und dem Interruptprozess eines Timers überlassen
	in temp1, tast_dr				; Richtungsregister der Tasten lesen
	andi temp1, ~((1<<taste1) | (1<<taste2) | (1<<taste3))			; Bit 2:0 löschen
	out tast_dr, temp1				; Tastenport.2:0 als Eingabeleitungen setzen

	ldi temp1, (1<<pin)
	out p, temp1					; LED aus


	ldi temp1, 0					; Systemtakt für Timer
	out tccr0b, temp1				; ausschalten
	
	ldi temp1, (1<<wgm01)			; CTC-Mode 2 einstellen, Zählen bis OCR0A 
	out tccr0a, temp1
	
	ldi temp1, vergleichswert-1		; OCR0A setzen
	out ocr0a, temp1

	ldi temp1, (1<<ocie0a)			; output compare 1A IRQ für Timer 0 zulassen
	out timsk, temp1

	ldi temp1, (1<<cs01)			; Systemtakt durch 8 als takt für timer 0 
	out tccr0b, temp1				; Takt einschalten
	
	clr jiffies
	clr hundertstel					; Zeitrechnung auf 0 stellen
	clr sekunden					; 
	clr minuten

	ldi	ledan, 50					; 50 als Startwert für Dutycycle (LED)


	sei								; beliebige Interrupts grundsätzlich zulassen
; -------------------------------------------------------------------------------------------------
loop:								; Hauptschleife
	rjmp loop

; *************************************************************************************************
; *   Unterprogramme
; *************************************************************************************************
; Output compare Interrupt - Service Routine

timer0_oc0a:
	push temp1						; temp1 sichern
	in temp1, sreg					; Statusregister sichern
	push hundert					; weitere Register retten
	push temp2

	sbi p, pin+1					; Testpin PortD.pin+1 auf 1

	inc jiffies						; Jiffies erhöhen
	; ------------------------------- IRQ - Aufgaben ----------------------------------------------
	cpi jiffies, 1					; 
	brne job2
	; Job 1   Zeitscheibe 1: Tastenabfrage ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	; Taste 1 gedrückt, wenn taste1-bit=0  ........................................................
	sbic tast_in, taste1			; überspringe nächsten Befehl, wenn Bit = 0
	rjmp t1r						; bit = 1 -> Taste nicht gedrückt
t1p:
	inc t1							; Zähler für Taste 1 erhöhen
	cpi t1, 100+1					; Langzeit Tastendruck	
	brlo t1_ok
	ldi t1,100
t1_ok: 
	rjmp t1_fertig
t1r:
	clr t1							; Zähler für Taste 1 auf 0, wenn nicht gedrückt
t1_fertig:

	; Taste 2 gedrückt, wenn taste2-bit=0 .........................................................
	sbic tast_in, taste2			; überspringe nächsten Befehl, wenn Bit = 0
	rjmp t2r						; bit = 1 -> Taste nicht gedrückt
t2p:
	inc t2							; Zähler für Taste 2 erhöhen
	cpi t2, 100+1					; Langzeit Tastendruck	
	brlo t2_ok
	ldi t2,100
t2_ok: 
	rjmp t2_fertig
t2r:
	clr t2							; Zähler für Taste 1 auf 0, wenn nicht gedrückt
t2_fertig:

	; Taste 3 gedrückt, wenn taste3-bit=0 ........................................................
	sbic tast_in, taste3			; überspringe nächsten Befehl, wenn Bit = 0
	rjmp t3r						; bit = 1 -> Taste nicht gedrückt
t3p:
	inc t3							; Zähler für Taste 3 erhöhen
	cpi t3, 100+1					; Langzeit Tastendruck	
	brlo t3_ok
	ldi t3,100
t3_ok: 
	rjmp t3_fertig
t3r:
	clr t3							; Zähler für Taste 1 auf 0, wenn nicht gedrückt
t3_fertig:

job2:
	; Job 2   Zeitscheibe 2: Tastenaktionen +++++++++++++++++++++++++++++++++++++++++++++++++++++
	cpi jiffies, 2					; 
	brne job3
	; Job 1   Zeitscheibe 1: Tastenabfrage
	; Taste 1 war kurz gedrückt, wenn t1=3
	cpi t1,3		
	brne t1l
	inc ledan						; An-Phase für LED erhöhen
	cpi ledan, 100					; fertig solange kleiner 100
	brlo t2k
	ldi ledan, 99					; ledan = 99 (%) sonst
	rjmp t2k
t1l:
	cpi t1, 100						; langer Tastendruck
	brne t2k
	ldi ledan, 99					; dann Maximum setzen

t2k:		
	cpi t2,3						; Taste 2 kurz gedrückt, 
	brne t2l
	dec ledan						; An-Phase verringern
	cpi ledan, 1					; größer - gleich 1 -> fertig
	brsh t3k
	ldi ledan, 1					; sonst = 1 setzen
	rjmp t3k
t2l:
	cpi t2, 100						; Taste 2 langgedrückt
	brne t3k
	ldi ledan, 1					; dann ledan = 1 (minimum)

t3k:
	; weitere beliebige Tastenfunktion
		
job3:
	; ------------------------------- IRQ - Aufgaben beendet--------------------------------------

	cbi p, pin+1					; Testpin PortD.pin+1 auf 0
	cpi jiffies, jfactor			; so lange 50 nicht erreicht ist, fertig
	brne end_isr					; ergibt: 80000000Hz/8/200 = 5000 Hz (DC=0,4%)
	
									; es ist der wert 50 erreicht
	clr jiffies						; Jiffies löschen, 50 * 200µs = 10000µs=10ms=0,010s

	inc hundertstel					; hundertstelsekunden erhöhen

	ldi hundert, 100				; Subtrahiere ledan von 100
	sub hundert, ledan
	cp hundertstel, hundert			; Für die letzten ledan hundertstel sekunden
	brne led_fertig
	cbi p, pin						; led einschalten, (wenn Dutycycle-Wert erreicht)
led_fertig:	

	cpi hundertstel, 100			; eine Sekunde erreicht?
	brne fertig						; nein
									; ja
	clr hundertstel					; Hundertstelsekunden auf 0 rücksetzen
	sbi p, pin						; und am Ende der 100 hundertstel Sekunden: LED aus
	inc sekunden					; sekunden erhöhen
	cpi sekunden, 60
	brne fertig						; Minute noch  nicht erreicht?
									; sonst Sekundenzähler löschen
	clr sekunden					; Sekundenzähler läuft  von 0 bis 59(60)
									; Hier könnte sich ein Minuten, Stunden, Tage...Zähler 
									; anschließen.

fertig:
	ldi flag, 1						; Hier oder im Verlauf der IRQ-Routine können Flags
									; für das Hauptprogramm gesetzt werden.

end_isr:
	pop temp2						; Register restaurieren
	pop hundert
	out sreg, temp1					; status register restaurieren
	pop temp1						; temp1 zurück
	reti							; irq-routine beenden


.exit
;
; ******************************************************************************************
; * Ende für Programmcode 
; ******************************************************************************************

	clr stunden
	clr flag


	clr sekunden
	inc minuten	
	cpi minuten, 60		
	brne fertig

	clr minuten
	inc stunden
	cpi stunden, 24
	brne fertig

	clr stunden







