;**********************************************************************************************
; Autor: Sven Stoecker
; V 0.1 2004-03-20	: Nixie Clock; Treiber fuer  74141
;**********************************************************************************************

.include "4433def.inc"

;**********************************************************************************************
; Belegung der Ports 
;**********************************************************************************************

; PORTB0	Nixie1 D0 		Stunden HI
; PORTB1	Nixie1 D1 
; PORTB2	Nixie1 D2 
; PORTB3	Nixie1 D3 / Prog
; PORTB4	DCF	  / Prog
; PORTB5	Taster	  / Prog

; PORTC0	Nixie2 D0		Minuten HI
; PORTC1	Nixie2 D1
; PORTC2	Nixie2 D2
; PORTC3	Nixie2 D3
; PORTC4	Doppelpunkt
; PORTC5	LED

; PORTD0	Nixie3 D0		Stunden LO
; PORTD1	Nixie3 D1
; PORTD2	Nixie3 D2		
; PORTD3	Nixie3 D3		
; PORTD4	Nixie4 D0		Minuten LO
; PORTD5	Nixie4 D1
; PORTD6	Nixie4 D2
; PORTD7	Nixie4 D3

;*******************************************************************************
; Variablen und Zuweisungen
;*******************************************************************************

.def temp 		= r16 		; temporary variable
.def temp2 		= r17 		; temporary variable
.def temp3 		= r18 		; temporary variable
.equ Korrekt		= 4500		; sec bis zum auslassen einer sec

;**********************************************************************************************
; Belegung des SRAMS
;**********************************************************************************************

.equ secLO 		=0x65
.equ secHI 		=0x64
.equ minLO		=0x63
.equ minHI		=0x62
.equ hLO 		=0x61
.equ hHI 		=0x60

;**********************************************************************************************
; Beginn des Codesbereiches
;**********************************************************************************************

.cseg
.org $0000

;**********************************************************************************************
; Interupt-Sprungtabelle
;**********************************************************************************************

         	rjmp 	Start        	; RESET
         	reti			; IRQ0
         	reti			; IRQ1
         	reti                 	; TIMER1 CAPT
         	reti                 	; TIMER1 COMP
         	rjmp	sekunde       	; TIMER1 OVF
         	reti 	       		; TIMER0 OVF
        	reti                 	; SPI, STC
         	reti        		; UART, RX
         	reti                 	; UART, UDRE
         	reti                 	; UART, TX
         	reti              	; ADC
 		reti                 	; EE_RDY
         	reti                 	; ANA_COMP

;**********************************************************************************************
; Korrekturtabelle fuer Nixieansteuerung
;**********************************************************************************************

Korrektur:	.db 0x03,0x04,0x07,0x08,0x06,0x00,0x02,0x09 
		.db 0x05,0x01,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a


;**********************************************************************************************
; jetzt kommen die Interuptroutinen
;**********************************************************************************************

	sekunde:	push 	temp			; temp sichern
			in 	temp,SREG       	; SREG holen und 
			push 	temp			; sichern
			ldi 	temp,6			; Zaehlerstart 
			out	TCNT1H,temp		; H setzen
			clr	temp			; L setzen
			out	TCNT1L,temp		; und jetzt uebernehmen
			ldi	temp,0x0f		
			out	DDRB,temp		; Taster auf Eingang
			in	temp,PINB		; Taster Stunde?
			sbrs	temp,5			
			rjmp	plusstunde		; ja -->
			in	temp,PINB		; Taster min?
			sbrs	temp,4 
			rjmp	plusminute		; ja -->

			clr	temp			
			subi	YL,1			; Ganggenauigkeit Korrektur 
			sbc	YH,temp
			brbc	0,plussekunde		; schon faellig? nein --->
			ldi	YH,high(Korrekt)        ; neu starten
			ldi	YL,low(Korrekt)
			rjmp	A9			; keine sec erhoehen

;**********************************************************************************************
; Erhoehen der Zeit
;**********************************************************************************************

plussekunde:		lds	temp,secLO		; hole sekunden einer
			inc	temp			; +1
			cpi	temp,10			; schon 10
			brbs	1,A1			; ja
			sts	secLO,temp		; nein
			ret
						
A1:			clr	temp			
			sts	secLO,temp
			
			lds	temp,secHI		; hole sekunden zehner
			inc	temp			; +1
			cpi	temp,6			; schon 6
			brbs	1,A2			; nein
			sts	secHI,temp		; nein
			ret

A2:			clr	temp
			sts	secHI,temp


plusminute:		lds	temp,minLO		; hole min einer
			inc	temp			; +1
			cpi	temp,10			; schon 10
			brbs	1,A3			; ja
			sts	minLO,temp		; nein
			rjmp 	A8
						
A3:			clr	temp			
			sts	minLO,temp
			
			lds	temp,minHI		; hole min zehner
			inc	temp			; +1
			cpi	temp,6			; schon 6
			brbs	1,A4			; nein
			sts	minHI,temp		; nein
			rjmp	A8

A4:			clr	temp
			sts	minHI,temp
			
plusstunde:		lds	temp,hHI		; hole h zehner
			cpi	temp,2			; schon 2
			brbs	1,A6			; ja
			
			lds	temp,hLO		; hole h einer
			inc	temp			; +1
			cpi	temp,10			; schon 10
			brbs	1,A5			; ja
			sts	hLO,temp		; nein
			rjmp	A8

A5:			clr	temp			; loesche h einer
			sts	hLO,temp		; speichern h einer
			lds	temp,hHI		; hole h zehner
			inc	temp			; +1
			sts	hHI,temp		; speichern h zehner
			rjmp	A8

A6:			lds	temp,hLO		; holen h einer
			inc	temp			; +1
			cpi	temp,4
			brbs	1,A7
			sts	hLO,temp
			rjmp	A8

A7:			clr	temp
			sts	hLO,temp
			sts	hHI,temp
A8:			clr	temp			
			sts	secLO,temp
			sts	secHI,temp

A9:	 		rcall	Zeitausgabe		; Zeit auf Ports ausgeben
			pop	temp			; SREG vom Stack holen
			out	SREG,temp		; und wiederherstellen
			pop	temp		 	; temp wiederherstellen
			reti		
			
;**********************************************************************************************
; jetzt kommen Unterprogramme
;**********************************************************************************************
;**********************************************************************************************
;Warteschleifen 
; 1 cycle = 125ns;
; 100ľsec = 800 c
; 4100ľsec = 32800 c
; 15000ľsec = 120000 c
;**********************************************************************************************

Delay100:		nop                  		; 1 cycle ; total 800 = (157*5)+(1*2)+10+3
         		nop                  		; 1 cycle
         		nop                  		; 1 cycle
         		ldi 	temp2,157        	; 1 cycle
         		ldi 	temp3,1          	; 1 cycle
         		rjmp 	Delay           	; 2 cycles

Delay4100:		nop                  		; 1 cycle ; total 32800 = (6547*5)+(26*2)+10+3
         		nop                  		; 1 cycle
         		nop                  		; 1 cycle
         		ldi 	temp2,147        	; 1 cycle
         		ldi 	temp3,26         	; 1 cycle
         		rjmp 	Delay           	; 2 cycles

Delay15000:		nop                		; 1 cycle ; total 120000 = (23808*5)+(94*2)+10+2
         		nop                  		; 1 cycle
         		ldi 	temp2,152        	; 1 cycle
         		ldi 	temp3,94         	; 1 cycle
         		rjmp 	Delay           	; 2 cycles

;**********************************************************************************************
; RCALL needs 3 cycles
; each inner loop = 5
; each outer loop = +2 (3-1)
; last loop = +3 (4-1)
; formula == ((temp2+(temp3-1)*256)*5)+(temp3*2)+10+(num of nops)
;**********************************************************************************************

Delay:   		nop                  		; 1 cycle
         		nop                  		; 1 cycle
         		dec 	temp2           	; 1 cycle
         		brne 	Delay           	; 2/1 cycles ; Check if inner loop is finished
         		dec 	temp3            	; 1 cycle
         		brne 	Delay           	; 2/1 cycles ; Check if outer loop is finished
         		ret                  		; 4 cycles 

;**********************************************************************************************
; Ausgabe der Zeit auf Ports
;**********************************************************************************************

Zeitausgabe:		ldi	temp,0b11111111
			out	DDRD,temp		; set port D output
			ldi	temp,0b00001111
			out	DDRB,temp		; set port C output 
			ldi	temp,0b00001111
			out	DDRC,temp		; set port C (0-3) output 
			
			lds	temp,hHI		; hole Zehner Stunden
			;andi	temp,0x0f
			;brbc	1,Zeitausgabe1		; nicht Null
			;ldi	temp,11			; Null ausblenden
Zeitausgabe1:		rcall	Korrport		; 74141 Belegung korrigieren
			out	PORTB,temp		; ausgeben

			lds	temp,minLO		; hole einer Stunde
			rcall	Korrport		; 74141 Belegung korrigieren
			out	PORTC,temp		; ausgeben

			lds	temp,minHI		; hole Einer Minuten
			rcall	Korrport		; 74141 Belegung korrigieren
			mov	temp2,temp
			lds	temp,hLO		; hole Zehner Minuten
			rcall	Korrport		; 74141 Belegung korrigieren
			swap	temp			; in oberes Nibble
			or	temp,temp2		; zusammenwuerfeln
			out	PORTD,temp		; ausgeben
			ret

;**********************************************************************************************
; Anpassung der Ausgabe an Falsche Belegung des 74141
;**********************************************************************************************

Korrport:		andi	temp,0x0f
			ldi 	ZL, low(Korrektur*2) 	;Zeiger auf Tabelle laden
         		ldi 	ZH,high(Korrektur*2)
		        add	ZL,temp              	;Zeiger auf Element
			clr	temp
			adc	ZH,temp
			lpm                		;Zeichen nach R0
	         	mov 	temp,R0       		;Zeichen holen
			ret
			
;**********************************************************************************************
; Ab hier gehts richtig los:-)
; das ist der Programmstart nach Reset und Power on
;**********************************************************************************************

;**********************************************************************************************
; Initialisieren der Ports
;**********************************************************************************************

Start:			ldi	temp,RAMEND		
			out	SPL,temp		; set stack pointer
			ldi	temp,0xff
			out	PORTD,temp
			out	PORTC,temp
			out	PORTB,temp
			ldi	temp,0b11111111
			out	DDRD,temp		; set port D output
			ldi	temp,0b00001111
			out	DDRB,temp		; set port C output 
			ldi	temp,0b00001111
			out	DDRC,temp		; set port C (0-3) output 

;**********************************************************************************************
; Initialisieren der Variablen
;**********************************************************************************************

			ldi	YH,high(Korrekt)	; Korrekturwert ganggenauigkeit laden
			ldi	YL,low(Korrekt)
			clr	temp
			sts	secLO,temp
			sts	secHI,temp
			sts	minLO,temp
			sts	minHI,temp
			sts	hLO,temp
			sts	hHI,temp

;**********************************************************************************************
; Timer 1 starten mit 1/64 Quarztakt
;**********************************************************************************************

			ldi	temp,250
			out	TCNT1H,temp
			clr	temp
			out	TCNT1L,temp
			ldi	temp,0x03		; 1/64 Takt    ( 0x01 = 1/1 Takt)
			out	TCCR1B,temp
			ldi	temp, 0x80
			out	TIMSK,temp		; Timerinterupt freigeben
			sei				; Interupt freigeben
				
;**********************************************************************************************
; Alles erledigt?
; Dann geht jetzt die richtige Arbeit los
;**********************************************************************************************

Hauptschleife:		rjmp	Hauptschleife		; das hier ist die Hauptsache:-)