Connecting Multiple SRF08 Sonar Modules to the BS2 

Introduction
The SRF08 modules use the I2C bus for communication. This example shows how to connect two SRF08's to the BS2, however it is expandable to up 16 SRF08's on the I2C bus. The SDA (data) and SCL (clock) lines are connected to pins P8 and P9 on the BS2. These are the pins used by the BS2p for the I2CIN and I2COUT commands. 

If you are using BS2p firmware release Rev C or later, then you can use the I2CIN and I2COUT commands to control the SRF08's. Example. 

The example below should be used for earlier revisions of the BS2p as well as the BS2, BS2e and BS2sx. This example uses a combination of bit bashing and the SHIFTIN and SHIFTOUT commands. It has been tested with the BS2 and BS2p.
The BS2 internal 5v regulator is not suitable for powering much external circuitry. I therefore recommend you use a separate 5v regulator.

Circuit Schematic for connecting two SRF08 Sonar Modules to the Basic Stamp BS2

The schematic above shows 4k7 pull-up resistors on the SCL and SDA lines to Vdd, as recommended by Parallax. 
For greater noise immunity, I recommend pulling up to the SRF08's 5v supply instead (so as not to place any more load on the BS2) and using 1k8 resistors.

Changing the SRF08 I2C Address
Before you can use the SRF08's you will need to re-program their I2C addresses from the default address of 0xE0 they are supplied with. The simple program below will do this. Make sure you only have one SRF08 connected when you do this. You only have to change the NEW_SRF08_ADDRESS constant in the program below to the address you want. For example if you want the SRF08 to be at hex address 0xF2, then change NEW_SRF08_ADDRESS to read;

NEW_SRF08_ADDRESS con $f2          ' Place new address for SRF08 here

Now download the program to the BS2, you will see rapid brief flashes on the Red Led on the SRF08 indicating that the change of address was successful. It is wise to make a note of the new address on the SRF08 itself. 
To use the example code described later on this page, set one SRF08 to address 0xE0 and the other to 0xE2. The following program can be downloaded here.

'{$STAMP BS2}

'***********************************************************
'**                                                       **
'**            I2C Routines for the Basic Stamp           **
'**               to change address of SRF08              **
'**                                                       **
'**             Copyright 2002 - Devantech Ltd            **
'**     Commercial use of this software is prohibited     **
'**     Private and educational use only is permitted     **
'**                                                       **
'**        Written by Gerald Coe - January 2002           **
'**                                                       **
'**       This Code has been Tested on BS2 and BS2p       **
'**   It should work equally well on the BS2e and BS2sx   **
'**                                                       **
'***********************************************************

NEW_SRF08_ADDRESS con $e2          ' Place new address for SRF08 here
'available addresses are: e0, e2, e4, e6, e8, ea, ec, ee
'                         f0, f2, f4, f6, f8, fa, fc, fe

SCL con 9                          ' I2C clock
SDA con 8                          ' I2C data
SDAin var in8
SDAout var out8                    ' To change the pins used, alter these 5 lines
SDAdir var dir8                    ' The 4 SDA numbers must be the same, of course

loop var byte                      ' just a looping counter
I2cBuf var byte                    ' I2c read/write buffer
I2cAddr var byte                   ' Address of I2C device
I2cReg var byte                    ' Register number within I2C device
I2cData var word                   ' Data to read/write
I2cAck var bit                     ' Acknowledge bit

Main:

I2cAddr = 0                        ' use general broadcast address ($00) if don't know current SRF08 address
I2cReg = 0                         ' command register
I2cData = $a0                      ' 1st command in address change sequence
gosub I2cByteWrite
I2cData = $aa                      ' 2nd command in address change sequence
gosub I2cByteWrite
I2cData = $a5                      ' 3rd command in address change sequence
gosub I2cByteWrite
I2cData = NEW_SRF08_ADDRESS
gosub I2cByteWrite

endlessloop:
I2cAddr = NEW_SRF08_ADDRESS
I2cReg = 0
I2cData = 81                       ' one of the ranging commands
gosub I2cByteWrite
pause 70                           ' wait for ranging to complete
goto endlessloop

'--------------------------------------------------------------------------------------------
' I2C subroutines follow
'--------------------------------------------------------------------------------------------

I2cByteWrite:                      ' writes I2cData.lowbyte to I2cReg at I2cAddr
gosub I2cStart
I2cBuf = I2cAddr
gosub I2cOutByte                   ' send device address
I2cBuf = I2cReg
gosub I2cOutByte                   ' send register number
I2cBuf = I2cData.lowbyte
gosub I2cOutByte                   ' send the data
gosub I2cStop
return

I2cWordWrite:                      ' writes I2cData to I2cReg at I2cAddr
gosub I2cStart
I2cBuf = I2cAddr
gosub I2cOutByte                   ' send device address
I2cBuf = I2cReg
gosub I2cOutByte                   ' send register number
I2cBuf = I2cData.highbyte
gosub I2cOutByte                   ' send the data - high byte
I2cBuf = I2cData.lowbyte
gosub I2cOutByte                   ' send the data - low byte
gosub I2cStop
return

I2CByteRead:
gosub I2cStart
I2cBuf = I2cAddr
gosub I2cOutByte                   ' send device address
I2cBuf = I2cReg
gosub I2cOutByte                   ' send register number
gosub I2cStart                     ' repeated start
I2cBuf = I2cAddr | 1
gosub I2cOutByte                   ' send device address (with read set)
I2cAck = 0                         ' send Nak
gosub I2cInByte
I2cData.lowbyte = I2cBuf           ' read the data
I2cData.highbyte = 0
gosub I2cStop
return

I2CWordRead:
gosub I2cStart
I2cBuf = I2cAddr
gosub I2cOutByte                   ' send device address
I2cBuf = I2cReg
gosub I2cOutByte                   ' send register number
gosub I2cStart                     ' repeated start
I2cBuf = I2cAddr | 1
I2cAck = 1                         ' send Ack
gosub I2cOutByte                   ' send device address (with read set)
gosub I2cInByte
I2cData.highbyte = I2cBuf          ' read the data
I2cAck = 0                         ' send Nak
gosub I2cInByte
I2cData.lowbyte = I2cBuf
gosub I2cStop
return

I2cOutByte:
shiftout SDA, SCL, MSBFIRST, [I2cBuf]
input SDA
high SCL                           ' clock in the ack' bit
low SCL
return

I2cInByte:
shiftin SDA, SCL, MSBPRE, [I2cBuf]
SDAout = 0
SDAdir = I2cAck
high SCL                           ' clock out the ack' bit
low SCL
input SDA
return

I2cStart                           ' I2C start bit sequence
high SDA
high SCL
low SDA
low SCL
return

I2cStop:                           ' I2C stop bit sequence
low SDA
high SCL
high SDA
return


Displaying Light Sensor and Range readings in a PC Debug window
 Now that you have your SRF08's re-programmed to their new I2C addresses (0xE0 and 0xE2) the following sample code will display the light sensor reading and the 1st range reading, for each SRF08 in a Debug window on the PC .
The sample code below can be downloaded here.

'{$STAMP BS2}

'***********************************************************
'**                                                       **
'**           I2C Routines for the Basic Stamp            **
'**       Controlling Two SRF08 Ultrasonic Rangers        **
'**                                                       **
'**           Copyright 2002 - Devantech Ltd              **
'**     Commercial use of this software is prohibited     **
'**     Private and educational use only is permitted     **
'**                                                       **
'**         Written by Gerald Coe - January 2002          **
'**                                                       **
'**      This Code has been Tested on BS2 and BS2p        **
'**   It should work equally well on the BS2e and BS2sx   **
'**                                                       **
'***********************************************************

SCL con 9                          ' I2C clock
SDA con 8                          ' I2C data
SDAin var in8
SDAout var out8                    ' To change the pins used, alter these 5 lines
SDAdir var dir8                    ' The 4 SDA numbers must be the same, of course

loop var byte                      ' just a looping counter
I2cBuf var byte                    ' I2c read/write buffer
I2cAddr var byte                   ' Address of I2C device
I2cReg var byte                    ' Register number within I2C device
I2cData var word                   ' Data to read/write
I2cAck var bit                     ' Acknowledge bit

Main:

' 1st SRF08 Ranger
I2cAddr = $e0
I2cReg = 0
I2cData = 81                       ' Ranging command - 80 for inches, 81 for cm, 82 for uS
gosub I2cByteWrite
pause 70                           ' wait for ranging to complete
I2cReg = 1                         ' address of light sensor register
gosub I2cByteRead
debug 2,0,0, "Light Sensor1 ", dec3 I2cData
I2cReg = 2                         ' address of first ranging result
gosub I2cWordRead
debug 2,0,1, "Range1 ", dec4 I2cData

' 2nd SRF08 Ranger
I2cAddr = $e2
I2cReg = 0
I2cData = 81                       ' Ranging command - 80 for inches, 81 for cm, 82 for uS
gosub I2cByteWrite
pause 70                           ' wait for ranging to complete
I2cReg = 1                         ' address of light sensor register
gosub I2cByteRead
debug 2,0,3, "Light Sensor2 ", dec3 I2cData
I2cReg = 2                         ' address of first ranging result
gosub I2cWordRead
debug 2,0,4, "Range2 ", dec4 I2cData

goto main

'--------------------------------------------------------------------------------------------
' I2C subroutines follow
'--------------------------------------------------------------------------------------------

I2cByteWrite:                      ' writes I2cData.lowbyte to I2cReg at I2cAddr
gosub I2cStart
I2cBuf = I2cAddr
gosub I2cOutByte                   ' send device address
I2cBuf = I2cReg
gosub I2cOutByte                   ' send register number
I2cBuf = I2cData.lowbyte
gosub I2cOutByte                   ' send the data
gosub I2cStop
return

I2cWordWrite:                      ' writes I2cData to I2cReg at I2cAddr
gosub I2cStart
I2cBuf = I2cAddr
gosub I2cOutByte                   ' send device address
I2cBuf = I2cReg
gosub I2cOutByte                   ' send register number
I2cBuf = I2cData.highbyte
gosub I2cOutByte                   ' send the data - high byte
I2cBuf = I2cData.lowbyte
gosub I2cOutByte                   ' send the data - low byte
gosub I2cStop
return

I2CByteRead:
gosub I2cStart
I2cBuf = I2cAddr
gosub I2cOutByte                   ' send device address
I2cBuf = I2cReg
gosub I2cOutByte                   ' send register number
gosub I2cStart                     ' repeated start
I2cBuf = I2cAddr | 1
gosub I2cOutByte                   ' send device address (with read set)
I2cAck = 0                         ' send Nak
gosub I2cInByte
I2cData.lowbyte = I2cBuf           ' read the data
I2cData.highbyte = 0
gosub I2cStop
return

I2CWordRead:
gosub I2cStart
I2cBuf = I2cAddr
gosub I2cOutByte                   ' send device address
I2cBuf = I2cReg
gosub I2cOutByte                   ' send register number
gosub I2cStart                     ' repeated start
I2cBuf = I2cAddr | 1
I2cAck = 1                         ' send Ack
gosub I2cOutByte                   ' send device address (with read set)
gosub I2cInByte
I2cData.highbyte = I2cBuf          ' read the data
I2cAck = 0                         ' send Nak
gosub I2cInByte
I2cData.lowbyte = I2cBuf
gosub I2cStop
return

I2cOutByte:
shiftout SDA, SCL, MSBFIRST, [I2cBuf]
input SDA
high SCL                           ' clock in the ack' bit
low SCL
return

I2cInByte:
shiftin SDA, SCL, MSBPRE, [I2cBuf]
SDAout = 0
SDAdir = I2cAck
high SCL                           ' clock out the ack' bit
low SCL
input SDA
return

I2cStart                           ' I2C start bit sequence
high SDA
high SCL
low SDA
low SCL
return

I2cStop:                            ' I2C stop bit sequence
low SDA
high SCL
high SDA
return