I2C Sonar Range Finder

Joseph E. Bradshaw 5-24-2004

 

 

 

 

            In many embedded systems design, it becomes necessary to have the capability of discerning the distance of boundaries or objects without physical contact.  Ultrasound can be a very useful tool through which this task can be accomplished with significant accuracy.

 

            The Ultrasonic Range finder utilizes the following primary components.

1.      The Microchip PIC16F876 micro-controller

2.      An Analog Devices AD605 Single-Supply Variable Gain Amplifier

3.      40KHz Ultrasonic Transducers (Transmit and Receive)

4.      “Transducer Matched” ferrite core toroidal Transformer

 

 

BASIC SYSTEM OPERATION

 

            The Ultrasonic Range Finder is triggered to return a range sample by communication via I2C interface.  After receiving the PIC’s address (which is programmable), a hexadecimal 0x0d, or Carriage Return byte received will cause the module to take a range sample.  After triggering a short time period should be delayed to allow the PIC to record the return signal strength for every 2 inches sound travels at room temperature.

            When triggered, the PIC processor uses the PWM capability of the Capture/Compare module to generate 16 pulses of approximately 50% duty cycle to an FDV303NCT N-Channel Logic level MOSFET.  The micro-controller is then set up to delay 1ms to allow the Ultrasonic Receiver to settle from the Transmitted pulse.

            The FDV303NCT drives the primary coil of a transformer.  The transformers secondary coil is wound to match the impedance of the Ultrasonic Transducer at 40KHz providing maximum energy transfer efficiency at the Transducers resonant frequency of operation (see notes and calculations below).  A ferrite core toroid from Amidon and 30 AWG polythermaleze wire were used. The transformer was coated in clear Epoxy.  The primary transformer has only 2 turns and must be isolated from the power supply with a low resistance.  Anything from 2 to 10ohms worked fine, a 4.32ohm resistor was chosen.  A 4.7uF capacitor was placed across the primary coil to common/ground.  At 50% duty cycle or less, there’s plenty of time for the capacitor to recharge between pulses and provide the energy needed to drive the primary of the coil at full capacity.

            After the damping time of 1ms is finished, the processor starts an interrupt driven time delay that is equal to the time it takes sound to travel 2 inches (travel an inch, reflect off an object, travel back an inch) at room temperature 255 times and increment a register for inches.  The Receiver Transducers output is connected to an AD605 Amplifier wired for maximum adjustable gain (0dB-96.8dB).  The amplifiers output is taken through a voltage doubler circuit and rectified before entering the PIC16F876’s A2D converter.  Each returned pulse is averaged with the previous returned pulse to help cancel out noise and the largest pulses corresponding inches register value is recorded as the largest objects distance.

            After 255 returned samples have been compared, the inches value is converted from hexadecimal to BCD and ready to be read from the PIC16F876’s I2C Port.

 

 

NOTES AND CALCULATIONS

Fο = 1/(2π√LC)

If the capacitance of the transducer is typically 2.4nF (or measured 2.54nF) and the resonant frequency (Fo) is 40KHz, the transducer will have a capacitive-reactance of 1566ohms.  The value of the transformers secondary winding was calculated to have the same inductive reactance value of 1566ohms.  L is then calculated from the inductive reactance formula XL = 2 πFoL where XL and Fo are the known values.  L = 1566ohms/(2π40KHz) to give 6.23mH. The transformer’s primary coil should have only 1 or 2 turns to yield the maximum voltage gain due to the transformer turns ratio.

 

T1 Characteristics

Amidon Ferrite Toroid

FT-50-J Manganese-Zinc

# Turns - 1000√(6.23mH/AL)

AL = 2710mH/1000 turns from the FT-50-J’s specification

# Turns = 47.97, actual # of turns used was 50 to give the closest mH value of    6.25mH.  30AWG polythermaleze wire was used to wind the transformer.

 

 

 

 

 

 

            The Sonar triggering from the received I2C 0x0d byte is shown on SDA (I2C data line) and SCL (O2C clock line).  Channel 2 shows the 16 pulses at 40KHz being transmitted at the gate of the FDV303 MOSFET.  Channel 1 shows the rectified amplifier output at the input of the PIC’s analog to digital converter.  After approximately 15ms the result is read back via the I2C port.  

CODE EXAMPLE

isr

            movwf              W_TEMP                    ;Save current W and Status register contents

            swapf               STATUS, W

            bcf                   STATUS, RP0

            movwf              STATUS_TEMP

 

            banksel PIR1

            btfss                 PIR1, SSPIF    ;Did I2C Byte cause Interrupt?

            goto                 TMR0_int

            call                   SSP_Handler

            banksel PIR1

            bcf                   PIR1, SSPIF

            goto                 exit_isr

TMR0_int

;           banksel TMR0              ;Yeilds an interrupt time of ...

;           movf                 TMR0_val, W

            movlw              76

            movwf              TMR0

 

            banksel INTCON

            bcf                   INTCON, T0IF           ;Clear the Timer 0 interrupt flag

            banksel STATUS                     

            movf                 last_str, W        ;Move last_str register value to W

            addwf               new_str, F        ;Add last sample and new sample, then divide

            rrf                     new_str, F        ; by two to attain the average

 

            movf                 max_str, W      ;Load max_str into W

            subwf               new_str, W      ;Subtract avg_str from max_str, carry will be

                                                ; set if new averaged value is greater

                                                ; then previous largest signals value.

            btfss                 STATUS, C     ;If subtractions result resulted in a negative

                                                ; number, the new value is greater

            goto                 no_new_value  ;In result is not negative, the new value is

                                                ; not greater

record_new_value

            movf                 inches, W         ;Move current inches into W

            movwf              targ_dist           ;Record current inches to targ_distance

            movf                 new_str, W      ;Move new_str register value to W

            movwf              max_str                        ;Record the new_str register value as the

                                                ; maximum strength signal received

 

no_new_value                          ;This is done regardless if new sample was

                                                ; greater or not

            movf                 new_str, W      ;Move new_str into W

            movwf              last_str ;Move W into the last_str register

            incf                   inches, F           ;Increment the inches register

exit_isr

            banksel STATUS                      ;Restore Status and W register contents

            swapf               STATUS_TEMP, W    ; to how they were before interrupt

            movwf              STATUS

            swapf               W_TEMP, F

            swapf               W_TEMP, W

 

            retfie                             ;Return from the interrupt

;===============================================================

SSP_Handler

            banksel PIR1

            bcf                   PIR1, SSPIF

            banksel SSPSTAT

            btfss                 SSPSTAT, 2    ;R_W, skip next if read command was received

            goto                 slave_reception

slave_transmission

            banksel FSR

            movlw              0x73                            ;Have FSR point to the hund register

            movwf              FSR

 

            movf                 cnt, W                          ;Move current count to W

            addwf               FSR, F                         ;Add cnt offset to FSR

           

            movf                 INDF, W                                 ;Read contents of current FSR

            call                   WriteI2C                      ;Write to SSPBUF

            banksel cnt

            incf                   cnt, F                           ;Increment counter

 

            movlw  4

            subwf               cnt, W                          ;Subtract 4 from cnt

 

            banksel STATUS

            btfsc                 STATUS, Z                 ;If zero register is set then cnt is 4

            clrf                   cnt                                            ;clear cnt register

            goto                 end_ssp

                       

slave_reception

            banksel SSPBUF

            call                   ReadI2C                                  ;Get I2C Data

            movwf              i2c_rec_buf                  ;Move I2C byte to incoming buffer

           

            movlw              '\r';                               ;If '\r' (CR) was byte received by PIC, set the ;Start Sonar Flag

            subwf               i2c_rec_buf, W

           

            banksel STATUS

            btfss                 STATUS, Z

            goto                 end_ssp

            banksel son_flag

            bsf                    son_flag, 0                    ;If received byte was a CR '\r', set flag 0                      

            banksel PIE1

            bsf                    PIE1, 3                        ;Re-Enable SSP Interrupt

end_ssp

            banksel SSPCON

            bcf                   SSPCON, SSPOV      ;Clear Overflow bit

 

            return  

;----------------------------------------------------------------------

WriteI2C

            banksel SSPSTAT

            btfsc                 SSPSTAT, BF ; Is the buffer full?

            goto                 WriteI2C          ; Yes, keep waiting

            banksel SSPCON                     ; No, continue

DoI2CWrite

            bcf                   SSPCON, WCOL       ; Clear the WCOL flag

            movwf              SSPBUF                      ; Write the byte in WREG

            btfsc                 SSPCON, WCOL       ; Was there a write collision?

            goto                 DoI2CWrite

            bsf                    SSPCON, CKP           ; Release the clock

            return

;-----------------------------------------------------------------------

ReadI2C

            banksel SSPBUF

            movf                 SSPBUF, W    ; Get the byte and put it in WREG

            return

;-----------------------------------------------------------------------

            end