 TITLE  "thermo_dig.asm"   		; -55 - 120C termometer  
 List P=PIC16F628a, R=DEC
 INCLUDE "p16f628a.inc"

DQ	EQU	4						; DQ line setup

wait MACRO 	TIME				; Delay for TIME µs.
	movlw 	(TIME/5) - 2 		; must be a mult. of 5 and at least 10
	movwf 	del5 					
	call 	delay5 			
  ENDM

; data segment in BANK 0
 CBLOCK 0x20           
 tempRQ, d, tmp, cnt, tint  	; local variables 
 w_save, stat_save, pc_save		; ISR variables 
 point, scale, button, sign		; decimal point flag
 del5, err_1w, dataIO			; 1-WIRE interface vars
 hundreds, units, tens, fract	; vars for BCD conversion
 bcd:4							; BCD representation of TEMP
 temp:2				  			; storage for temp measurement
 conv:2, temp2:2				; storage for C -> F conversion
 divTMP							; used in div5 procedure
 ENDC					

; code segment
 PAGE
 __CONFIG _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSC_OSC_NOCLKOUT

  ORG 0
	goto 	main

  ORG 4						; ISR
	movwf	w_save			; save W reg
	swapf	STATUS, w		; save stat reg without
	movwf	stat_save		; changing flags
	movf	PCLATH, w
	movwf	pc_save

	bcf		INTCON, 2		; clear TMR0 INT flag
	call	displayDigit	; <45 mksec

	decfsz	tint, f			; time to read temp ?
	 goto	task2			; NO - get to the next task 

task1						; request new temp conversion
	movlw	100
	movwf	tint			; restore the temp interval cntr
	
	call 	getTemp1		; start TEMP conversion (~2msec)
	incf 	tempRQ, f		; set temp requested flag
	goto	ISR_end

task2						; fetch temp reading from slave
	btfss	tempRQ, 0		; new temp requested?
	 goto 	task3			; NO - get to the next task

	btfss	PORTA, DQ		; conversion is ready?
	 goto	ISR_end			; NO - return from INT

	clrf	tempRQ			; clear temp request flag
	call 	getTemp2		; get new temp reading (3msec)
	call	bin2bcd			; convert it into BCD (<1 msec)
	goto	ISR_end

task3						; check the C/F button status
	btfss	PORTA, 5				
	 goto	$+3
	clrf	button			; buton is not pressed - continue
	goto	ISR_end

	btfsc	button, 0		; button debouncing:
	 goto	ISR_end			; button was pressed and not released

	bsf		button, 0		; button is just presed
	movf	scale, w		; toggle the C/F status
	sublw	1					
	movwf	scale			; scale = 1 - scale
	addlw	10				; W = 10 or 11 to display C/F
	movwf	bcd				; setup the scale letter code
	call	bin2bcd			; according	to the scale (C/F)	

ISR_end
	movf	pc_save, w		; restore PCLATH
	movwf	PCLATH
	swapf	stat_save, w	; get orig flags in STATUS
	movwf	STATUS
	swapf	w_save, f		; restore the original W		
	swapf	w_save, w
	retfie

encode7seg					; set up 7-seg digit codes
	andlw	0x0F
	addwf	PCL, f
  	retlw	b'00111111' 	; gidit 0 pgfedcba
	retlw	b'00000110' 	; digit 1
	retlw	b'01011011'		; digit 2
	retlw	b'01001111'		; digit 3
	retlw	b'01100110'		; digit 4	
	retlw	b'01101101'		; digit 5
	retlw	b'01111101'		; digit 6
	retlw	b'00000111'		; digit 7
	retlw	b'01111111' 	; digit 8
	retlw	b'01101111'		; digit 9
	retlw	b'00111001'		; letter C
	retlw	b'01110001'		; letter F
	retlw	b'01000000'		; the - sign
	retlw	b'00000000'     ; blank
    retlw  	b'00001000'
    retlw	b'00001000'
  

main       		           	; main code
	bcf		STATUS, RP0		; activate BANK 0
	clrf	PORTA			; initialize PORT A
	clrf	PORTB			; initialize PORT C
	movlw	0x07
	movwf	CMCON			; comparators OFF
	
	bsf    	STATUS, RP0     ; change to BANK 1	
	movlw	b'10010011'		; TMR0 1:16 prescaler 
	movwf	OPTION_REG^0x80		

	movlw	b'00110000'
	movwf	TRISA ^ 0x80	; enable RA<5:4> for input
	clrf	TRISB ^ 0x80	; enable output on PORTB
	bcf    	STATUS, RP0     ; back to BANK 0

	movlw	100				; INITIALIZATION
	movwf	tint			; setup temp reading interval (4sec)
	clrf	scale			; scale: 0=C  1=F
	clrf	point			; decimal point flag
	clrf 	temp
	clrf	temp+1
	movlw	1
	movwf	d				; d is the digit code (0 - 3)

	movlw	0x0D			; initialize BCD array with blanks
	movwf	bcd+3
	movwf	bcd+2
	movwf	bcd+1
	movlw	0x0A				
	movwf	bcd
	
	movlw	b'10100000'		; enable TMR0 interrupts
	movwf	INTCON

	goto 	$				; infinite loop

; procedures
reset_1W					; reset in 1-wire interface
	movlw	0x85			; setup FSR to point to TRISA
	movwf	FSR
	bcf		PORTA, DQ
	bsf		INDF, DQ		; start with DQ line high
	nop
	bcf		INDF, DQ		; bring the DQ line low
	wait 	500				; wait for 500usec 
	bsf		INDF, DQ		; bring the line up again
	wait 	70 				; wait 70µs for slave responce
	clrf	err_1w
	btfss	PORTA, DQ		; check slave's responce
	incf	err_1w, f
	wait 	430 			; wait 430µs after slave responce
	return

write_1W					; write file DATA to 1W interface
	bcf		PORTA, DQ
	movlw	8
	movwf	cnt
w_loop
	bcf		INDF, DQ		; bring the DQ line low
	nop						; for 2 us
	nop
	rrf		dataIO, f		; shift rightmost bit to C		
	btfsc	STATUS, C		; bit == 1 ?
	 bsf	INDF, DQ		; YES - release the DQ line
	wait 	60				; 60us delay
	bsf		INDF, DQ		; release the DQ line
	nop						; relax for 2 us
	nop
	decfsz	cnt, f			; repeat this 8 times
	 goto	w_loop
	return

read_1W						; read a byte from 1W interface
	bcf		PORTA, DQ
	movlw	8
	movwf	cnt
r_loop
	bcf		INDF, DQ		; bring the DQ line low	
	goto	$+1				; for 6 usec
	goto	$+1
	goto	$+1
	bsf		INDF, DQ		; release the DQ line
	goto	$+1				; and wait for 6usec 
	goto	$+1				; for a response from slave
	goto	$+1
	movf	PORTA, w
	andlw	16
	addlw	255				; C = data bit
	rrf		dataIO, f
	wait	50				; wait for end of read slot
	decfsz	cnt, f			; repeat this 8 times
	 goto	r_loop
	return

getTemp1					; request TEMP conversion
	call	reset_1W		; INIT
	movlw	0xCC			; SKIP ROM command
	movwf	dataIO
	call	write_1W
	movlw	0x44			; CONVERT TEMP command
	movwf	dataIO
	call	write_1W
 return

getTemp2					; get TEMP reading from sensor
	call	reset_1W		; INIT
	movlw	0xCC			; SKIP ROM command
	movwf	dataIO
	call	write_1W
	movlw	0xBE			; READ SCRATCHPAD command
	movwf	dataIO
	call 	write_1W
	call 	read_1W			; read temp LSB
	movf	dataIO, w
	movwf	temp
	call	read_1W			; read temp MSB
	movf	dataIO, w
	movwf	temp+1
	return

bin2bcd						; convert tempAve into BCD representation
	clrf	sign
	clrf	point
	movf	temp, w			; preserve the original temp value
	movwf	conv			; by copying it to conv for
	movf	temp+1, w		; further processing
	movwf	conv+1
	
	btfsc	scale, 0		; scale == C?
	 call	convert			; convert C to F
	
	btfss	conv+1, 7		; temp < 0 ?
	 goto	frac			; NO - proceed
	movlw	0xFF			; convert temp to a positive
	xorwf	conv+1, f		; value in the 2's complement system
	xorwf	conv, f
	movlw	1
	addwf	conv, f
	btfsc	STATUS, C
	 incf	conv+1, f
	
	movlw	12				; the "-" sign code
	movwf	bcd+3
	incf	sign, f			; negative sign flag	

frac
	movf	conv, w
	andlw	0x0F
	movwf	fract			; fraction as int
	bcf		STATUS, C
	rlf		fract, f
	rlf		fract, f
	addwf	fract, f		; tmp = fraction*5
	rrf		fract, f				
	bcf		STATUS, C
	rrf		fract, f	
	bcf		STATUS, C
	rrf		fract, f
	btfsc	STATUS, C
	incf	fract, f		; rounding off

	rrf		conv+1, f		; fetching the integer part
	rrf		conv, f			; it all fits in 8 bits
	rrf		conv+1, f
	rrf		conv, f
	rrf		conv+1, f
	rrf		conv, f
	rrf		conv+1, f
	rrf		conv, w			; the int part of temp is in W
		
	clrf	hundreds
	clrf	tens
	clrf	units

dig2						; processing hundreds
	incf	hundreds, f
	addlw	-100
	btfsc	STATUS, C
	 goto	dig2
	decf	hundreds, f
	addlw	100

dig1						; processing tens
	incf	tens, f
	addlw	-10
	btfsc	STATUS, C
	 goto	dig1
	decf	tens, f
	addlw	10
	movwf	units			; processing units

	; packing the digits in BCD
	btfss	sign, 0			; temp < 0 ?
	 goto	positive		; NO - positive number processing
	movf	tens, f		
	btfss	STATUS, Z		; tens == 0 ?
	 goto	nofrac			; NO - drop the fraction

	movf	units, w		; -10 < temp < 0
	movwf	bcd+2			; display units and fraction	
	movf	fract, w
	movwf	bcd+1
	bsf		point, 7		; raise the decimal point flag
	return

nofrac
	movf	tens, w			; pack tens and units
	movwf	bcd+2
	movf	units, w
	movwf	bcd+1	
	return

positive
	movf	hundreds, f		; hundreds == 0 ?
	btfsc	STATUS, Z
	 goto 	nohundreds	
	
	movf	hundreds, w		; display a 3-digit number
	movwf	bcd+3
	movf	tens, w
	movwf	bcd+2
	movf	units, w
	movwf	bcd+1
	return

nohundreds
	movf	tens, w
	btfsc	STATUS, Z
	 movlw	13				; blank code  
	movwf	bcd+3			; display one or two-digit number
	movf	units, w		; and fraction
	movwf	bcd+2
	movf	fract, w
	movwf	bcd+1
	bsf		point, 7        ; decimal point
	return

displayDigit   				; display digit at position d
	movlw	0xF0
	andwf	PORTA, f		; shut down all digits
	btfss	d, 0
	 goto 	check2			; leftmost digit
	movf	bcd+3, w
	call	encode7seg		; w = segment code
	goto 	lightIt

check2
	btfss	d, 1			; middle number digit
	 goto	check3
	movf	bcd+2, w
	call	encode7seg
	addwf	point, w
	goto	lightIt

check3
	btfss	d, 2			; rightmost number digit
	 goto	check4
	movf	bcd+1, w
	call	encode7seg
	goto	lightIt

check4
	movf	bcd, w			; C/F LED
	call	encode7seg

lightIt		
	movwf	PORTB
	movf	d, w
	addwf	PORTA, f

	rlf		d, f			; next d in cyclic order
	movlw	1
	btfsc	d, 4
	 movwf	d
	return

delay5						; a delay for 5*del5 µs
	goto	$+1				; 2µs to process
	decfsz 	del5, f 		; 1µs if not zero or 2µs if zero
	goto 	delay5	 		; 2µs to process
	return		

convert						; convert C into F
	movf	temp, w			; input: temp; output: conv
	movwf	temp2			; save original temp in temp2
	movf	temp+1, w
	movwf	temp2+1

	btfss	temp+1, 7
	 goto	absolute
	movlw	0xFF			; complement temp2 if temp < 0
	xorwf	temp2+1, f
	xorwf	temp2, f
	movlw	1
	addwf	temp2, f
	btfsc	STATUS, C
	 incf	temp2+1, f	
	
absolute
	movf	temp2, w
	movwf	tmp
	movf	temp2+1, w		; w:tmp contain the orig. temp2
	bcf		STATUS, C
	rlf		temp2, f
	rlf		temp2+1, f
	rlf		temp2, f
	rlf		temp2+1, f
	rlf		temp2, f
	rlf		temp2+1, f		; now temp2 is 8*temp2
	addwf	temp2+1, f
	movf	tmp, w			; tmp = old temp2
	addwf	temp2, f
	btfsc	STATUS, C
	 incf	temp2+1, f		; now temp2 = temp2*9

	movf	temp2+1, w		; w = first devidend
	call	div5
	movwf	tmp 			; tmp = q1
	movwf	conv+1			; byte conv+1 is ready
	bcf		STATUS, C	
	rlf		tmp, f			; tmp = q1*2
	rlf 	tmp, f			; tmp = q1*4
	addwf	tmp, w			; w = q1*5
	subwf	temp2+1, w		; w = r1
	movwf	tmp
	swapf	tmp, f
	swapf 	temp2, w		; w = left nibble of temp
	andlw	0x0F
	addwf	tmp, w			; w = second dividend
	movwf	temp2+1			; save it

	call	div5			; w = q2
	movwf	tmp
	swapf	tmp, w
	movwf	conv			; left nibble of conv is ready
	swapf	conv, w			; w = q2 again
	bcf		STATUS, C	
	rlf		tmp, f			; tmp = q2*2
	rlf 	tmp, f			; tmp = q2*4
	addwf	tmp, w			; w = q2*5
	subwf	temp2+1, w		; w = r2
	movwf	tmp
	swapf	tmp, f
	movf 	temp2, w
	andlw	0x0F	
	addwf	tmp, w			; w = third devidend
	movwf	temp2			; save it	

	call 	div5
	addwf	conv, f			; conv is ready
	movwf	tmp
	bcf		STATUS, C	
	rlf		tmp, f			; tmp = q3*2
	rlf 	tmp, f			; tmp = q3*4
	addwf	tmp, w			; w = q3*5
	subwf	temp2, f		; temp = r3
	incf	temp2, f
	btfss	temp2, 2
	 goto 	compl
	movlw	1				; rounding off
	addwf	conv, f
	btfsc	STATUS, C		; now conv (2 bytes) equals
  	 incf	conv+1, f		; 9*temp / 5

compl
	btfss	temp+1, 7		; was temp (in C) negative?
	 goto   add32			; NO - proceed adding 32
	movlw	0xFF
	xorwf	conv+1, f		; YES - complement temp2
	xorwf	conv, f
	movlw	1
	addwf	conv, f
	btfsc	STATUS, C
	 incf	conv+1, f

add32
	movlw	2				; adding 32 to the result
	addwf	conv+1, f		; to complete the conversion
	return

div5
	movwf	divTMP			; save W
	movlw	high divTable		
	movwf	PCLATH			; PCLATH = table segment
	movf	divTMP, w		; restore original W
	addlw	low	divTable	; w = table offset
	btfsc	STATUS, C		; correct PCLATH
	 incf	PCLATH, f		;  (if needed)
	movwf	PCL				; jump to the table entry
divTable
	dt 0, 0, 0, 0, 0, 1, 1, 1
	dt 1, 1, 2, 2, 2, 2, 2, 3
	dt 3, 3, 3, 3, 4, 4, 4, 4
	dt 4, 5, 5, 5, 5, 5, 6, 6
	dt 6, 6, 6, 7, 7, 7, 7, 7
	dt 8, 8, 8, 8, 8, 9, 9, 9
	dt 9, 9, 10, 10, 10, 10, 10, 11
	dt 11, 11, 11, 11, 12, 12, 12, 12
	dt 12, 13, 13, 13, 13, 13, 14, 14
	dt 14, 14, 14, 15, 15, 15, 15, 15
	dt 16, 16, 16, 16, 16, 17, 17, 17
	dt 17, 17, 18, 18, 18, 18, 18, 19
	dt 19, 19, 19, 19, 20, 20, 20, 20
	dt 20, 21, 21, 21, 21, 21, 22, 22
	dt 22, 22, 22, 23, 23, 23, 23, 23
	dt 24, 24, 24, 24, 24, 25, 25, 25
	dt 25, 25, 26, 26, 26, 26, 26, 27
	dt 27, 27, 27, 27, 28, 28, 28, 28
	dt 28, 29, 29, 29, 29, 29, 30, 30
	dt 30, 30, 30, 31, 31, 31, 31, 31
	dt 32, 32, 32, 32, 32, 33, 33, 33
	dt 33, 33, 34, 34, 34, 34, 34, 35
	dt 35, 35, 35, 35, 36, 36, 36, 36
	dt 36, 37, 37, 37, 37, 37, 38, 38
	dt 38, 38, 38, 39, 39, 39, 39, 39
	dt 40, 40, 40, 40, 40, 41, 41, 41
	dt 41, 41, 42, 42, 42, 42, 42, 43
	dt 43, 43, 43, 43, 44, 44, 44, 44
	dt 44, 45, 45, 45, 45, 45, 46, 46
	dt 46, 46, 46, 47, 47, 47, 47, 47
	dt 48, 48, 48, 48, 48, 49, 49, 49
	dt 49, 49, 50, 50, 50, 50, 50, 51
 end
