 TITLE  "7seg2.asmt"    ; displaying 0,1,...,99 on a double digit LED
 List P=16F84a, R=DEC
 INCLUDE "p16F84a.inc"

; data segment
 CBLOCK 0x00C                   
 del, n					; variables for passing the parameters
 delTMP					; local var for the delay function 
 n1, n0					; digits to display on LEDs (left,right)
 d					; currently processing digit (1 or 2) 
 s					; counter update speed (500 ms)
 segments:10				; 7-seg codes array
 ENDC

; code segment
 PAGE
 __CONFIG _CP_OFF & _PWRTE_ON  & _WDT_OFF & _XT_OSC

  org 0                      		; start program at the beginning of mem
  	bsf    	STATUS, RP0      	; change to BANK 1
	movlw	3
	movwf	PORTA			; turn off all digits	
	
  	clrf    TRISB ^ 0x80      	; enable RB1-RB7 for output
  	movlw	0x1C
  	movwf	TRISA ^ 0x80		; enable RA0 and RA1 for output 
  	
  	movlw  	0x7F              	; enable internal Pull-Ups
  	movwf  	OPTION_REG ^ 0x80
  	bcf    	STATUS, RP0        	; back to BANK 0

; initialization
	call 	initSegments
    	clrf	n1          		; start counting with 00
    	clrf	n0 
   	movlw	1           		; start displaying the left digit
	movwf	d			; this number will flip between 2 and 1
	movlw	25			; set up counter update speed 500ms
	movwf	s			; 2*10*25 = 500ms 

; main loop
loop
	movf	n1, w       		; display the left digit n1
	movwf	n			; pass n1 to displayDigit as n
	call	displayDigit		; update the left digit

	movf	n0, w			; display the left digit n0
	movwf	n			; pass n0 to displayDigit
	call	displayDigit		; update the right digit

	decfsz	s, f			; time to update the counter?
	goto 	loop			; NO - display same digits n1,n0 again

; update the counter digits n1 and n0
	movlw	25			; YES - update n0 (and n1)
	movwf	s			; restore s

	incf	n0, f			; n0++ (the right digit)	
 	movf	n0, w
	sublw	10	   
	btfss	STATUS, Z		; n0 == 10?	
	goto	loop			; NO - continue

	clrf 	n0 			; YES - reset n0 to 0
	incf	n1, f			; increment the right digit
	movf	n1, w
	sublw	10
	btfss	STATUS, Z		; n1 == 10?
	goto 	loop			; NO - digits update is done
	clrf	n1			; YES - reset n1 to 0
	goto 	loop

; procedures
displayDigit   				; display digit n at position d
  	movf	d, w
	movwf	PORTA			; start displaying the digit #d
	xorlw	3           		; flip d
	movwf	d			; save it

	movfw	n			; get parameter to w
	addlw	segments
	movwf	FSR         		; FSR is a pointer to the digit code
	movf	INDF, w			; w = segments[digit]
	xorlw	0xFF			; invert the code for a common anode LED
	movwf	PORTB       		; light on the digit
	
	movlw	10			; a 10ms delay
	movwf	del
	call 	delay				
	return

initSegments				; set up 7-seg digit codes
  	movlw	b'11011110' 		; gidit 0
	movwf	segments+0
	movlw	b'00011000' 		; digit 1
	movwf	segments+1
	movlw	b'11101100'		; digit 2
	movwf	segments+2
	movlw	b'01111100'		; digit 3
	movwf	segments+3
	movlw	b'00111010'		; digit 4	
	movwf	segments+4
	movlw	b'01110110'		; digit 5
	movwf	segments+5
	movlw	b'11110110'		; digit 6
	movwf	segments+6
	movlw	b'00011100'		; digit 7
	movwf	segments+7
	movlw	b'11111110' 		; digit 8
	movwf	segments+8
	movlw	b'01111110'		; digit 9
	movwf	segments+9
	return

delay					; a delay for del milliseconds
	movlw 	200
	movwf	delTMP
delL	
	nop				; this loop takes 5us*200 = 1ms
	nop				; for PIC16F84A @ 4 Mhz
	decfsz	delTMP, f
	goto 	delL

	decfsz	del
	goto 	delay
	return

 end
