Read values from i2c sensors with the same address

arduino multiple i2c same address
multiple i2c devices with same address
multiple i2c devices arduino code
i2c address arduino
arduino multiple i2c busses
i2c sensors list
i2c address list
how are i2c addresses assigned

I have 4 SingleTact capacitive sensors each with the i2c address of 0x04. I want to find the average value of the sensors, in order to make a joystick. However I am unsure how to assign each sensor it's own address since they all have the same address as they are the same sensor. I have an initial code however this only works with one single sensor as it only has one single i2c address byte. I have wired together all the SDA and SCL line together using tutorials online and have included pull-up resistors.

#include <Wire.h>
#define initializetime 4
byte serialToPCBuffer[77];
byte serialToPCBufferIndex = 0;

int data[4];
int databuffer[4][initializetime] = {0,0,0,0,0,0,0,0,0,0,0,0};
int base[4] = {0,0,0,0};
int ArduinoToPCBuffer[4] = {1000,2000,3000,4000};
byte outgoingI2CBuffer[32];
unsigned long timeStamp_;

void setup() {
  int i;
  Wire.begin();
  //TWBR = 12;
  Serial.begin(57600);
  Serial.flush();
  initializeSensors();

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("PPS UK: SingleTact sensor value in PSI. \n(resembles PC executable display)");
  Serial.println("Refer manual for any other calculation.");
  Serial.println("----------------------------------------");  
}    

void loop(){
  byte i2cAddress = 0x04; // Slave address (SingleTact), default 0x04
  int data = readDataFromSensor(i2cAddress);
  Serial.print("I2C Sensor Data:");
  Serial.print(data);    
  Serial.print("\n");
  delay(100); // Change this if you are getting values too quickly 
}

int readDataFromSensor(int address)
{
  byte i = 0;
  byte i2cPacketLength = 6;
  byte outgoingI2CBuffer[3];
  byte incomingI2CBuffer[6];

  outgoingI2CBuffer[0] = 0x01;
  outgoingI2CBuffer[1] = 128;
  outgoingI2CBuffer[2] = i2cPacketLength;

  Wire.beginTransmission(address);
  Wire.write(outgoingI2CBuffer,3);
  byte error = Wire.endTransmission();
  if (error != 0) return -1;
  Wire.requestFrom(address,i2cPacketLength);

  int incomeCount =0;
  while(incomeCount < i2cPacketLength)
  {
    if(Wire.available())
    {
    incomingI2CBuffer[incomeCount] = Wire.read();
    incomeCount++;
    }
    else
    {
    delay(1);
    }
  }
  if(serialToPCBuffer[4] == 0x00 && serialToPCBuffer[5] == 0xFE)
  {
    serialToPCBuffer[5] = 0xFF;
  }

  int datafromi2c = serialToPCBuffer[4]*256+serialToPCBuffer[5]-base[address-5];

  if(datafromi2c<21)
    datafromi2c = 0;

  return datafromi2c;
}

void initializeSensors()
{
  for(int k = 0;k<4;k++)
  {
    databuffer[k][0] = readDataFromSensor(k+5);
    delay(10);
    databuffer[k][1] = readDataFromSensor(k+5);
    delay(10);
    databuffer[k][2] = readDataFromSensor(k+5);
    delay(10);
    databuffer[k][3] = readDataFromSensor(k+5);
    delay(10);
    base[k] = (databuffer[k][0] + databuffer[k][1] + databuffer[k][2] +     databuffer[k][3])/3;
  }
}

Thanks for any advice.

You should read the manual of this device, available here. It says, at the interface description, that

Multiple sensor interfaces may be connected to a single I2C bus. The bus address of individual sensor interfaces can be configured by writing desired address value (4 to 127) via the I2C interface to register address 0 with an I2C Write Operation. Change of individual sensor I2C addresses is supported by the PC and Arduino Example.

So you just have to

  1. plug the first sensor
  2. write an address (e.g. 0x41) to the register 0 of this device
  3. unplug the sensor
  4. repeat 1-2-3 for all the sensors using different addresses

Then each sensor will reply to the address you set.

Please note that

As the interface board will always respond to address 0x04 then this address must be considered reserved for SingleTact. Where multiple SingleTact interfaces are to be connected to the same I2C bus then address 0x04 must be considered invalid

So, even in this case, the RTFM advice is the most important one...

Multiple I2C sensors with the same address, Provide a link to that library. I guess it's easy to extend it to provide the I2C port. In your code you read the value but as you just doubled all the  Your mag_read_register function returns after it has read the first sensor. There's no way it can read the second sensor. You'll have to modify the function so that it returns one or both values in global variables instead of as the value of the function.

You can also use an I2C Multiplexer. They have their own I2C address and can enumerate the four sensors on their own buses (broadcast domains) so that it is possible to switch between them. Your programming will need to explicitly select each sensor in turn and keep track of which one it is reading. Once switched, I2C traffic just passes through to the selected device. This works best with a cluster of sensors in a star topology as you are running extra wiring.

I'm going to go further, and say you could even use relays to switch these in and out, or OR/NAND gates.

Read values from i2c sensors with the same address, I have 4 SingleTact capacitive sensors each with the i2c address of 0x04. I want to find the average value of the sensors, in order to make a joystick. However I  Wire.requestFrom(address, 1) command expects to receive 1 byte of data from the TC74 sensor. Wire.available() waits for data to be available on the I2C bus and when the data is received in a 8-bit value it is stored inside integer c with the Wire.read() function.

You need use the Kalman Filter

    #include "Wire.h"                      // i2c library
    #include "BMP085.h"                   // bmp085 library, download from url link (1)
    #include "Tone.h"                      // tone library, download from url link (3)
    #include "stdlib.h"                    // we need that to use dtostrf() and convert float to string
    #include "stdarg.h"

    #define UART_SPEED  9600
    short SPEAKER_PIN1 = 11;               // Speaker output -
    short SPEAKER_PIN2 = 12;               // Speaker output +
    short LED_PIN = 13;

    Tone speaker1, speaker2;
    BMP085   bmp085 = BMP085();            // BMP085 sensor

    const float SEA_LEVEL_PRESSURE = 101325;    // Pressure at sea level (Pa)
    const float KF_VAR_MEASUREMENT = 0.1;       // Variance of pressure measurement noise.
    const float KF_VAR_ACCEL = 0.75;             // Variance of pressure acceleration noise input.

    float CLIMB_TONE2_MULT;
    float SINK_TONE2_MULT;

    float   kf_x_abs,
            kf_x_vel,
            kf_p_abs_abs,
            kf_p_abs_vel,
            kf_p_vel_vel,
            kf_var_accel;

    #define VARIOS_LEN  5
    int varios[VARIOS_LEN];
    int varios_pos = 0, varios_sum = 0;

    void p(char *fmt, ... ){
        char tmp[128]; // resulting string limited to 128 chars
        va_list args;
        va_start (args, fmt );
        vsnprintf(tmp, 128, fmt, args);
        va_end (args);
        Serial.print(tmp);
    }

    void kf_reset(float abs_value, float vel_value) {
        kf_x_abs = abs_value;
        kf_x_vel = vel_value;
        kf_p_abs_abs = 1000000000;
        kf_p_abs_vel = 0;
        kf_p_vel_vel = KF_VAR_ACCEL;
        kf_var_accel = KF_VAR_ACCEL;

        varios_sum = 0;
        for (int i = 0; i < VARIOS_LEN; i++) varios[i] = 0;
        varios_pos = 0;
    }

    void setup() {
        Serial.begin(UART_SPEED);            // set up arduino serial port
        Wire.begin();                        // lets init i2c protocol
        speaker1.begin(SPEAKER_PIN1);        // piezo speaker output -
        speaker2.begin(SPEAKER_PIN2);        // piezo speaker output +
        digitalWrite(SPEAKER_PIN2, LOW);

        bmp085.init(MODE_ULTRA_HIGHRES, SEA_LEVEL_PRESSURE, false);

        kf_reset(SEA_LEVEL_PRESSURE, 0);

        CLIMB_TONE2_MULT = pow(2, 9/12);
        SINK_TONE2_MULT = pow(2, 1/12);

        welcome();      //everything is ready, play "welcome" sound
    }

    void welcome() {
        speaker1.play(300, 50);     // (note, duration)
        delay(100);
        speaker2.play(300, 50);     // (note, duration)
        delay(100);
        Serial.println("Vario is ready");
    }

    float pressure2altitude(float pressure) {
        return (float)44330 * (1 - pow(((float)(pressure)/SEA_LEVEL_PRESSURE), 0.190295));
    }

    float last_time = 0;
    void update_pressure() {
        long pressure;
        bmp085.calcTruePressure(&pressure);

        float time = millis();
        float dt = (time - last_time) / 1000;
        last_time = time;

        /* Kalman Filter code */
        kf_x_abs += kf_x_vel * dt;

        kf_p_abs_abs += (float)2 * dt * kf_p_abs_vel  +  dt * dt * kf_p_vel_vel  +  kf_var_accel * dt * dt * dt * dt / (float)4;
        kf_p_abs_vel +=                                       dt * kf_p_vel_vel  +  kf_var_accel * dt * dt * dt / (float)2;
        kf_p_vel_vel +=                                                          +  kf_var_accel * dt * dt;

        // Update state covariance. The last term mixes in acceleration noise.
        float y = pressure - kf_x_abs;                              // Innovation.
        float s_inv = 1.0 / (kf_p_abs_abs + KF_VAR_MEASUREMENT);    // Innovation precision.
        float k_abs = kf_p_abs_abs * s_inv;                         // Kalman gain
        float k_vel = kf_p_abs_vel * s_inv;

        // Update state estimate.
        kf_x_abs += k_abs * y;
        kf_x_vel += k_vel * y;

        // Update state covariance.
        kf_p_vel_vel -= kf_p_abs_vel * k_vel;
        kf_p_abs_vel -= kf_p_abs_vel * k_abs;
        kf_p_abs_abs -= kf_p_abs_abs * k_abs;
    }

    int avg_vario() {
        float altitude = pressure2altitude(kf_x_abs);
        int vario = (int)((altitude - pressure2altitude(kf_x_abs - kf_x_vel)) * 100);

        varios_sum += vario;
        varios_sum -= varios[varios_pos];
        varios[varios_pos] = vario;

        if (++varios_pos == VARIOS_LEN) varios_pos = 0;
        return varios_sum / VARIOS_LEN;
    }


    int CLIMB_RATE_START = 25,
        SINK_RATE_START  = -80;

    int loop_id = 0;
    unsigned long next_signal_time = 0;
    void loop() {
        update_pressure();
        int vario = avg_vario();

        unsigned long time = millis();
        if (time >= next_signal_time) {
            if (vario > CLIMB_RATE_START) {
                long beep_period = 350 - vario / 2;
                if (beep_period < 20) beep_period = 20;

                int silence_period = beep_period / 16;
                int tone = 1300 + vario;
                if (tone > 2300) tone = 2300;

                next_signal_time = time + beep_period + silence_period;
                speaker1.play(tone, beep_period);

                Serial.print("CLIMB  beep:");
                Serial.print(beep_period);
                Serial.print("    silence:");
                Serial.print(silence_period);
                Serial.print("    vario: ");
                Serial.println(vario);
            } else if (vario < SINK_RATE_START) {
    //            int beep_period = 350 * 50 / (-vario);
    //            int silence_period = beep_period / 5;
                int beep_period = 350 + vario / 2;
                if (beep_period < 20) beep_period = 20;
                int silence_period = beep_period / 16;
                int tone = 1000 + vario;
                if (tone < 300) tone = 300;

                next_signal_time = time + beep_period + silence_period;
                speaker1.play(tone, beep_period);     // (note, duration)

                Serial.print("SINK  beep:");
                Serial.print(beep_period);
                Serial.print("    silence:");
                Serial.print(silence_period);
                Serial.print("    vario: ");
                Serial.println(vario);
            }
        }

        loop_id++;
        if ((loop_id % 10) == 0) {
            Serial.print("vario: ");
            Serial.println(vario);
        }

        if ((loop_id % 10) == 0) {
            digitalWrite(LED_PIN, LOW);
        }
        if ((loop_id % 10) == 5) {
            digitalWrite(LED_PIN, HIGH);
        }
    }

Overview | I2C addresses!, If they don't speak the same language, communication is difficult. Likewise, electronic parts need to communicate - and they also have their own languages. There  All the IMUs with AD0 set to HIGH with have an I2C address of 0x69, whereas the only one on LOW will have an address of 0x68. If you want to read them all, you just go through a loop and set the one you want to LOW, the others to HIGH, and you're set.

Multiple I2C sensors with the same address, Multiple I2C sensors with the same address When you want to read from a specific IMU, set all AD0 s to HIGH , except the one you want to  I2C communication is generally used to communicate with Gyroscope, accelerometer, barometric pressure sensors, LED displays etc. In this Arduino I2C tutorial we will use I2C communication between two arduino boards and send (0 to 127) values to each other by using potentiometer.

How to resolve I2C address clashes?, By using our site, you acknowledge that you have read and understand our Multiple I2C devices with same address During the transmission of a byte, the device which has the clock and data pins I had two TCS3414 color-light sensors that I wanted to compare (The FN and CS packages, which have different filters). The only bad news about I2C is that each I2C device must have a unique address - and the addresses only range from 0 to 127 (aka 0 to 0x7F hex). One thing this means is that if you have two accelerometers (lets say) and they both have address 0x22 you cannot have both of them on the same I2C lines. There are a few work-arounds:

Multiple I2C Sensors with Same address (no peripherals/multiplexer , Unfortunately when I attempt this the show I2C command shows that there are devices at all I2C addresses. I can still take data but it reads as  There is nothing built into I2C to do this, normally slave devices will have some externals pins that can be set to 0 or 1 to toggle a couple of the address bits to avoid this issue. Alternatively I've dealt with a few manufacturers that have 4 or 5 part numbers for a part, the only difference being its I2C address.

Comments
  • see: changing i2c address
  • Sorry, but how does this answer reply to the OP question? he is asking how to read from 4 sensors with the same address, not how to read the data from one sensor..
  • It look like an "out of place" answer to me, intended for another question perhaps?