;**************************************************************************** ;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