 TITLE  "LM60 based thermometer"   	  
 List P=PIC16F628A, R=DEC	
 INCLUDE "p16f628a.inc"

 __CONFIG _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

#define	ENA 		PORTB,4
#define	SDT			PORTB,3
#define	SCK 		PORTB,2
#define SCL			2			; I2C clock line setup
#define SDA			1			; I2C data line setup
#define	I2C_port 	PORTA		; I2C port setup	
#define	I2C_conf 	TRISA		; I2C PIC's direction register

 CBLOCK 0x20       				; data segment in BANK 0   
 n:2, dat:2, del 
 cnt, dataIO, ACK
 ENDC					

; code segment
 ORG 0     		               	; main code
	bcf		STATUS, RP0			; activate BANK 0
	clrf	PORTA				; initialize PORT A
	clrf	PORTB				; initialize PORT B
	bsf		I2C_port, SCL
	movlw	0x07
	movwf	CMCON				; comparators OFF
	
	bsf    	STATUS, RP0      	; switch to BANK 1	
	movlw	b'00100010'
	movwf	TRISA ^ 0x80		; enable input on RA2
	clrf	TRISB ^ 0x80		; enable output on PORTB
	bcf		STATUS, RP0			; back to BANK 0

	call	init_MAX6950		; initialize the LED driver 

loop
	call	requestData			; request data for odd values of mode
	movlw	250
	movwf	del
	call	delay				; 0.25 sec delay

	call	getData				; get data for even values of mode
	call	display
  	goto 	loop				; endless loop

;//////////////// procedures
init_MAX6950
	movlw	1
	movwf	dat+1				; decode register
	movlw	b'00001111'			; enable decoding for all digits
	movwf	dat
	call	write_MAX6950
 
	movlw	2
	movwf	dat+1				; intensity register
	movlw	1
	movwf	dat					; initial intensity 1/16
	call	write_MAX6950

	movlw	3
	movwf	dat+1				; scan limit register
	movlw	3
	movwf	dat					; scan 4 digits
	call	write_MAX6950
	
	movlw	4
	movwf	dat+1				; config register
	movlw	b'00100001'			; no blinking, normal mode, reset
	movwf	dat					
	call	write_MAX6950
	return

write_MAX6950					; write a 16-bit word; first byte is reg address
	movlw	16					; bits counter
	bcf		SCK					; make sure that SCK=0
	bcf		ENA					; enable the device

write_loop	
	rlf		dat, f
	rlf		dat+1, f			; shift out MSB to 
	btfsc	STATUS, C
	 bsf	SDT
	btfss	STATUS, C
	 bcf	SDT					; the data line is set up now
	bsf		SCK					; clock up
	nop							; short delay
	bcf		SCK					; ... and down	
	addlw	-1
	btfss	STATUS, Z			; all bits sent?
	 goto	write_loop			; not yet

	bsf		ENA					; yes - latch in the data and exit
	return	

display							; display ADC data in HEX
	movf	n+1, w
	movwf	dat		
	swapf	dat, f
	bcf		dat, 7
	movlw	0x63				; digit 3 address
	movwf	dat+1
	call	write_MAX6950

	movf	n+1, w
	movwf	dat	
	bcf		dat, 7	
	movlw	0x62				; digit 2 address
	movwf	dat+1
	call	write_MAX6950

	movf	n, w
	movwf	dat		
	swapf	dat, f
	bcf		dat, 7
	movlw	0x61				; digit 1 address
	movwf	dat+1
	call	write_MAX6950

	movf	n, w
	movwf	dat	
	bcf		dat, 7	
	movlw	0x60				; digit 0 address
	movwf	dat+1
	call	write_MAX6950
	return

requestData	
	bsf		PORTA, 0		
	call	start_I2C			; start communication
	movlw	b'11010000'			; MCP3425 address and write
	movwf	dataIO
	call	write_I2C			; write adress byte
	movlw	b'10001000'			; single conversion request
	movwf	dataIO				; 16-bit, PGA=1
	call	write_I2C			; write configuration byte
	call	stop_I2C			; terminate communication
	bcf		PORTA, 0
	return

getData
	call	start_I2C			; start communication
	movlw	b'11010001'			; MCP3425 address and read
	movwf	dataIO
	call	write_I2C
	clrf	ACK					; setup the ACK signal
	call	read_I2C			; get MSB
	movf	dataIO, w
	movwf	n+1					; save it in n+1
	incf	ACK, f				; setup for NACK signal
	call	read_I2C			; get MSB
	movf	dataIO, w
	movwf	n					; save it in n
	call	stop_I2C			; terminate communication
	return

delay
	movlw	200					; this loop takes 1us*5*200 = 1ms
	addlw	-1					; for PIC @ 4 MHz
	nop
	btfss	STATUS, Z
	 goto 	$-3
	decfsz	del, f
	 goto	$-6
	return

;;;;;;;;;;;;;;;;;;;;;;;implementation of the I2C interface
;       ___        
; DATA:    |_______
;       ______    
; SCK :       |___
start_I2C						; start setup for I2C interface
	movlw	I2C_conf			; setup FSR to point to TRISC
	movwf	FSR
	bsf		INDF, SDA			; pull high SDA and SCL
	bsf		I2C_port, SCL
	nop							; delay slot
	bcf		I2C_port, SDA
	bcf		INDF, SDA			; set data low
	bcf		I2C_port, SDA
	goto	$+1					; wait for slave to detect it
	bcf		I2C_port, SCL		; set clock low
	return
;              ___        
; DATA: ______|   
;           ______    
; SCK : ___|
stop_I2C						; stop setup for I2C interface
	bcf		I2C_port, SCL		; make sure that clock and data
	bcf		I2C_port, SDA
	bcf		INDF, SDA			; lines are low
	goto	$+1
	bsf		I2C_port, SCL		; release clock line
	goto	$+1
	bsf		INDF, SDA			; release data line
	return

write_I2C						; write a byte to the I2C bus
	bcf		I2C_port, SCL		; make sure that clock is low
	bcf		I2C_port, SDA
	movlw	8
	movwf	cnt					; bits counter

w_loop
	bcf		I2C_port, SDA		; preset 0 on data line
	rlf		dataIO, f			; get the rightmost data bit
	btfsc	STATUS, C
	 bsf	INDF, SDA			; set data high
	btfss	STATUS, C
	 bcf	INDF, SDA			; set data low
	bsf		I2C_port, SCL		; raise clock up
	nop
	bcf		I2C_port, SCL		; ... and down
	decfsz	cnt, f
	 goto	w_loop				; repeat this 8 times

	bsf		INDF, SDA			; get ACK from slave		
	goto	$+1					; let slave respond
	bsf		I2C_port, SCL		; clock up
	nop							; slave responds OK (hopefully)
	bcf		I2C_port, SCL		; clock down
	return

read_I2C						; read byte from I2C bus
	bcf		I2C_port, SCL		; make sure that clock is low		
	movlw	8
	movwf	cnt					; bits counter	

r_loop
	bsf		I2C_port, SCL		; clock up
	bcf		STATUS, C
	btfsc	I2C_port, SDA
	 bsf	STATUS, C			; C = data bit
	bcf		I2C_port, SCL		; clock down
	rlf		dataIO, f			; insert it into the data byte
	decfsz	cnt, f
	 goto	r_loop				; repeat this 8 times

	movf	ACK, f				; set Z flag
	bcf		I2C_port, SDA
	btfsc	STATUS, Z
	 bcf	INDF, SDA			; ACK signal
	bsf		I2C_port, SCL		; clock up
	goto	$+1
	goto	$+1
	nop
	bcf		I2C_port, SCL		; clock down
	bsf		INDF, SDA			; release the data line
	return

 
 END
