 TITLE  "7seg3.asm"    ; displaying 0,1,...,255 on a triple digit LED
 List P=16F84a, R=DEC
 INCLUDE "p16F84a.inc"

; data segment
 CBLOCK 0x00C                   
 del, n, r						; variables for passing the parameters
 count							; number to display	
 temp, cnt						; local variable 
 d								; currently processing digit (1, 2, or 4) 
 s								; counter update speed (360 ms)
 segments:10					; 7-seg codes array
 ENDC

; code segment
 PAGE
 __CONFIG _CP_OFF  & _PWRTE_ON  & _WDT_OFF & _HS_OSC

  org 0                      	; start program at the beginning of mem
  	bsf    	STATUS, RP0      	; change to BANK 1
	clrf	PORTA				; turn off all digits	
	
  	clrf    TRISB ^ 0x80      	; enable RB1-RB7 for output
  	movlw	0x18
  	movwf	TRISA ^ 0x80		; enable RA0-RA2 for output 
  	
  	movlw  	0x7F              	; enable internal Pull-Ups
  	movwf  	OPTION_REG ^ 0x80
  	bcf    	STATUS, RP0        	; back to BANK 0

; initialization
	call 	initSegments
    clrf	count	          	; start counting with 0
	movlw	15					; set up counter update speed 360ms
	movwf	s					; 3*8*15 = 360ms 

; main loop
loop
	movf	count, w
	movwf	n					; copy count to n for processing

	clrf	d					; start displaying the rightmost digit
	incf	d, f				; d = 1
	call 	div10				; computing n = n/10 and r = n%10
	call 	displayDigit

	incf	d, f				; do the same with the middle digit
	call 	div10
	call 	displayDigit

	incf	d, f				; ... and the leftmost one
	incf	d, f				; (its d-index is 4)
	call	div10
	call 	displayDigit

	decfsz	s, f				; time to update the counter?
	goto 	loop				; NO - display same digits n1,n0 again

; update the counters
	movlw	15					; YES - update 
	movwf	s					; restore s
	incf	count, f			; count++
	goto 	loop

; procedures
displayDigit   					; display digit r at position d
  	movf	d, w
	movwf	PORTA				; start displaying the digit #d

	movf	r, w				; get parameter to w
	addlw	segments
	movwf	FSR         		; FSR is a pointer to the digit code
	movf	INDF, w				; w = segments[digit]
	movwf	PORTB       		; light on the digit
	
	movlw	8					; a 8ms delay
	movwf	del
	call 	delay				
	return

div10							; computing n = n/10 and r = n%10
	movlw	5
	movwf	cnt					; cnt = 5
	movf	n, w				
	movwf	r					; r = n
	clrf	n					; n = 0
	movlw	0xA0
	bsf		STATUS, C
		
	subwf	r, f				; loop that executes 5 times
	btfsc	STATUS, C
	goto	$+3
	addwf	r, f
	bcf		STATUS, C

	rlf		n, f				; C = bit of n/10
	movwf	temp
	rrf		temp, f
	movf	temp, w				; shift right W

	decfsz 	cnt, f				; div is done in 5 loop iterations
	goto	$-10				; end of loop
    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
	
	sublw	1					; this loop takes 5us*200 = 1ms
	sublw	0					; for PIC16F84A @ 4 Mhz
	btfss	STATUS, Z
	goto 	$-3

	decfsz	del
	goto 	delay
	return

 end