 TITLE  "wind.asm"           		; test code to calibrate the anemometr 
 List P=PIC16F84A, R=DEC
 INCLUDE "p16f84a.inc"

; data segment
 CBLOCK 0x20                   
 del, dis	  			; variables used for delay
 wind					; wind sensor counter
 d, n, r, cnt, temp			; local variables
 segments:10				; code to drive 7-segment LED
 w_save, stat_save			; locations to save W and STATUS in ISR
 ENDC

; code segment
 PAGE
 __CONFIG _CP_OFF  & _PWRTE_ON  & _WDT_OFF & _HS_OSC

  ORG 0                      		; start program at the beginning of mem
	goto main

  ORG 4					; Interrupt Service Routie
	movwf	w_save			; save W reg
	swapf	STATUS, w		; save stat reg without
	movwf	stat_save		; changing flags
	bcf	INTCON, INTF		; clear hardware interrupt flag

	btfsc	PORTA, 3		; check for the processing time
	incf	wind, f			; update wind counter

	swapf	stat_save, w		; get orig flags in STATUS
	movwf	STATUS
	swapf	w_save, f		; restore the original W
	swapf	w_save, w
	retfie

main					; main code
	bcf	STATUS, RP0		; activate BANK 0
	clrf	PORTA			; initialize PORT A
	clrf	PORTB			; initialize PORT B
	bsf    	STATUS, RP0      	; change to BANK 1
	movlw	b'01000111'
	movwf	OPTION_REG ^ 0x80	; set up timer0
	movlw	0xF0
	movwf	TRISA ^ 0x80		; enable output on PORTA<3:0>
	movlw	1			; enable input on PORTB0
	movwf	TRISB ^ 0x80		; configure PORTB<6:1> for output
	bcf    	STATUS, RP0        	; back to BANK 0
	movlw	b'10010000'		; enable PORTB<0> interrupts
	movwf	INTCON			

	call	initSegments		; setup 7-seg LED codes
	clrf	wind			; clear the wind counter
loop
; counting pulses from the wind sensor
	movlw	0xF8			; shut down the display
	andwf	PORTA, f
		
	clrf	wind			; clear the wind counter
	movlw	-64			; measurement interval 2^22usec =4.2sec
	bsf	PORTA, 3		; measurement LED ON
 	call	delayL
	bcf	PORTA, 3		; LED off	

; display the results
	movlw	-32			; display interval 2^21usec = 2sec
	movwf 	dis			; set delay counter

	bcf	INTCON, 2		; clear timer IR bit
	clrf	TMR0			; clear timer

L2	btfsc	INTCON, 2		; check for timer overflow
	goto 	L3
	call 	display			; display the wind value
	goto 	L2	

L3	bcf	INTCON, 2		; handling 32 TMR0 overflows to
	incfsz 	dis, f			; reach the required delay
	goto 	L2	
	goto 	loop

display					; display the results	
	movf	wind, w			; copy counter value for displaying
	movwf	n		

	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
	return
	
displayDigit   				; display digit r at position d
	movlw	0xF8			; clear display
	andwf	PORTA, f
  	movf	d, w
	iorwf	PORTA, f		; 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	7			; a 7ms 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

delayL                                  ; long (4.2sec delay for measurement)
	movwf 	del			; set delay counter

	bcf	INTCON, 2		; clear timer bit
	clrf	TMR0

L1	btfss	INTCON, 2		; check for timer overflow
	goto 	L1
	
	bcf	INTCON, 2
	incfsz 	del, f
	goto 	L1
	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, f
	goto 	delay
	return
 end
