	list b=4
;********************************************************************
;* 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
; 1.1      18.09.09 adjust,date and 6 tube mode  by Sooty  
; 1.2	   21.03.10 improved pic16f628 compatibile version by Sooty
; 1.3 beta 10.09.10 some effects by Sooty (other pic support by Hp41c)
;********************************************************************

#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

; V added porting to 16F627,628(A)
  ifdef __16F84
	include	<p16f84.inc>
  endif
  ifdef __16F84A
	include	<p16f84a.inc>
  endif

  ifdef __16F627
	include	<p16f627.inc>
  endif
  ifdef __16F627A
	include	<p16f627a.inc>
  endif
  ifdef __16F628
	include	<p16f628.inc>
  endif
  ifdef __16F628A
	include	<p16f628a.inc>
  endif
; ^ added porting to 16F627,628(A)

	include "pic16cxy.inc"

;****** Variablen ***************************************************
 
; V added porting to 16F627,628(A)
  ifdef CMCON
#define	RamBeg	0x20
  else
#define	RamBeg	0x0C
  endif

  cblock	RamBeg
; ^ added porting to 16F627,628(A)

	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, stored
;*** fade variables
	fade56, fade34, fade12, fa_delay
;*** display digit variables
	show56, show34, show12, blink
;*** animation effect variables
	roller, scroller, animation, ani,anim_on 
 
LastBank0:
  endc

; V added porting to 16F627,628(A)
  ifdef __16F84
	IF LastBank0 > 0x30
		ERROR "To many variables used in Bank0 RAM"
	ENDIF
  endif
  ifdef __16F84A
	IF LastBank0 > 0x30
		ERROR "To many variables used in Bank0 RAM"
	ENDIF
  endif
  ifdef	CMCON
	IF LastBank0 > 0x70
		ERROR "To many variables used in Bank0 RAM"
	ENDIF
  endif
; ^ added porting to 16F627,628(A)

;****** 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
	bcf STATUS,6		; pic16f628 compatibile
	bcf STATUS,7		; STATUS 6,7 must be 0
	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

	movf blink,w  ;blinking when change on show date mode accepted
	addlw 255
	skpnc 
	decfsz blink,f
	goto normal
	movlw 0x0f
	movwf disp_on
	clrf btn2
	clrf sbtn2
normal	
	movf	dispMin,w ; normal display
	movwf	show34	;show34=dispMin
	movf	dispStd,w
	movwf	show12	;show12=dispStd
	movf	dispSec,w
	movwf	show56	;show56=dispSec

	

chkdatebtn	
	btfsc 	PORTA,3	;if date on or date button pressed -> show date on display from 30th sec to 40th sec
	goto	showdate
	btfss 	date_on,1 
	goto 	fade
	btfss 	dispSec,5
	goto 	fade 
	btfss 	dispSec,4
	goto	fade
	
	
	
showdate
	movf	dispMon,w
	movwf	show34	
	movf	dispJahr,w
	movwf	show12	
	movf	dispTag,w
	movwf	show56
	
	call animate

;****** fade effect between displayed numbers  ***************
fade
	decfsz fa_delay,f
	goto fadeout
	movlw TICKS/4
	movwf fa_delay
	movf	show34,w
	movwf	fade34
	movf	show12,w
	movwf	fade12	
	movf	show56,w
	movwf	fade56	
fadeout
	
	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 
		
	btfss 	PORTB,3
	clrf 	btn1
	btfss 	PORTA,3
	clrf	btn2	
	btfss 	PORTA,4
	clrf	btn3	

	btfsc 	PORTB,3
	call 	button1
	btfsc 	PORTA,3
	call	button2	
	btfsc 	PORTA,4
	call	button3	

	btfss 	PORTB,3
	clrf 	btn1
	movlf 	0xff,PORTB
	btfss	disp_on,0
	return
		
	movf	precount,w
	andlw	0x0f
	addwf	PCL,f
	goto	scan0
	goto	scan1
	goto	scan2
	goto	scan3
	goto	scan4
	goto	scan5
	goto	scan6
	goto	scan7
	goto	scan0f
	goto	scan1f
	goto	scan2f
	goto	scan3f
	goto	scan4f
	goto	scan5f
	goto	scan6f
	goto	scan7f

  
scan0	movf	show56,w	
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x03	
	movwf	PORTB
	return			
scan1 swapf	show56,w
	andlw	0xf0
	iorlw	0x0f	
	movwf	PORTB
	andlw	0xf0
	iorlw	0x02
	movwf	PORTB	
	return
scan2	movf	show34,w
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x01
	movwf	PORTB	
	return
scan3	swapf	show34,w
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x06
	movwf	PORTB	
	return
scan4	movf	show12,w			
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x05	
	movwf	PORTB
	return
scan5	swapf	show12,w
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x04	
	movwf	PORTB
	return	
scan6	movf	show56,w					
	andlw	0xf0
	iorlw	0x0f	
	movwf	PORTB
	andlw	0xf0
	iorlw	0x07	
	movwf	PORTB
	return
scan7	swapf	show56,w
	andlw	0xf0
	movwf	PORTB
	andlw	0xf0
	iorlw	0x00	
	movwf	PORTB
	return		
scan0f	movf	fade56,w	
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x03	
	movwf	PORTB
	return			
scan1f swapf	fade56,w
	andlw	0xf0
	iorlw	0x0f	
	movwf	PORTB
	andlw	0xf0
	iorlw	0x02
	movwf	PORTB	
	return
scan2f	movf	fade34,w
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x01
	movwf	PORTB	
	return
scan3f	swapf	fade34,w
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x06
	movwf	PORTB	
	return
scan4f	movf	fade12,w			
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x05	
	movwf	PORTB
	return
scan5f	swapf	fade12,w
	andlw	0xf0
	iorlw	0x0f
	movwf	PORTB
	andlw	0xf0
	iorlw	0x04	
	movwf	PORTB
	return	
scan6f	movf	show56,w					
	andlw	0xf0
	iorlw	0x0f	
	movwf	PORTB
	andlw	0xf0
	iorlw	0x07	
	movwf	PORTB
	return
scan7f	swapf	show56,w
	andlw	0xf0
	movwf	PORTB
	andlw	0xf0
	iorlw	0x00	
	movwf	PORTB
	return		

;****** Hauptprogramm ***********************************************
main    

	MOVLW 7				;pic16f628 compatibile settings
	MOVWF CMCON			;comparators off

	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'00011001',TRISA	; porta3,4=button2,3 ; porta0=dcf in
	movlf	0x08,TRISB	; portb0..2,4..7output ; portb3=button1

; buttons -> button1= display on/off  button2= show date on/off button3= adjust time (fast forward)  

	bcf	STATUS,RP0	; select Register-Page 0

	clrf	flag
	clrf	puls_zeit
	movlf	TICKS,zweihund

	clrf	dispSec
	clrf	fade56
	clrf	show56
 	movlw	0x12
 	movwf	dispStd
	movwf	fade12
	movwf	show12
 	movlw	0x34
 	movwf	dispMin
	movwf	fade34
	movwf 	show34
	clrf	btn1
	clrf	btn2
	clrf	btn3
	clrf	sbtn1
	clrf	sbtn2
	clrf	dispWtag
	clrf	dispJahr
	clrf	blink
		
	movlw 0x0f	;initial value display on, date off, fa_delay=0.25s
	movwf	disp_on
	movlw TICKS/4
	movwf	fa_delay 
	movlw 0xf0
	movwf	date_on
	movwf	anim_on
	movlw	1
	movwf	dispMon
	movwf	dispTag
	movlw 8
	movwf	animation
	movlw TICKS/10
	movwf	ani
	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
	movlw 8
	movwf	animation
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,6	
	call plus1min
	return

button2:
	incf btn2,f
	btfsc btn2,7
	call slow2
	return

button1:
	incf btn1,f
	btfsc btn1,7	
	call slow1
	return

plus1min:
	clrf 	dispSec
	clrf	btn3
	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

	return


slow1:
	clrf btn1
	incf sbtn1,f
	btfsc sbtn1,3	
	call on_off_disp
	return
slow2:
	clrf btn2
	incf sbtn2,f
	btfsc sbtn2,6	
	call on_off_date
	return
on_off_date:
	clrf btn2
	clrf sbtn2
	swapf date_on,f
	call blink3
	return
on_off_disp:
	clrf btn1
	clrf sbtn1
	swapf disp_on,f
	return
blink3
	movlw 0xf0
	movwf disp_on
	movlw TICKS/2
	movwf blink
	return	
	
animate
	btfsc 	PORTA,3	;if button pressed -> no animation
	goto 	end_ani
	movlw	8
	xorwf	animation,w
	skpnz
	goto	ani0
	movlw	7
	xorwf	animation,w
	skpnz
	goto	ani1
	movlw	6
	xorwf	animation,w
	skpnz
	goto	ani2
	movlw	5
	xorwf	animation,w
	skpnz
	goto	ani3
	movlw	4
	xorwf	animation,w
	skpnz
	goto	ani4
	movlw	3
	xorwf	animation,w
	skpnz
	goto	ani5
	movlw	2
	xorwf	animation,w
	skpnz
	goto	ani6
	movlw	1
	xorwf	animation,w
	skpnz
	goto	ani7
	
	;clrf	animation
	goto	ani_zero

ani0
	movlw 0x12
	movwf fade12
	movwf show12
	movlw 0x34
	movwf fade34
	movwf show34
	movlw 0x56
	movwf fade56
	movwf show56
	goto common
ani1
	movlw 0x23
	movwf fade12
	movwf show12
	movlw 0x45
	movwf fade34
	movwf show34
	movlw 0x67
	movwf fade56
	movwf show56
	goto common
ani2
	movlw 0x34
	movwf fade12
	movwf show12
	movlw 0x56
	movwf fade34
	movwf show34
	movlw 0x78
	movwf fade56
	movwf show56
	goto common
ani3
	movlw 0x45
	movwf fade12
	movwf show12
	movlw 0x67
	movwf fade34
	movwf show34
	movlw 0x89
	movwf fade56
	movwf show56
	goto common
ani4
	movlw 0x56
	movwf fade12
	movwf show12
	movlw 0x78
	movwf fade34
	movwf show34
	movlw 0x90
	movwf fade56
	movwf show56
	goto common
ani5
	movlw 0x67
	movwf fade12
	movwf show12
	movlw 0x89
	movwf fade34
	movwf show34
	movlw 0x01
	movwf fade56
	movwf show56
	goto common
ani6
	movlw 0x78
	movwf fade12
	movwf show12
	movlw 0x90
	movwf fade34
	movwf show34
	movlw 0x12
	movwf fade56
	movwf show56
	goto common
ani7
	movlw 0x89
	movwf fade12
	movwf show12
	movlw 0x01
	movwf fade34
	movwf show34
	movlw 0x23
	movwf fade56
	movwf show56
	goto common
ani_zero

	goto nodec

common
	decfsz ani,f
	goto nodec
	decf animation,f
	movlw TICKS/10
	movwf ani
	goto end_ani
nodec
	;movf dispJahr,w
	;movwf fade12
	;movwf show12
	;movf dispMon,w
	;movwf fade34
	;movwf show34
	;movf dispTag,w
	;movwf fade56
	;movwf show56
end_ani
	return


	end

