 TITLE  "LCD direct drive"  
 List P=16F913, R=DEC
 INCLUDE "p16F913.inc"

SCL	EQU	1						; Clock line setup
SDA	EQU 0						; Data line setup

; data segment in the shared area
 CBLOCK 0x70             	 	
 tempC:2, tens, units, tempOld
 displayCodes:2, mode
 err_i2c, dataIO, ACK_NAK, cnt		; I2C interface vars
 ENDC

 __CONFIG _DEBUG_OFF & _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF &  _CP_OFF & _MCLRE_OFF & _PWRTE_ON  & _WDT_ON & _INTOSCIO
; __CONFIG _DEBUG_OFF & _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF &  _CP_OFF & _MCLRE_OFF & _PWRTE_ON  & _WDT_OFF & _INTOSCIO

 ORG 0
	btfss	STATUS, NOT_TO
	 goto 	loop	
	goto 	main

codeUr
	addwf 	PCL, f
	retlw 	b'00000111' 		; right part of digit 0
	retlw	b'00000001'			; right part of digit 1
	retlw	b'00001110'			; right part of digit 2
	retlw	b'00001011'			; right part of digit 3
	retlw	b'00001001'			; right part of digit 4
	retlw	b'00001011'			; right part of digit 5
	retlw	b'00001111'			; right part of digit 6
	retlw	b'00000001'			; right part of digit 7
	retlw	b'00001111'			; right part of digit 8
	retlw	b'00001011'			; right part of digit 9
	retlw	b'00001101'			; right part of digit A
	retlw	b'00001111'			; right part of digit B
	retlw	b'00000111'			; right part of digit C
	retlw	b'00001111'			; right part of digit D
	retlw	b'00001110'			; right part of digit E
	retlw	b'00001100'			; right part of digit F

codeUl
	addwf	PCL, f
	retlw	b'01000011'			; left part of digit 0
	retlw	b'00000001'			; left part of digit 1
	retlw	b'00000011'			; left part of digit 2
	retlw	b'00000011'			; left part of digit 3
	retlw	b'01000001'			; left part of digit 4
	retlw	b'01000010'			; left part of digit 5
	retlw	b'01000010'			; left part of digit 6
	retlw	b'00000011'			; left part of digit 7 
	retlw	b'01000011'			; left part of digit 8
	retlw	b'01000011'			; left part of digit 9
	retlw	b'01000011'			; right part of digit A
	retlw	b'01000000'			; right part of digit B
	retlw	b'01000010'			; right part of digit C
	retlw	b'00000001'			; right part of digit D
	retlw	b'01000010'			; right part of digit E
	retlw	b'01000010'			; right part of digit F

codeTr
	addwf	PCL, f
	retlw	b'11110000'			; right part of digit 0
	retlw	b'01000000'			; right part of digit 1
	retlw	b'11100000'			; right part of digit 2
	retlw	b'01100000'			; right part of digit 3
	retlw	b'01010000'			; right part of digit 4
	retlw	b'00110000'			; right part of digit 5
	retlw	b'10110000'			; right part of digit 6
	retlw	b'01100000'			; right part of digit 7
	retlw	b'11110000'			; right part of digit 8
	retlw	b'01110000'			; right part of digit 9
 	retlw	b'11110000'			; right part of digit A
	retlw	b'10010000'			; right part of digit B
	retlw	b'10110000'			; right part of digit C
	retlw	b'11000000'			; right part of digit D
	retlw	b'10110000'			; right part of digit E
	retlw	b'10110000'			; right part of digit F

codeTl
	addwf	PCL, f
	retlw	b'00011000'			; left part of digit 0
	retlw	b'00001000'			; left part of digit 1
	retlw	b'10010000'			; left part of digit 2
	retlw	b'10011000'			; left part of digit 3
	retlw	b'10001000'			; left part of digit 4
	retlw	b'10011000'			; left part of digit 5
	retlw	b'10011000'			; left part of digit 6
	retlw	b'00001000'			; left part of digit 7 
	retlw	b'10011000'			; left part of digit 8
	retlw	b'10011000'			; left part of digit 9
	retlw	b'10001000'			; right part of digit A
	retlw	b'10011000'			; right part of digit B
	retlw	b'00010000'			; right part of digit C
	retlw	b'10011000'			; right part of digit D
	retlw	b'10010000'			; right part of digit E
	retlw	b'10000000'			; right part of digit F

main
	clrf	PORTC
	bsf		PORTC, SCL
  	bsf    	STATUS, RP0        			; change to BANK 1
	movlw	7
	movwf	CMCON0						; comparators off
	clrf	ANSEL ^ 0x80				; all inputs digital
	clrf	OSCCON ^ 0x80				; oscillator configuration bits

    clrf	TRISA ^ 0x80				; STEP 1
  	clrf    TRISB ^ 0x80           
	movlw 	b'00000100'
	movwf	TRISC ^ 0x80
	bcf		STATUS, RP0
  	bsf		STATUS, RP1					; change to BANK 2

	bsf		LCDCON ^ 0x100, VLCDEN		; STEP 2: enable LCD bias voltage pins
	bsf		LCDCON ^ 0x100, CS1			; STEP 3: select clock source (lfintosc)	
	bcf		LCDCON ^ 0x100, CS0
	bcf		LCDCON ^ 0x100, LMUX1		; STEP 4: select multiplex mode (static)
	bcf		LCDCON ^ 0x100, LMUX0

	bcf		LCDPS, 	WFT					; STEP 5: select waveform type (A)
	bcf		LCDPS,	BIASMD				; STEP 6: select Bias mode
	bcf		LCDPS, 	LP3					; STEP 7: select refresh rate
	bcf		LCDPS, 	LP2	
	bsf		LCDPS,	LP1
	bcf		LCDPS,	LP0

	movlw	0xFF						; step 8: enable LCD segment lines
	movwf	LCDSE0
	movlw	b'11111011'
	movwf	LCDSE1
	clrf	LCDDATA0 ^ 0x100			; step 9: clear segment data registers
	clrf	LCDDATA1 ^ 0x100

	bsf		LCDCON ^ 0x100,	LCDEN		; step 10: turn on the LCD driver module
	bcf		LCDCON ^ 0x100, SLPEN		; enable LCD in sleep mode

	movlw	b'00001010'		
	movwf	WDTCON ^ 0x100				; watchdog timer prescaler 1:1024

	bcf		STATUS, RP1					; back to BANK 0

	; setup TCN75A temp resolution of 0.0625C and shutdown
setup
	call	start_I2C
	movlw	b'10010000'			; address byte
	movwf	dataIO
	call	write_I2C			; send address byte
	movlw	1				
	movwf	dataIO				; config pointer
	call	write_I2C
	movlw	b'01100001'
	movwf	dataIO				; temp resolution
	call	write_I2C
	call 	stop_I2C
	clrf	tempOld
	clrf	mode
; goto setup				

loop							; MAIN LOOP
	btfss	mode, 0				
	 goto	getTemp
	clrwdt
	call 	getTemp1			; mode 0: request new temp conversion
	incf	mode, f
	sleep
	nop	

getTemp
	clrwdt
	call	getTemp2			; get temp from sensor
	incf	mode, f
	movf	tempOld, w			
	subwf	tempC, w
	btfss	STATUS, Z			; old temp = new one?
	 call	displayTemp			; NO - update display
	sleep
	nop
	goto	loop

displayTemp
	clrf	displayCodes		
	clrf	displayCodes+1

	movlw	150
	subwf	tempC, w
	btfsc	STATUS, C
	 bsf	displayCodes+1, 5	; display hundreds

	call 	temp2BCD
	movwf	tens
	movwf	units
	swapf	tens, f
	movlw	0x0F
	andwf	tens, f
	andwf	units, f

	btfsc	displayCodes+1, 5
	 goto	dispTens			; display tens for temp >= 100F
	movf	tens, w
	btfsc	STATUS, Z			; do not display tens if it is 0
	 goto 	dispUnits			; and temp < 100

dispTens
	movf	tens, w				; displaying tens
	call 	codeTr
	iorwf	displayCodes, f
	movf	tens, w
	call	codeTl
	iorwf	displayCodes+1, f

dispUnits
	movf	units, w			; displaying units
	call 	codeUr
	iorwf	displayCodes, f
	movf	units, w
	call	codeUl
	iorwf	displayCodes+1, f

	bsf		STATUS, RP1
	movf	displayCodes+1, w	; update LCD
	movwf	LCDDATA1 ^ 0x100
	movf	displayCodes, w
	movwf	LCDDATA0 ^ 0x100
	bcf		STATUS, RP1			; back to BANK 0
	return

start_I2C						; start setup for I2C interface
	movlw	0x87				; setup FSR to point to TRISC
	movwf	FSR
	bsf		INDF, SDA			; pull high SDA and SCL
	bsf		PORTC, SCL
	nop							; delay slot
	bcf		PORTC, SDA
	bcf		INDF, SDA			; set data low
	goto	$+1					; wait for slave to detect it
	bcf		PORTC, SCL			; set clock low
	return

stop_I2C						; stop setup for I2C interface
	bcf		PORTC, SCL			; make sure that clock and data
	bcf		PORTC, SDA
	bcf		INDF, SDA			;  lines are low
	nop
	bsf		PORTC, SCL			; release clock line
	goto	$+1
	bsf		INDF, SDA			; release data line
	return

write_I2C						; write byte to I2C line	
	bcf		PORTC, SCL			; make sure that clock is low
;	bcf		INDF, SDA
;	clrf	err_i2c				; start with no error
	movlw	8
	movwf	cnt					; bits counter

w_loop
	bcf		PORTC, SDA			; start w. data bit low
	rlf		dataIO, f			; get the rightmost data bit
	btfss	STATUS, C
	 bcf	INDF, SDA			; now the data bit is on the line
	btfsc	STATUS, C
	 bsf	INDF, SDA
	nop
	bsf		PORTC, SCL			; raise clock up
	nop
	bcf		PORTC, SCL			; ... and low
	decfsz	cnt, f
	 goto	w_loop				; repeat this 8 times

	bsf		INDF, SDA			; check ACK from slave		
	goto	$+1					; let slave respond
	bsf		PORTC, SCL			; clock up
	nop
;	btfsc	PORTC, SDA			; check the ACK from slave
;	 incf	err_i2c, f			; no ACK (error)
	bcf		PORTC, SCL			; clock down
	return

read_I2C						; read byte from I2C line
;	bcf		PORTC, SDA
	bcf		PORTC, SCL			; make sure that clock is low			
	bsf		INDF, SDA			; configure data line for input
	movlw	8
	movwf	cnt					; bits counter	

r_loop
;	bcf		PORTC, SCL			; set clock low for long enough
;	goto	$+1
	bsf		PORTC, SCL			; clock up
	bcf		STATUS, C
	btfsc	PORTC, SDA
	 bsf	STATUS, C			; C = data bit
	bcf		PORTC, SCL			; clock down
	rlf		dataIO, f			; insert it into the data byte
	decfsz	cnt, f
	 goto	r_loop				; repeat this 8 times

	bcf		PORTC, SDA			; sending the ACK/NAK to slave
	bsf		INDF, SDA
	movf	ACK_NAK, f			; the NAK signal
	btfsc	STATUS, Z
	 bcf	INDF, SDA			; the ACK signal
	nop
	bsf		PORTC, SCL			; clock up
	goto	$+1
	bcf		PORTC, SCL			; ... and down
	nop
	bsf		INDF, SDA			; release the data line
	return

getTemp1						; request TEMP conversion
	call	start_I2C
	movlw	b'10010000'			; address byte
	movwf	dataIO
	call	write_I2C			; send address byte
	movlw	1				
	movwf	dataIO				; config pointer
	call	write_I2C
	movlw	b'11100001'			; request one-shot temp conv
	movwf	dataIO				; temp resolution
	call	write_I2C
	call 	stop_I2C
	return

getTemp2						; read TEMP from sensor
	call	start_I2C
	movlw	b'10010000'			; address byte/W
	movwf	dataIO
	call	write_I2C			; send address byte				
	clrf	dataIO				; TEMP register pointer
	call	write_I2C

	call	start_I2C
	movlw	b'10010001'			; address byte/R
	movwf	dataIO
	call	write_I2C			; send address byte
	clrf	ACK_NAK
	call	read_I2C			; get TEMP high order byte
	movf	dataIO, w
	movwf	tempC
	incf	ACK_NAK, f			; setup to send NAK signal
	call	read_I2C			; get TEMP low order byte
	movf	dataIO, w
	movwf	tempC+1
	call 	stop_I2C

	rlf		tempC+1, f			; shift a bit from the low order byte
	rlf		tempC, f            ; into the high one
	btfsc	STATUS, C			; negative tem ?
	 goto 	negative
	rlf		tempC+1, f
	rlf		tempC, f			; too high hemp (> 63.75C) ?
	btfsc	STATUS, C
	 goto	tooHot
 	return

negative
	clrf	tempC				; ignore negative temp, show it as 0
	return

tooHot
 	movlw	0xFF				; do not show temperatures higher
	movwf	tempC				; than 63.75C
	return

temp2BCD
	movf	tempC, w
	movwf	tempOld				; update old temp
	bsf		STATUS,	RP1			; switch to BANK 2
	movwf	EEADRL ^ 0x100 		; set address (in Wreg) to read
	bsf		STATUS, RP0			; switch to BANK 3
	bcf		EECON1 ^ 0x180, EEPGD
	bsf		EECON1 ^ 0x180, RD	; load byte form EEPROM
	bcf		STATUS, RP0			; back to BANK 2
	movf	EEDATL ^ 0x100, w	; move it to Wreg
	bcf		STATUS, RP1			; back to BANK 0
	return

 ORG 0x2100						; conversion table	
	dt 0x32, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35
	dt 0x36, 0x36, 0x37, 0x37, 0x37, 0x38, 0x38, 0x39
	dt 0x39, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x42
	dt 0x43, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46
	dt 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49, 0x50
	dt 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x53, 0x53
	dt 0x54, 0x54, 0x55, 0x55, 0x55, 0x56, 0x56, 0x57
	dt 0x57, 0x58, 0x58, 0x59, 0x59, 0x59, 0x60, 0x60
	dt 0x61, 0x61, 0x62, 0x62, 0x63, 0x63, 0x64, 0x64
	dt 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68
	dt 0x68, 0x68, 0x69, 0x69, 0x70, 0x70, 0x71, 0x71
	dt 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75
	dt 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78
	dt 0x79, 0x79, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82
	dt 0x82, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x86
	dt 0x86, 0x86, 0x87, 0x87, 0x88, 0x88, 0x89, 0x89
	dt 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x93
	dt 0x93, 0x94, 0x94, 0x95, 0x95, 0x95, 0x96, 0x96
	dt 0x97, 0x97, 0x98, 0x98, 0x99, 0x99, 0x00, 0x00
	dt 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04
	dt 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07
	dt 0x08, 0x08, 0x09, 0x09, 0x09, 0x10, 0x10, 0x11
	dt 0x11, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14, 0x14
	dt 0x15, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18
	dt 0x18, 0x19, 0x19, 0x20, 0x20, 0x21, 0x21, 0x22
	dt 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25
	dt 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x29
	dt 0x29, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32
	dt 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36
	dt 0x36, 0x37, 0x37, 0x38, 0x38, 0x39, 0x39, 0x40
	dt 0x40, 0x40, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43
	dt 0x44, 0x44, 0x45, 0x45, 0x45, 0x46, 0x46, 0x47

	end