;****************************************************************************
;Dbt_light_meter
;Dbt reads LDR values to 10-bit resolution, scales to a voltage reading,
;converts to 4 digits of BCD, and displays on Hand Controller LCD.
;Rear LDR is scaled to be a true millivolt reading, displayed to tens of mV
;Requires Hand Controller loaded with corresponding program.
;Handshaking is not implemented between I2C Master & Slave, hence delays are 
;used to ensure writing is complete	before next byte is sent to controller.
;TJW 19.7.05											Tested 20.7.05
;***************************************************************************
;Clock is 4MHz
;
	list 	p=16F873A
	#include p16f873A.inc
;
;Set Configuration Word: crystal oscillator HS, WDT off, 
;     power-up timer on, code protect off, LV Program off.
	__CONFIG _HS_OSC & _WDT_OFF & _PWRTE_ON & _LVP_OFF
;
;Specify RAM
	cblock 20
delcntr1    	;used in delay5 & delayADC SRs
delcntr2    
ldr_rt_hi   	;stores for ldr values, read thru ADC
ldr_rt_lo   
ldr_left_hi 
ldr_left_lo 
ldr_rear_hi 
ldr_rear_lo 
temp	     	;a temp location, to be used only in consecutive instructions
I2C_RX_word 	;holds most recent I2C word recd
I2C_add	 	  	;holds address used in I2C message
I2C_TX_word 	;holds word to be transmitted on I2C	
;for Binary to BCD routine
R0 				; output bytes 10k’s digits
R1 				; 1k’s, 100’s digits
R2 				; 10’s, 1’s digits
TEMPL 			; input bytes (2 byte binary)
TEMPH
COUNT 			; internal variable in Bin2BCD16
;for 16x16 multiply routine
AARGB0
AARGB1
AARGB2
AARGB3
TEMPB0
TEMPB1
BARGB0
BARGB1
loopcount
		endc
;Specify some port bits
;For Port A
mot_en_rt 	equ	2
mot_en_left	equ	5

;For Port B
sounder		equ	1	;piezo electric sounder
us_rt		equ 6	;right microswitch
us_left		equ 7	;left microswitch

;For PortC
mot_left 	equ 1	;left motor direction bit, 1=forward
mot_rt 		equ 2	;right motor direction bit
led_rt		equ 5	;diagnostic led
led_left	equ 6	;diagnostic led
mode		equ	7	;mode switch

	org 00
;Initialise
	bcf		status,rp1
	bsf		status,rp0 	;select memory bank 1
	movlw	B'00001011'	;set port A bits according to their function,
	movwf	trisa		   ;ADC channels set as inputs
	movlw	B'11001000'
	movwf	trisb		;also port B bits
	movlw	B'10011000'	;set port C bits, I2C bits are both set as ip
	movwf	trisc
	movlw	B'10000100' ;select port A bits 0,1,3 for analog input
	movwf	adcon1		   ;right justify result
	movlw	09 		;set up I2C for 100kbps baud rate
	movwf	sspadd
;Initialise SFRs in Bank 0
	bcf		status,rp0	;select bank 0
	movlw	B'00101000'	;SSPCON1:MSSP on, I2C Master 
	movwf	sspcon
	movlw	B'01000001'	;set up ADC: clock Fosc/8, switch ADC on but not running,
	movwf	adcon0		;input channel selection currently irrelevant
;
;Switch all outputs off
	movlw 00
	movwf porta
	movwf portb
	movwf portc
;diagnostic, flash leds
	bsf portc,6
	bsf portc,5
	call delay500
	bcf portc,6
	bcf portc,5
	call delay500
;Read mode switch to determine Derbot operating mode
	btfsc	portc,mode
	goto	sw_move
;***********************************
;The “main” program loop starts here
;***********************************
;read and store ldrs
main_loop movlw B'01000001' ;select channel 0 as input (left front ldr)
	movwf	adcon0
	call 	delay20u	;acquisition time 
	bsf		adcon0,go	;start conversion
 	btfsc	adcon0,go_done ;wait for conversion to complete
	goto	$-1
	movf	adresh,0	;read and store ADC output data, high byte
	movwf	ldr_left_hi
	bsf		status,rp0
	movf	adresl,0    ;read and store ADC output data, low byte
	bcf		status,rp0
	movwf	ldr_left_lo
;select channel 1 (right ldr)
	movlw   B'01001001' 
	movwf	adcon0		;select channel 1 as input (right front ldr)
	call 	delay20u
	bsf		adcon0,go	;start conversion
	btfsc	adcon0,go_done ;wait for conversion to complete
	goto	$-1
	movf	adresh,0
	movwf	ldr_rt_hi
	bsf		status,rp0
	movf	adresl,0
	bcf		status,rp0
	movwf	ldr_rt_lo
;select channel 3 (rear ldr)
	movlw   B'01011001' 
	movwf	adcon0
	call 	delay20u
	bsf		adcon0,go_done	;start conversion
	btfsc	adcon0,go_done ;wait for conversion to complete
	goto	$-1
	movf	adresh,0
	movwf	ldr_rear_hi	
	bsf		status,rp0
	movf	adresl,0
	bcf		status,rp0
	movwf	ldr_rear_lo
;	
;convert front left to BCD and send
	movf	ldr_left_hi,0
	andlw	B'00000011'	;suppress anything in unused bits
	movwf	temph
	movf	ldr_left_lo,0
	movwf	templ
	call 	Bin2BCD16
	call 	four_dig_disp
;convert front right to BCD and send
	movf	ldr_rt_hi,0
	andlw	B'00000011'	;suppress anything in unused bits
	movwf	temph
	movf	ldr_rt_lo,0
	movwf	templ
	call 	Bin2BCD16
	call 	four_dig_disp
;send spacers
	movlw	0a4			;this is slave address, R/W is write
	movwf	I2C_add
	call    I2C_send_add
	movlw	' '
	movwf	I2C_TX_word ;send the character	
	call	I2C_send_word
	call delay1				;///account for line feed
	call delay1
	call delay1	
	call delay1
	call	I2C_send_word
	call 	I2C_send_stop
	bcf		status,rp0
	call delay1	
	call delay1
;scale rear
	movf	ldr_rear_hi,0	 ;get higher byte of ADC conversion result
	movwf	aargb0		 ;this is multiplier higher byte
	movf	ldr_rear_lo,0
	movwf	aargb1		;this is multiplier lower byte
	movlw	04		 	;higher byte of scaling factor
	movwf	bargb0
	movlw	0e2		 	;lower byte of scaling factor
	movwf	bargb1
	call  	mult16x16	;call the multiply subroutine
	movf	aargb1,0	;discard highest and lowest bytes
	movwf	temph		;second highest byte for BCD conversion
	movf	aargb2,0	;third highest byte for BCD conversion
	movwf	templ
	call 	Bin2BCD16	;call Binary to BCD conversion subroutine
	call 	four_dig_disp ;call subroutine which sends BCD bytes to display

;send spacers
	movlw	0a4			;this is slave address, R/W is write
	movwf	I2C_add
	call    I2C_send_add
	movlw	' '
	movwf	I2C_TX_word ;send the character	
	call	I2C_send_word
	call 	delay1	
	call 	delay1
	call	I2C_send_word
	call 	I2C_send_stop
	bcf		status,rp0
	call 	delay1	
	call 	delay1
;
	call 	delay500
	call 	delay500
	call 	delay500
	call 	delay500
	goto 	main_loop
;
;*************************************
;move microswitch states to diag leds
;*************************************
sw_move bcf portc,led_left	;preclear left led
	btfss 	portb,us_left
	bsf		portc,led_left	;but set it if button pressed
;
	bcf		portc,led_rt	;preclear port C, bit 5
	btfss 	portb,us_rt
	bsf		portc,led_rt	;but set it if button pressed
	goto	sw_move
	
;**********************************************
;SUBROUTINES
;**********************************************
;sends BCD digits to LCD 
four_dig_disp
;Start I2C message
	movlw	0a4			;this is slave address, R/W is write
	movwf	I2C_add
	call    I2C_send_add
;send ms digit	
	swapf	R1,0
	andlw	B'00001111'	;suppress other nibble
	iorlw	30			;turn to ASCII
	movwf	I2C_TX_word ;send the character	
	call	I2C_send_word
	call 	delay1	
	call 	delay1
	call 	delay1	;lcd line feed may have occurred here, give extra delay	
	call 	delay1
;send second digit
	movf	R1,0
	andlw	B'00001111'	;suppress other nibble
	iorlw	30			;turn to ASCII
	movwf	I2C_TX_word ;send the character	
	call	I2C_send_word
	call 	delay1	
	call 	delay1
;send middle digit
	swapf	R2,0	;swap the nibbles
	andlw	B'00001111'	;suppress other nibble
	iorlw	30			;turn to ASCII
	movwf	I2C_TX_word ;send the character	
	call	I2C_send_word
	call 	delay1	
	call 	delay1
;send ls digit
	movf	R2,0	;
	andlw	B'00001111'	;suppress other nibble
	iorlw	30			;turn to ASCII
	movwf	I2C_TX_word ;send the character	
	call	I2C_send_word
	call 	delay1	
	call 	delay1
;	movlw ' ' 		;send a space
;	movwf	I2C_TX_word ;send the character	
;	call	I2C_send_word
	call 	I2C_send_stop
	bcf		status,rp0
	call 	delay1	
	call 	delay1
	return
;
;initiates I2C message, by sending the word found in I2C_add, which 
;must include R/W bit.
;Waits for all acknowledgement and completion states.
I2C_send_add
	bsf		status,rp0
	bsf		sspcon2,sen	;force start bit
	btfsc	sspcon2,sen	;check for its completion
	goto	$-1
	bcf		status,rp0
	movf	I2C_add,0	;load address and data dirn bit
	movwf	sspbuf		;and send 
	bcf		pir1,sspif	;will test this soon
	bsf		status,rp0
	btfsc 	sspstat,bf ;test for write complete
	goto	$-1
	btfsc 	sspcon2,ackstat	;wait for 0 acknowledge bit 
	goto 	$-1
	bcf		status,rp0
	btfss	pir1,sspif ;test for int flag to show completion
	goto	$-1
	bcf		pir1,sspif
	return
;
;Sends word on I2C bus, and awaits acknowledgement
I2C_send_word bcf status,rp0
	movf	I2C_TX_word,0	;get the word	
	movwf	sspbuf			;this starts the transfer
	bsf		status,rp0
	btfsc 	sspstat,r_w 	;test for write complete
	goto	$-1
	btfsc 	sspcon2,ackstat	;wait for 0 acknowledge bit 
	goto 	$-1
	bcf status,rp0
	return
;
;***************************************************************************
; Bin2BCD16 - Converts a 16-bit binary number in TEMPH:TEMPL into a 3 byte 
; packed BCD number in R0:R1:R2. R0 holds the 10 thousands digit, R1 holds
; the hundreds and thousands digits, R2 holds the ones and tens digits.
;From Microchip Application Note AN220.
;***************************************************************************
; Inputs: TEMPH, TEMPL (16-bit binary number)
; Outputs: R0, R1, R2 (5 digit BCD number)
; Used: COUNT
Bin2BCD16
; Initialize variables
	bcf STATUS,C 	;clear carry bit
	movlw D'16'
	movwf COUNT 	;init bit counter
	clrf R0 		;clear output
	clrf R1 		;clear output
	clrf R2 		;clear output
Loop16a2 rlf TEMPL,F ;mult by 2, shift MSb to TEMPH
	rlf TEMPH,F 	;mult by 2, shift MSb to R2
	rlf R2,F 		;mult by 2, shift MSb to R1
	rlf R1,F 		;mult by 2, shift MSb to R0
	rlf R0,F 		;mult by 2, shift MSb to Carry
	decfsz COUNT,F 	;decrement bit counter
	goto AdjDec2
	return
AdjDec2	movlw R2
	movwf FSR 		;point to R2
	call AdjBCD2
	movlw R1
	movwf FSR 		;point to R1
	call AdjBCD2
	movlw R0
	movwf FSR 		;point to R0
	call AdjBCD2
 	goto Loop16a2
;
AdjBCD2
	movlw 3
	addwf INDF,W 	;W = 3 + Rn
	movwf TEMP 		;TEMP = 3+Rn
	btfsc TEMP,3 
	movwf INDF 		;Rn=TEMP
	movlw 30 		;decimal adjust?
	addwf INDF,W 	;W=30+Rn
	movwf TEMP 		;TEMP=30+Rn
	btfsc TEMP,7
	movwf INDF 		;Rn=TEMP
	return
;
;Sends I2C stop bit, and awaits completion
I2C_send_stop bsf status,rp0
	bsf		sspcon2,pen		;force stop bit. 
	btfss	sspstat,p 		;test for stop bit completion
	goto	$-1

;introduces delay of 20us approx
delay20u  movlw 	D'5'	;5 cycles called, 
;			each taking 3us, plus call, return (2 ea), and 2 move insts
;			less one cycle lost when last goto is hopped
        movwf  	delcntr1
dela    decfsz 	delcntr1,1 ;3 inst cycles in this loop, ie 3us
        goto 	dela
        return
;
;introduces delay of 1ms approx
delay1  movlw 	D'250'	;250 cycles called, 
;			each taking 4us
        movwf  	delcntr1
del1    nop	;4 inst cycles in this loop, ie 4us
        decfsz 	delcntr1,1
        goto 	del1
        return
;
;200ms delay (approx)	;200 calls to delay1
delay200  movlw D'200'
        movwf  	delcntr2
del2    call 	delay1
        decfsz  delcntr2,1
        goto 	del2
        return  
;
;500ms delay (approx)	;500 calls to delay1
delay500  movlw D'250'
        movwf  	delcntr2
del5    call 	delay1
		call 	delay1
        decfsz  delcntr2,1
        goto 	del5
        return  

;*******************************************************************
;16x16 Bit Unsigned Fixed Point Multiply 16x16 -> 32
;Input: 16 bit unsigned fixed point multiplicand in AARGB0:AARGB1
; 16 bit unsigned fixed point multiplier in BARGB0:BARGB1
; Output: 32 bit product in AARGB0:AARGB1:AARGB2:AARGB3
; Result: AARG <-- AARG x BARG
;*******************************************************************
Mult16x16 
 	 CLRF AARGB2 ; clear partial product
 	CLRF AARGB3
 	 MOVF AARGB0,W
 	 MOVWF TEMPB0
 	 MOVF AARGB1,W
 	 MOVWF TEMPB1
 	 MOVLW 0x08
 	 MOVWF LOOPCOUNT
LOOPUM1616A
 	RRF BARGB1, F
 	BTFSC STATUS,C
 	GOTO ALUM1616NAP
 	 DECFSZ LOOPCOUNT, F
 	 GOTO LOOPUM1616A
	MOVWF LOOPCOUNT
LOOPUM1616B
 	RRF BARGB0, F
 	 BTFSC STATUS,C
 	GOTO BLUM1616NAP
 	 DECFSZ LOOPCOUNT, F
 	 GOTO LOOPUM1616B
 	CLRF AARGB0
 	CLRF AARGB1
 	 RETLW 0x00
BLUM1616NAP
 	BCF STATUS,C
 	GOTO BLUM1616NA
ALUM1616NAP
 	BCF STATUS,C
 	GOTO ALUM1616NA
ALOOPUM1616
 	RRF BARGB1, F
 	 BTFSS STATUS,C
 	 GOTO ALUM1616NA
 	 MOVF TEMPB1,W
 	ADDWF AARGB1, F
 	 MOVF TEMPB0,W
 	 BTFSC STATUS,C
 	INCFSZ TEMPB0,W
 	ADDWF AARGB0, F
ALUM1616NA
 	 RRF AARGB0, F
 	 RRF AARGB1, F
 	RRF AARGB2, F
 	DECFSZ LOOPCOUNT, F
 	GOTO ALOOPUM1616
  	 MOVLW 0x08
 	MOVWF LOOPCOUNT
BLOOPUM1616
 	 RRF BARGB0, F
 	 BTFSS STATUS,C
 	 GOTO BLUM1616NA
 	 MOVF TEMPB1,W
 	 ADDWF AARGB1, F
 	MOVF TEMPB0,W
 	 BTFSC STATUS,C
 	INCFSZ TEMPB0,W
 	 ADDWF AARGB0, F
BLUM1616NA
 	 RRF AARGB0, F
 	RRF AARGB1, F
 	RRF AARGB2, F
 	RRF AARGB3, F
 	DECFSZ LOOPCOUNT, F
 	GOTO BLOOPUM1616
 	Return
	
	end
