;********************************************************************
;*                                                                  *
;* Title       : Nixie-DCF                                          *
;* Version     : 0.1   05. Juni 2005                                *
;* Author      : Uwe Nagel, Parkstr. 46, D-68766 Hockenheim         *
;* Assembler   : MPASM (c) Microchip                                *
;*                                                                  *
;********************************************************************
; 0.1    15.06.02 aus DCF.ASM entstanden
; 1.0    05.06.05 erste veröffentlichte Version
;********************************************************************

#define TITEL "-Nixie-Uhr V1.0-"

	title		TITEL
	__CONFIG _CP_OFF & _WDT_ON & _PWRTE_ON & _XT_OSC
	errorlevel	-302		; keine bank select message
	radix	dec

	include	<p16f84a.inc>
	include "pic16cxy.inc"

;****** Variablen ***************************************************
 cblock	0x0c
	save_w		; w und
	save_STATUS	; STATUS während interrupt
	flag		; diverse Bits
	temp
	precount	; Vorteiler durch 16
	zweihund
	puls_zeit	; misst Pulsdauer
;*** diese Zeit wird angezeigt
	dispSec, dispMin, dispStd, dispTag, dispMon, dispJahr, dispWtag, dispStat
;*** hier kommt die gerade empfangene Zeit rein
	dcfMin, dcfStd, dcfTag, dcfMon, dcfJahr, dcfWtag, dcfStat
;*** zum Vergleich, die letzte Minute
	dcf1Min, dcf1Std, dcf1Tag, dcf1Mon, dcf1Jahr, dcf1Wtag
	filter
;*** setup variables
	date_on, disp_on, btn1, btn2, btn3,sbtn1,sbtn2,sbtn3,tenmin,quick, stored
 endc


;****** bits in flag ************************************************
#define	neusync flag,0
#define	alt     flag,1
#define	sekunde	flag,2
#define	comm	flag,7
#define dcfsign	flag,4

;****** Konstanten **************************************************
;#define	TICKS	109	; NTSC-Quartz (ungenau)
;#define	TICKS	122	; 4 MHz (ungenau)
#define	TICKS	100	; 3,276800 MHz (genau)
;#define	TICKS	128	; 4,194304 MHz (genau)


;********************************************************************
;* Programmcode ...
;********************************************************************
	org	0
	goto	main

;********************************************************************
;* interrupt :
;********************************************************************
	org	4
interrupt
	movwf	save_w		; W und STATUS sichern
	swapf	STATUS,w
	movwf	save_STATUS

	bcf	STATUS,RP0	; Wähle register page 0

	jnb	INTCON,T0IF,end_t0_isr ; ist es timer interrupt ?

	call	scan

	decfsz	precount,f
	goto	end_t0_isr
	
	movlw	16
	movwf	precount
 bsf PORTA,2



;****** filtern des Signals um kurze Störungen zu unterdrücken ***************
; increment filter if port=1 and filter if less than 8
; decrement filter if port=0 and filter if greater than 0


	btfss	PORTA,0
	goto	port_is_0
port_is_1
	incf	filter,f
	btfsc	filter,3	; <8 ?
port_is_0
	decf	filter,f
	btfsc	filter,7
	clrf	filter

; set dcfsign if filter becomes 6
; clear dcfsign if filter becomes 1
; 0 1 2 3 4 5 6 7   6 5 4 3 2 1 0
; 0 0 0 0 0 0 1 1   1 1 1 1 1 0 0

	movf	filter,w
	xorlw	6
	btfsc	STATUS,Z
	bsf	dcfsign
	xorlw	6^1
	btfsc	STATUS,Z
	bcf	dcfsign

	jb	alt,NoPos
	jnb	dcfsign,NoPos

;** positive Flanke...
 bsf PORTA,1
	bsf	alt
	clrf	puls_zeit

	jnb	neusync,noNeg

	clrf	dispSec
	movf	dcfMin,w
	movwf	dispMin
	movf	dcfStd,w
	movwf	dispStd
	movf	dcfTag,w
	movwf	dispTag
	movf	dcfWtag,w
	movwf	dispWtag
	movf	dcfMon,w
	movwf	dispMon
	movf	dcfJahr,w
	movwf	dispJahr
	movf	dcfStat,w
	movwf	dispStat

	movlw	TICKS
	movwf	zweihund
	bcf	neusync
	bsf	sekunde
	goto	end_t0_isr
	
NoPos:	jnb	alt,noNeg
	jb	dcfsign,noNeg	; jnb f. neg Pulse

;** fallende Flanke
	bcf	alt
 bcf	PORTA,1
	movf	puls_zeit,w
	addlw	-TICKS*3/20
 btfss STATUS,C
 bcf PORTA,3
 btfsc STATUS,C
 bsf PORTA,3
	rrf	dcfJahr,f
	rrf	dcfMon,f
	rrf	dcfTag,f
	rrf	dcfStd,f
	rrf	dcfMin,f
	rrf	dcfStat,f

noNeg:	decfsz	zweihund,f
	goto	timeOut

;** Sekunde abgelaufen
	movlw	TICKS
	movwf	zweihund

	call	tick
	bsf	sekunde


timeOut:
	incf	puls_zeit,f	; 1,5 s keine steigende Flanke ?
	movf	puls_zeit,w
	addlw	256-(TICKS*3/2)
	btfss	STATUS,C
	goto	end_t0_isr
	clrf	puls_zeit
	call	sec59


end_t0_isr
 bcf PORTA,2
	bcf	INTCON,T0IF     ; lösche timer interrupt flag
	swapf	save_STATUS,w
	movwf	STATUS
	swapf	save_w,f
	swapf	save_w,w
	retfie


;****** multiplexen des Displays *********************************************
scan	clrf	PORTB

	btfss 	PORTA,4
	clrf	btn3
	btfss 	PORTA,4
	clrf	tenmin	
	btfss 	PORTA,4
	clrf	quick

	btfsc 	PORTA,4
	call	button3	

	movf	precount,w
	andlw	0x03
	addwf	PCL,f
	goto	scan0
	goto	scan1
	goto	scan2
	goto	scan3
scan0	movf	dispStd,w
	andlw	0xf0
	movwf	PORTB
	bsf	PORTB,3
	return
scan1	swapf	dispStd,w
	andlw	0xf0
	movwf	PORTB
	bsf	PORTB,2
	return
scan2	movf	dispMin,w
	andlw	0xf0
	movwf	PORTB
	bsf	PORTB,1
	return
scan3	swapf	dispMin,w
	andlw	0xf0
	movwf	PORTB
	bsf	PORTB,0
	return
	
	
	
;****** Hauptprogramm ***********************************************
main    

	bsf	STATUS,RP0	; select Register-Page 1
                  
	movlf	0x00,OPTION_REG	; TMR0 internal clock/2 = 1600Hz @ 3,2768MHz Quarz
				;                         2048Hz @ 4,194304 MHz
	movlf	b'00010001',TRISA	; porta4=button3 ; porta0=dcf in
	movlf	0x00,TRISB	; portb7..0 output
  
	bcf	STATUS,RP0	; select Register-Page 0

	clrf	flag
	clrf	puls_zeit
	movlf	TICKS,zweihund

	clrf	dispSec
;	clrf	dispMin
;	clrf	dispStd
 movlw	0x12
 movwf	dispStd
 movlw	0x34
 movwf	dispMin
	clrf	btn3
	clrf	sbtn1
	clrf	sbtn2
	clrf	sbtn3
	clrf	dispWtag
	clrf	dispJahr
	movlw	1
	movwf	dispMon
	movwf	dispTag

	movlf	0xa0,INTCON	; Enable  TMR0-Int




;------

mainloop:
	clrwdt	
;	movlw	dispTag
;	movwf	FSR
;	call	tickTag
	goto	mainloop


;********************************************************************
;55555555 54444444 44433333 33333222 22222221 11111111
;87654321 09876543 21098765 43210987 65432109 87654321   Sekunde
;PJJJJJJJ JMMMMMWW WTTTTTTP SSSSSSPm mmmmmm1a ooaR0000   DCF-Bits
;
;JJJJJJJJ 000MMMMM 00tttttt 00ssssss 0mmmmmmm 1aooaR00 00000www
; Jahr     Monat    Tag      Stunde   Minute   STATUS   Wtag
;********************************************************************

; jetzt werden die empfangenen Bits erstmal umsortiert 
; 
sec59:	rlf	dcfMon,w
	rlf	dcfJahr,f	; =Jahr
	rlf	dcfTag,w
	rlf	dcfMon,w
	andlw	0x07
	movwf	dcfWtag		; =Wochentag Mo..So = 1..7
	rrf	dcfMon,f
	rrf	dcfMon,f
	movlw	0x1f
	andwf	dcfMon,f	; =Monat
	rrf	dcfTag,f
	movlw	0x3f
	andwf	dcfTag,f	; =Tag
	rrf	dcfStd,w
	rrf	dcfMin,f
	rrf	dcfStat,f
	rrf	dcfMin,f
	rrf	dcfStat,f	; =STATUS
	movlw	0x7f
	andwf	dcfMin,f	; =Minute
	rrf	dcfStd,f
	rrf	dcfStd,f
	movlw	0x3f
	andwf	dcfStd,f	; =Stunde

	movlw	dcf1Min
	movwf	FSR
	call	tickMin		; letzte Zeit weiterrechnen

	movf	dcfMin,w	; und mit gerade empfangener
	xorwf	dcf1Min,w	; Zeit vergleichen
	skpz
	goto	ungleich
	movf	dcfStd,w
	xorwf	dcf1Std,w
	skpz
	goto	ungleich
	movf	dcfTag,w
	xorwf	dcf1Tag,w
	skpz
	goto	ungleich
	movf	dcfMon,w
	xorwf	dcf1Mon,w
	skpz
	goto	ungleich
	movf	dcfJahr,w
	xorwf	dcf1Jahr,w
	skpz
	goto	ungleich

;*** zwei aufeinanderfolgende Zeiten haben zueinander gepasst
;*** die aktuelle Zeit bei nächster Sekunde ins Display kopieren

	bsf	neusync
	return

ungleich:
;*** zwei aufeinanderfolgende Zeiten haben nicht eine Minute unterschied
;*** merken wir die gerade empfangene Zeit für die nächste Minute
	movf	dcfMin,w
	movwf	dcf1Min
	movf	dcfStd,w
	movwf	dcf1Std
	movf	dcfTag,w
	movwf	dcf1Tag
	movf	dcfMon,w
	movwf	dcf1Mon
	movf	dcfJahr,w
	movwf	dcf1Jahr
	return

;------ hier wird die Zeit weitergezählt
tick:	movlw	dispSec
	movwf	FSR

	call	IncDec	; Sekunde
	movlw	0x60
	xorwf	INDF,w
	skpz
	return
	clrf	INDF	; Sekunde=0

	incf	FSR,f	; ->Minute
tickMin:
	call	IncDec	; Minute
	movlw	0x60
	xorwf	INDF,w
	skpz
	return
	clrf	INDF	; Minute=0

	incf	FSR,f	; -> Stunde
	call	IncDec	; Stunde
	movlw	0x24
	xorwf	INDF,w
	skpz
	return
	clrf	INDF	; Stunde=0

	incf	FSR,f	; ->Tag
tickTag:
	call	IncDec	; Tag

	incf	FSR,f	; ->Monat
	movlw	8
	subwf	INDF,w
	movf	INDF,w
	skpnc
	addlw	-7
	andlw	0x01	
	addlw	0x31	; Monatslänge+1=31 oder 32
	movwf	temp
	movf	INDF,w
	xorlw	2	; Februar ?
	skpz
	goto	nofeb
	movlw	0x30	; im Ferbruar nur 30
	movwf	temp
	incf	FSR,f	; ->Jahr
	movf	INDF,w	; Jahr
	decf	FSR,f	; ->Monat
	andlw	0x13	; erfasst Jahr 0,4,8, 20...
	skpnz		
	goto	nofeb	; Schaltjahr
	xorlw	0x12	; erfasst 12, 16
	skpnz
	goto	nofeb	; Schaltjahr
	movlw	0x29	; kein Schaltjahr, nur 28 Tage
	movwf	temp
nofeb:	decf	FSR,f	; -> Tag
	movf	temp,w
	xorwf	INDF,w
	skpz
	return
	movlw	1
	movwf	INDF	; Tag=1

	incf	FSR,f	; -> Monat
	call	IncDec	
	movf	INDF,w
	xorlw	0x13
	skpz
	return
	movlw	1
	movwf	INDF	; Monat=1

	incf	FSR,f	; -> Jahr
	call	IncDec	
	return

IncDec:	incf	INDF,f
	movf	INDF,w
	andlw	0x0f
	xorlw	0x0a
	skpz
	return
	movlw	0x06
	addwf	INDF,f
	return

button3:
	incf btn3,f
	btfsc btn3,7	
	call slow3
	return

plus1min:
	incf	tenmin,f
	clrf 	dispSec
	clrf	btn3
	clrf	sbtn3
	
	movf tenmin,w
	addlw 0xf5
	skpnc	
	goto plushour
	movlw	dispMin
	movwf	FSR
	call	IncDec	; Minute
	movlw	0x60
	xorwf	INDF,w
	skpz
	return
	clrf	INDF	; Minute=0

	incf	FSR,f	; -> Stunde
	call	IncDec	; Stunde
	movlw	0x24
	xorwf	INDF,w
	skpz
	return
	clrf	INDF	; Stunde=0

	incf	FSR,f	; ->Tag
	goto plend

plushour:
	movlw 0x01
	movwf quick
	movlw	dispMin
	movwf	FSR 
	clrf	INDF	; Minute=0
	incf	FSR,f	; -> Stunde
	call	IncDec	; Stunde
	movlw	0x24
	xorwf	INDF,w
	skpz
	return
	clrf	INDF	; Stunde=0
	incf	FSR,f	; ->Tag
	movlw 0x0a
	movwf tenmin 

plend:
	return



slow3:
	clrf btn3
	incf sbtn3,f
	btfss quick,0
	goto quickstep
	btfsc sbtn3,3
	call plus1min
	return
quickstep:	
	btfsc sbtn3,1	
	call plus1min
	return


	end
