/*
Project:		Seminararbeit DCF77 Funkuhr
Programmer:		
Final Build:	
*/

;Controller AtMega 8
.include "m8def.inc"

;Systemtakt in Hz
.equ takt = 4000000
;Timerintervall in ms
.equ intervall = 10
;CTC Vergleichswert, GILT NUR BEI PRESCALER = 1 !!!
.equ ctc_val = (takt/(intervall * 10) - 1)

;Reset Handle
.org 0x0000
	rjmp init
;Timer1 Compare Handle
.org OC1Aaddr
	rjmp timer1_compare

;DCF77 Routinen
.include "dcf77_routines.asm"

;Equates für Schieberegister Pins
;Sekunden
.equ DDR_SEK 	= DDRC
.equ PORT_SEK	= PORTC
.equ clk_sek	= 1
.equ clk_sek2	= 0
.equ dat_sek	= 3

;Minuten
.equ DDR_MIN	= DDRD
.equ PORT_MIN	= PORTD
.equ clk_min	= 0
.equ clk_min2	= 1
.equ dat_min	= 2

;Stunden
.equ DDR_H	= DDRC  
.equ PORT_H	= PORTC
.equ clk_h	= 5
.equ clk_h2	= 2
.equ dat_h	= 4

;DCF Modul
.equ DDR_DCF	= DDRD
.equ PORT_DCF	= PORTD
.equ PIN_DCF	= PIND
.equ PIN_DCF_NUM	= 6

;LEDs auffüllen oder Punkt
.equ DDR_FILL	= DDRD
.equ PORT_FILL	= PORTD
.equ PIN_FILL	= PIND
.equ PIN_FILL_NUM	= 3

;Definition Variablen
.def temp1 = r16
.def min_alt = r17
.def sek_alt = r18
.def zeit_neu = r19
.def impulse = r24
.def stu_alt = r25


;Timer1 Compare Interrupt (alle 10ms)
timer1_compare:
	;SREG sichern
	push temp1
	in temp1, SREG
	push temp1
	
	;DCF77 auswerten
	rcall dcf77_start
	
	;SREG wiederherstellen
	pop temp1
	out SREG, temp1
	pop temp1
	reti


;Initialisierung
INIT:
	; Stackpointer initialisieren
	ldi   temp1, LOW(RAMEND)
	out   SPL, temp1
    ldi   temp1, HIGH(RAMEND)
    out   SPH, temp1
 
	;Port Pins auf Ausgang konfigurieren und auf Null setzen
	;Sekunden
    ldi	temp1, (1<<clk_sek) | (1<<clk_sek2) | (1<<dat_sek)
    out	DDR_SEK, temp1
	com	temp1
	out	PORT_SEK, temp1

	;Minuten
	ldi temp1, (1<<clk_min) | (1<<clk_min2) | (1<<dat_min)
    out DDR_MIN, temp1
	com temp1
	out PORT_MIN, temp1

	;Stunden
	ldi temp1, (1<<clk_h) | (1<<clk_h2) | (1<<dat_h)
    out DDR_H, temp1
	com	temp1
	out	PORT_H, temp1

	;DCF Eingangspin als Eingang konfigurieren
	cbi	DDR_DCF, PIN_DCF_NUM

	;Pin LEDs auffüllen / Punkt als Eingang + PullUp
	cbi	DDR_FILL, PIN_FILL_NUM
	sbi PORT_FILL, PIN_FILL_NUM
	
	;Timer1 Initialisieren
	;Vergleichswert für 10ms
	ldi temp1, high(ctc_val)
	out OCR1AH, temp1
	ldi temp1, low(ctc_val)
	out OCR1AL, temp1
	;Prescaler = 1
	ldi temp1, (1<<WGM12) | (1<<CS10)
	out TCCR1B, temp1
	;Interrupt bei Timer Compare
	ldi temp1, (1<<OCIE1A)
	out TIMSK, temp1
	
	;DCF77 Routinen Initialisieren
	rcall dcf77_init

	;LEDs auffüllen / Punkt auffüllen
	;0 = ??? / 1 = ???

	//Alle LEDs am Schieberegister ausschalten
	ldi impulse, 16
	rcall SchiebeH
	ldi impulse, 61
	rcall SchiebeMin
	ldi impulse, 61
	rcall SchiebeSek
	
	

	;Definierten Ausgangszustand herstellen
	ser sek_alt
	ser min_alt
	ser stu_alt
	clr zeit_neu
	
	;Interrupts global aktivieren
	sei

;Hauptprogramm 
MAIN:
	lds zeit_neu, SEK			//lade SEK aus SRAM in r19=zeit_neu
	cp zeit_neu, sek_alt		//vergleiche r19 mit r18=sek_alt
	breq MAIN					//springe zu Main wenn r19=r18

	tst zeit_neu				//teste r19 auf 0 und Vorzeichen
	brne jumpsetsek				//wenn r19 ungleich 0 springe zu jumpsetsek 
	sbi PORT_sek, dat_sek		//ansonsten setze Pin3 in PORTC auf Ausgang

jumpsetsek:
	ldi impulse, 1				//lade impulse mit 1

	cpi zeit_neu, 57			//vergleiche r19 mit 57
	brne jumpsek				//wenn ungleich springe zu jumpsek
	inc impulse					//ansonsten erhöhe impulse, d.h. Schieberegister schiebt 2mal

jumpsek:
	rcall SchiebeSek			//rufe Uprog. SchiebeSek auf
	mov sek_alt, zeit_neu		//kopiere r19 nach r18
	cbi PORT_sek, dat_sek		//setzt Pin3 in PORTC auf Eingang

	//Minuten
	lds zeit_neu, MIN			//lade MIN aus SRAM in r19
	cp zeit_neu, min_alt		//vgl. r19 mit r17
	breq MAIN					//springe zu Main wenn r19=r17

	
	tst zeit_neu				//teste r19 auf 0 und Vorzeichen
	brne jumpsetmin				//wenn ungleich springe zu jumpsetmin
	sbi PORT_min, dat_min		//ansonsten setzte Pin2 in PORTD auf Ausgang

jumpsetmin:
	ldi impulse, 1				//lade impulse mit 1

	cpi zeit_neu, 57			//vergleiche r19 mit 57
	brne jumpmin				//wenn ungleich springe zu jumpmin	
	inc impulse					//ansonsten erhöhe impulse, d.h. schieberegister schiebt 2mal

jumpmin:
	rcall SchiebeMin			//rufe Uprog. SchiebeMin auf
	mov min_alt, zeit_neu		//kopiere r19 in nach r17
	cbi PORT_min, dat_min		//setze Pin2 in PORTD auf Eingang
		
	//Stunden
	lds zeit_neu, STU			//lade STU aus SRAM in r19
	cp zeit_neu, stu_alt		//vergleiche r19 mit r25
	breq MAIN					//springe zu Main wenn r19=r25

	tst zeit_neu				//teste r19 auf 0 und Vorzeichen
	brne jumpsetstu				//wenn r19 ungleich springe zu sumpsetstu
	sbi PORT_h, dat_h			//ansonsten setze Pin4 in PORTC auf Ausgang

jumpsetstu:
	ldi impulse, 1				//lade impulse mit 1

	cpi zeit_neu, 1				//vergleiche r19 mit 1
	brne jump1					//wenn ungleich springe zu jump1
	ldi impulse, 3				//ansonsten lade impulse mit 3
	rjmp jump6					//springe unbedingt zu jump6

jump1:
	cpi zeit_neu, 6				//vergleiche r19 mit 6
	brne jump6					//wenn ungleich springe zu jump6
	ldi impulse, 3				//ansonsten erhöhe impulse mit 3

jump6:	
	rcall SchiebeH				//rufe Uprog. SchiebeH auf
	mov stu_alt, zeit_neu		//kopiere r19 nach r25
	cbi PORT_h, dat_h			//setze Pin4 in PORTC auf Eingang

    rjmp  MAIN					//springe unbedingt zu Main, Programm beginnt von vorne




/*
Schiebeimpulse für die Schieberegister
Sekunden | Impulse | Bemerkung
	57		2		QA ausgelassen

Minuten | Impulse | Bemerkung
	57		2		QA ausgelassen

Stunden | Impulse | Bemerkung
	1		3		QA ausgelassen + LEDs falsch plaziert
	6		3		QA ausgelassen + LEDs falsch plaziert	
*/

;Sekunden an Schieberegister senden
SchiebeSek:

	sbi PORT_SEK, clk_sek		//setzte Pin1 in PORTC auf Ausgang
	cbi PORT_SEK, clk_sek		//setze Pin1 in PORTC auf Eingang

	dec impulse					//verringere impulse
	brne SchiebeSek				//wenn ungleich 0 springe zu SchiebeSek

	sbi PORT_SEK, clk_sek2		//ansonsten setzte Pin0 in PORTC auf Ausgang
	cbi PORT_SEK, clk_sek2		//setze Pin0 in PORTC auf Eingang
		
	ret							//Rücksprung aus Uprog.

;Minuten an Schieberegister senden
SchiebeMin:
	
	sbi PORT_MIN, clk_min		//setzte Pin1 in PORTD auf Ausgang
	cbi PORT_MIN, clk_min		//setze Pin1 in PORTD auf Eingang

	dec impulse					//verringere impulse
	brne SchiebeMin				//wenn ungleich springe zu SchiebeMin

	sbi PORT_MIN, clk_min2		//ansonsten setzte Pin0 in PORTD auf Ausgang
	cbi PORT_MIN, clk_min2		//setze Pin0 in PORTD auf Eingang

	ret							//Rücksprung aus Uprog.

	
;Stunden an Schieberegister senden
SchiebeH:
	
	sbi PORT_H, clk_h			//setzte Pin5 in PORTC auf Ausgang
	cbi PORT_H, clk_h			//setze Pin5 in PORTC auf Eingang

	dec impulse					//verringere impulse
	brne SchiebeH				//wenn ungleich springe zu SchiebeMin

	sbi PORT_H, clk_h2			//ansonsten setzte Pin2 in PORTC auf Ausgang
	cbi PORT_H, clk_h2			//setze Pin2 in PORTC auf Eingang

	ret							//Rücksprung aus Uprog.