Connecting Multiple SRF08 Sonar Modules to the BX-24 

Introduction
The SRF08 modules use the I2C bus for communication. This example shows how to connect two SRF08's to the BX-24, however it is expandable to up 16 SRF08's on the I2C bus. The SDA (data) and SCL (clock) lines are connected to pins 13 and 14 on the BX-24. The BX-24 does not have I2C communication, so the example provided here uses a combination of bit bashing and the SHIFTIN and SHIFTOUT commands instead.
The BX-24 internal 5v regulator is not suitable for powering much external circuitry. I therefore recommend you use a separate 5v regulator as shown below..

Circuit Schematic for connecting two SRF08 Sonar Modules to the BX-24

The schematic above shows 1k8 pull-up resistors on the SCL and SDA lines to Vdd. This is for good noise immunity, however any value up to 4k7 should be OK.

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 program below will do this. Make sure you only have one SRF08 connected when you do this. You only have to change the SRF08_NEW_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 SRF08_NEW_ADDRESS to read;

Const SRF08_NEW_ADDRESS As Byte = $Hf2          ' Place new address for SRF08 here

Now download the program to the BX-24, you will see rapid brief flashes on the Red Led on the SRF08 indicating that the change of address was successful. If you set your Monitor port on the PC, you will see the LDR and first range displayed on screen. It is wise to make a note of the new address on the SRF08 itself. It is easy to forget which is which otherwise.
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.


'***********************************************************
'**                                                       **
'**          I2C Routines for the Basic BX-24             **
'**        to change the I2C address of the SRF08         **
'**                                                       **
'**           Copyright 2002 - Devantech Ltd              **
'**    Commercial use of this software is prohibited      **
'**    Private and educational use only is permitted      **
'**                                                       **
'**        Written by Gerald Coe - February 2002          **
'**                                                       **
'***********************************************************

Const SRF08_NEW_ADDRESS As Byte = &He0           ' 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

Const SCL As Byte = 14                           ' I2C clock - choose any pins you wish for SCL and SDA
Const SDA As Byte = 13                           ' I2C data

Const GB As Byte = 0                             ' I2C General Broadcast address
Const CmdReg As Byte = 0                         ' SRF08 command register
Const LdrReg As Byte = 1                         ' Address of Light Sensor Register in SRF08
Const RangeReg As Byte = 2                       ' Address of Range Register in SRF08
Const RangeCmd As Byte = 81                      ' Ranging command - 80 for inches, 81 for cm, 82 for uS

Dim I2cAck As Boolean                            ' Acknowledge flag

Sub Main()
Dim Ldr As Byte
Dim Range As New UnsignedInteger

    Call PutPin(SCL, bxOutputHigh)
    Call PutPin(SDA, bxOutputHigh)

    Call Delay(1.0)                              ' Delay just to be sure SRF08 is out of reset
    Call I2cByteWrite(GB, CmdReg, &Ha0)          ' 1st command in address change sequence
    Call I2cByteWrite(GB, CmdReg, &Haa)          ' 2nd command in address change sequence
    Call I2cByteWrite(GB, CmdReg, &Ha5)          ' 3rd command in address change sequence
    Call I2cByteWrite(GB, CmdReg, SRF08_NEW_ADDRESS) ' The new I2C address

' That's the address changed, now perform SRF08 Ranging in an endless loop at the new address
Do
    Call I2cByteWrite(SRF08_NEW_ADDRESS, CmdReg, RangeCmd) ' Start Ranging in Cm
    Call Delay(0.07)                                       ' 70mS wait for ranging to complete
    Ldr = I2cByteRead(SRF08_NEW_ADDRESS, LdrReg)           ' Read light sensor
    Range = I2cWordRead(SRF08_NEW_ADDRESS, RangeReg)       ' Read Range Register
    debug.Print "LDR = "; CStr(Ldr); ", Range = "; CStr(Range)
Loop
End Sub

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

' writes I2cData to I2cReg at I2cAddr
Sub I2cByteWrite(ByVal I2cAddr As Byte, ByVal I2cReg As Byte, ByVal I2cData As Byte)
    Call I2cStart()
    Call I2cOutByte(I2cAddr)                  ' send device address
    Call I2cOutByte(I2cReg)                   ' send register address
    Call I2cOutByte(I2cData)                  ' send the data
    Call I2cStop()
End Sub

Function I2CByteRead(ByVal I2cAddr As Byte, ByVal I2cReg As Byte) As Byte
    Call I2cStart()
    Call I2cOutByte(I2cAddr)                  ' send device address
    Call I2cOutByte(I2cReg)                   ' send register address
    Call I2cStart()                           ' repeated start
    I2cAddr = I2cAddr+1
    Call I2cOutByte(I2cAddr)                  ' send device address with read set
    I2cAck = False                            ' setup to send Nak
    I2cByteRead = I2cInByte()                 ' get data byte with Nak
    Call I2cStop()
End Function

Function I2CWordRead(ByVal I2cAddr As Byte, ByVal I2cReg As Byte) As UnsignedInteger
    Set I2CWordRead = New UnsignedInteger
    Call I2cStart()
    Call I2cOutByte(I2cAddr)                  ' send device address
    Call I2cOutByte(I2cReg)                   ' send register address
    Call I2cStart()                           ' repeated start
    I2cAddr = I2cAddr+1
    Call I2cOutByte(I2cAddr)                  ' send device address with read set
    I2cAck = True                             ' setup to send Ack
    I2cWordRead = CuInt(I2cInByte()*256)
    I2cAck = False                            ' setup to send Nak
    I2cWordRead = I2cWordRead + CuInt(I2cInByte())
    Call I2cStop()
End Function

Sub I2cOutByte(I2cData As Byte)
    Call ShiftOut(SDA, SCL, 8, I2cData)       ' shift data out
    Call PutPin(SDA, bxInputTristate)         ' turn SDA around
    Call PutPin(SCL, bxOutputHigh)            ' and clock in the ack' bit
    Call PutPin(SCL, bxOutputLow)
End Sub

Function I2cInByte() As Byte
    I2cInByte = ShiftIn(SDA, SCL, 8)
    If I2cAck=True Then
        Call PutPin(SDA, bxOutputLow)
    Else
        Call PutPin(SDA, bxOutputHigh)
    End If
    Call PutPin(SCL, bxOutputHigh)            ' clock out the ack' bit
    Call PutPin(SCL, bxOutputLow)
End Function

Sub I2cStart()                                ' I2C start bit sequence
    Call PutPin(SDA, bxOutputHigh)
    Call PutPin(SCL, bxOutputHigh)
    Call PutPin(SDA, bxOutputLow)
    Call PutPin(SCL, bxOutputLow)
End Sub

Sub I2cStop()                                 ' I2C stop bit sequence
    Call PutPin(SDA, bxOutputLow)
    Call PutPin(SCL, bxOutputHigh)
    Call PutPin(SDA, bxOutputHigh)
End Sub

 


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 the monitor port window on the PC .
The sample code below can be downloaded here.

'***********************************************************
'**                                                       **
'**            I2C Routines for the BX-24                 **
'**      to demonstrate the use of multiple SRF08's       **
'**                                                       **
'**            Copyright 2002 - Devantech Ltd             **
'**     Commercial use of this software is prohibited     **
'**     Private and educational use only is permitted     **
'**                                                       **
'**        Written by Gerald Coe - February 2002          **
'**                                                       **
'***********************************************************

Const SCL As Byte = 14                  ' I2C clock - choose any pins you wish for SCL and SDA
Const SDA As Byte = 13                  ' I2C data

Const CmdReg As Byte = 0                ' SRF08 command register
Const LdrReg As Byte = 1                ' Address of Light Sensor Register in SRF08
Const RangeReg As Byte = 2              ' Address of Range Register in SRF08
Const RangeCmd As Byte = 81             ' Ranging command - 80 for inches, 81 for cm, 82 for uS

' Note that SRF08's must have been previously set to these addresses
Const Sonar1 As Byte = &He0             ' 1st SRF08 at I2C address 0Xe0
Const Sonar2 As Byte = &He2             ' 2nd SRF08 at I2C address 0Xe2

Dim I2cAck As Boolean                   ' Acknowledge flag

Sub Main()
Dim Ldr1 As Byte
Dim Range1 As New UnsignedInteger
Dim Ldr2 As Byte
Dim Range2 As New UnsignedInteger

    Call PutPin(SCL, bxOutputHigh)
    Call PutPin(SDA, bxOutputHigh)

Do
' 1st SRF08 Ranger
    Call I2cByteWrite(Sonar1, CmdReg, RangeCmd) ' Start Ranging in Cm
    Call Delay(0.07)                            ' 70mS wait for ranging to complete
    Ldr1 = I2cByteRead(Sonar1, LdrReg)          ' Read light sensor
    Range1 = I2cWordRead(Sonar1, RangeReg)      ' Read Range Register

' 2nd SRF08 Ranger
    Call I2cByteWrite(Sonar2, CmdReg, RangeCmd) ' Start Ranging in Cm
    Call Delay(0.07)                            ' 70mS wait for ranging to complete
    Ldr2 = I2cByteRead(Sonar2, LdrReg)          ' Read light sensor
    Range2 = I2cWordRead(Sonar2, RangeReg)      ' Read Range Register

    debug.Print "LDR1 = "; CStr(Ldr1); ", Range1 = "; CStr(Range1); _
               " LDR2 = "; CStr(Ldr2); ", Range2 = "; CStr(Range2)
Loop
End Sub

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

' writes I2cData to I2cReg at I2cAddr
    Sub I2cByteWrite(ByVal I2cAddr As Byte, ByVal I2cReg As Byte, ByVal I2cData As Byte)
    Call I2cStart()
    Call I2cOutByte(I2cAddr)                   ' send device address
    Call I2cOutByte(I2cReg)                    ' send register address
    Call I2cOutByte(I2cData)                   ' send the data
    Call I2cStop()
End Sub

Function I2CByteRead(ByVal I2cAddr As Byte, ByVal I2cReg As Byte) As Byte
    Call I2cStart()
    Call I2cOutByte(I2cAddr)                   ' send device address
    Call I2cOutByte(I2cReg)                    ' send register address
    Call I2cStart()                            ' repeated start
    I2cAddr = I2cAddr+1
    Call I2cOutByte(I2cAddr)                   ' send device address with read set
    I2cAck = False                             ' setup to send Nak
    I2cByteRead = I2cInByte()                  ' get data byte with Nak
    Call I2cStop()
End Function

Function I2CWordRead(ByVal I2cAddr As Byte, ByVal I2cReg As Byte) As UnsignedInteger
    Set I2CWordRead = New UnsignedInteger
    Call I2cStart()
    Call I2cOutByte(I2cAddr)                   ' send device address
    Call I2cOutByte(I2cReg)                    ' send register address
    Call I2cStart()                            ' repeated start
    I2cAddr = I2cAddr+1
    Call I2cOutByte(I2cAddr)                   ' send device address with read set
    I2cAck = True                              ' setup to send Ack
    I2cWordRead = CuInt(I2cInByte()*256)
    I2cAck = False                             ' setup to send Nak
    I2cWordRead = I2cWordRead + CuInt(I2cInByte())
    Call I2cStop()
End Function

Sub I2cOutByte(I2cData As Byte)
    Call ShiftOut(SDA, SCL, 8, I2cData)        ' shift data out
    Call PutPin(SDA, bxInputTristate)          ' turn SDA around
    Call PutPin(SCL, bxOutputHigh)             ' and clock in the ack' bit
    Call PutPin(SCL, bxOutputLow)
End Sub

Function I2cInByte() As Byte
    I2cInByte = ShiftIn(SDA, SCL, 8)
    If I2cAck=True Then
        Call PutPin(SDA, bxOutputLow)
    Else
        Call PutPin(SDA, bxOutputHigh)
    End If
    Call PutPin(SCL, bxOutputHigh)             ' clock out the ack' bit
    Call PutPin(SCL, bxOutputLow)
End Function

Sub I2cStart()                                 ' I2C start bit sequence
    Call PutPin(SDA, bxOutputHigh)
    Call PutPin(SCL, bxOutputHigh)
    Call PutPin(SDA, bxOutputLow)
    Call PutPin(SCL, bxOutputLow)
End Sub

Sub I2cStop()                                  ' I2C stop bit sequence
    Call PutPin(SDA, bxOutputLow)
    Call PutPin(SCL, bxOutputHigh)
    Call PutPin(SDA, bxOutputHigh)
End Sub

You can find more information on the SRF08 here