;----------------------------------------------------------
;	File	VFD.asm
;
	TITLE	"Vacuum Fluorescent Display Driver"
;----------------------------------------------------------
;
	LIST	p=16C84
;
	include "reg84.h"
;
;----------------------------------------------------------
; Equates
;
IntInterval	equ	0x4	; interrupt interval
; Port B pin assignments
DispData	equ	0	; Data pin is RB0
DispClk		equ	1	; Clock pin is RB1
DispStb		equ	2	; Strobe pin is RB2
;
;----------------------------------------------------------
; External hardware
;
; A 0 will shut the segment/digit off. A 1 will light up the segment 
; or enable the digit. Assuming the left most digit is shifted out 
; first, the bits are
; [Dig 4] [Dig 3] [Dig Mid] [Dig 2] [Dig 1] followed by
; [Auto] [Seg g] [Seg f] [Seg e] [Seg d] [Seg c] [Seg b] [Seg a]
; The shift registers are 10 bit - so the segment bits are preceded
; by two dummy bits
;
;----------------------------------------------------------
RtccCount	equ	07ah
; This was a count used for some other application with a 10 MHz crystal.
; This app has a 3.58 MHZ crystal. Let us see what we get...
; With an overhead, the count is 0x6f. No of cycles = 0 - 0x6f = 145
; The rate = 145 * 3.58 / 4 = 129.774 us = 130 us(approx)
;
;----------------------------------------------------------
; Data
	ORG	0CH	; Data Origin
;
SaveWReg	res	1
SaveStat	res	1
;
Digit12		res	1	; Least significant two bytes
Digit34		res	1	; Most significant two bytes
DigitMid	res	1	; Centre symbol bit pattern
;
SegSr		res	1	; Segment shift register
;
SegInx		res	1	; Segment index(uses 3 bits)
IntCount	res	1	; Interrupt counter(uses 4 bits)
SegBitCnt	res	1	; Segment bit count(uses 3 bits)
;
Counter1	res	1	; General purpose slow counter
Counter2	res	1
;
;----------------------------------------------------------
; Program
;
	ORG	0	; Reset vector
;
	goto	main
;
;
	ORG	4	; Interrupt vector
;
	goto	DispISR
;
;
	ORG	8	; Program starts here
;
;----------------------------------------------------------
main	call	InitIsr
	movlw	0x21
	movwf	Digit12
	movlw	0x43
	movwf	Digit34
	movlw	55
	movwf	DigitMid
Loop	movlw	0x4
	xorwf	Counter2,0
	JMPNZ	Loop
	clrf	Counter2
	movlw	0x11
	addwf	Digit12,1
	addwf	Digit34,1
	decf	Counter1,1
	goto	Loop
;
;----------------------------------------------------------
InitIsr	
	bsf	RegStatus,BitRp0
	bcf	RegTrisb,DispData	; Set Data pin to output
	bcf	RegTrisb,DispClk	; Set Clock pin to output
	bcf	RegTrisb,DispStb	; Set Strobe pin to output
	bcf	RegOption,BitRts	; Enable RTCC timer
	bcf	RegStatus,BitRp0
	movlw	0
	movwf	RegRtcc
	movwf	SegInx
	movlw	1
	movwf	IntCount 
	bsf	RegIntcon,BitGie        ; Enable Global interrupt
	bsf	RegIntcon,BitRtie       ; Enable RTCC interrupt
	return
;
;----------------------------------------------------------
; Interrupt service routine to manage display
DispISR	btfss	RegIntcon,BitRtif
	retfie
	movwf	SaveWReg		; Save W and status
	swapf	RegStatus,w
	movwf	SaveStat
	bcf	RegStatus,BitRp0
	movlw	RtccCount		; Reload RTCC
	movwf	RegRtcc
;
	decfsz	IntCount,1		; if --IntCount != 0
	goto	SkipIsr			;   return
IncCnt	incf	Counter1,1
	JMPNZ	DoDisp
	incf	Counter2,1
DoDisp	movlw	IntInterval		; IntCount = IntInterval
	movwf	IntCount
	movlw	8
	movwf	SegSr			; SegSr = 8
	movf	SegInx,0		; W = SegInx
Loop1	btfsc	RegStatus,BitZero	; while W != 0
	goto	DigDone
	bcf	RegStatus,BitCarry
	rlf	SegSr,1			;   SegSr <<= 1
	addlw	0xff			;   --W
	goto	Loop1
;
DigDone	movlw	0xff
	movlw	5			; SegBitCnt = 5
	movwf	SegBitCnt
	call	DispDigit		; Display digit in SegSr
;
	movf	SegInx,0		; W = SegInx
	btfss	RegStatus,BitZero	; if SegInx == 0
	goto	NotDig1
	movf	Digit12,0		;   W(3,0) = Digit12(3,0)
	goto	GetSeg
;
NotDig1	xorlw	1			; else if SegInx == 1
	btfss	RegStatus,BitZero
	goto	NotDig2
	swapf	Digit12,0		;   W(3,0) = Digit12(7,4)
	goto	GetSeg
;
NotDig2	xorlw	1^3			; else if SegInx == 3
	btfss	RegStatus,BitZero
	goto	NotDig3
	movf	Digit34,0		;   W(3,0) = Digit34(3,0)
	goto	GetSeg
;
NotDig3	xorlw	3^4			; else if SegInx == 4
	btfss	RegStatus,BitZero
	goto	NotDig4
	swapf	Digit34,0		;   W(3,0) = Digit34(7,4)
	goto	GetSeg
;
NotDig4	movf	DigitMid,0
	movwf	SegSr
	goto	Disp
;
GetSeg	andlw	0xf			; if digit
	call	DigToSeg		;   W &= 0xf
	movwf	SegSr
Disp	movlw	8			;   SegBitCnt = 8
	movwf	SegBitCnt
	bcf	RegPortb,DispClk	;   Two dummy clocks
	bsf	RegPortb,DispClk	;
	bcf	RegPortb,DispClk	;
	bsf	RegPortb,DispClk	;
	call	DispDigit		; Display digit in SegSr
	bsf	RegPortb,DispStb	; Set strobe to high
	bcf	RegPortb,DispStb	; Set strobe to low
;
	movf	SegInx,0		; if --SegInx < 0
	addlw	0xff
	btfss	RegStatus,BitCarry
	movlw	4			;   SegInx = 4
	movwf	SegInx
;
SkipIsr	swapf	SaveStat,w
	movwf	RegStatus
	swapf	SaveWReg,w
	bcf	RegIntcon,BitRtif
	retfie
;
DispDigit				; do
	rlf	SegSr,1			;   SegSr <<= 1
	btfsc	RegStatus,BitCarry	;   Output carry
	bsf	RegPortb,DispData
	btfss	RegStatus,BitCarry
	bcf	RegPortb,DispData
	bcf	RegPortb,DispClk	;   Set clock to low
	bsf	RegPortb,DispClk	;   Set clock to high
	decfsz	SegBitCnt,1		; while --SegBitCnt != 0
	goto	DispDigit
SegEnd	return
;
;----------------------------------------------------------
; Subroutine to convert 4 bit digit in W to a 7 segment pattern. The bits
; correspond to auto, segment g to a from MSB to LSB. Due to the inversion 
; in the hardware, the bits have to be complemented.
DigToSeg
	addwf	RegPcl,1
	retlw	0x3f		; 00111111B		; 0
	retlw	0x06		; 00000110B		; 1
	retlw	0x5b		; 01011011B		; 2
	retlw	0x4f		; 01001111B		; 3
	retlw	0x66		; 01100110B		; 4
	retlw	0x6d		; 01101101B		; 5
	retlw	0x7d		; 01111101B		; 6
	retlw	0x07		; 00000111B		; 7
	retlw	0x7f		; 01111111B		; 8
	retlw	0x6f		; 01101111B		; 9
	retlw	0x77		; 01110111B		; A
	retlw	0x7c		; 01111100B		; b
	retlw	0x39		; 00111001B		; C
	retlw	0x5e		; 01011110B		; d
	retlw	0x79		; 01111001B		; E
	retlw	0x71		; 01110001B		; F
	return
;
	END
;----------------------------------------------------------

External Labels :