How to use two Grove Water Level Sensor with Grove Base Shield V2.0 using I2C

Hi There,

I am looking for some help, as I have tried on my own for the last few days and not succeeding.

I am trying to use two Grove water level sensors (10cm) to measure the liquid in a jar. I am using Elegoo Mega2560 with Grove Base Shield V2.0.

I can get the level sensor to work with the code below when it is just on it's own, however when I want to try and use the second one and plug it into the base shield I can't get it to work.

My understanding is that I need to change the address, but I have no clue on how to do this. I have zero experience in coding or with Arduino.

I would sincerely appreciate any help anyone could give. I apologize if this is posted to the wrong location. I just have no clue as how to start it.

The code for the level sensor is one I found online, it is not my own, hence no tags. It can be found here:

Base Shield

image

Code

#include <Wire.h>

#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL SerialUSB
#else
#define SERIAL Serial
#endif

unsigned char low_data[8] = {0};
unsigned char high_data[12] = {0};

#define NO_TOUCH       0xFE
#define THRESHOLD      100
#define ATTINY1_HIGH_ADDR   0x78
#define ATTINY2_LOW_ADDR   0x77

void getHigh12SectionValue(void)
{
  memset(high_data, 0, sizeof(high_data));
  Wire.requestFrom(ATTINY1_HIGH_ADDR, 12);
  while (12 != Wire.available());

  for (int i = 0; i < 12; i++) {
    high_data[i] = Wire.read();
  }
  delay(10);
}

void getLow8SectionValue(void)
{
  memset(low_data, 0, sizeof(low_data));
  Wire.requestFrom(ATTINY2_LOW_ADDR, 8);
  while (8 != Wire.available());

  for (int i = 0; i < 8 ; i++) {
    low_data[i] = Wire.read(); // receive a byte as character
  }
  delay(10);
}

void check()
{
  int sensorvalue_min = 250;
  int sensorvalue_max = 255;
  int low_count = 0;
  int high_count = 0;
  while (1)
  {
    uint32_t touch_val = 0;
    uint8_t trig_section = 0;
    low_count = 0;
    high_count = 0;
    getLow8SectionValue();
    getHigh12SectionValue();

    Serial.println("low 8 sections value = ");
    for (int i = 0; i < 8; i++)
    {
      Serial.print(low_data[i]);
      Serial.print(".");
      if (low_data[i] >= sensorvalue_min && low_data[i] <= sensorvalue_max)
      {
        low_count++;
      }
      if (low_count == 8)
      {
        Serial.print("      ");
        Serial.print("PASS");
      }
    }
    Serial.println("  ");
    Serial.println("  ");
    Serial.println("high 12 sections value = ");
    for (int i = 0; i < 12; i++)
    {
      Serial.print(high_data[i]);
      Serial.print(".");

      if (high_data[i] >= sensorvalue_min && high_data[i] <= sensorvalue_max)
      {
        high_count++;
      }
      if (high_count == 12)
      {
        Serial.print("      ");
        Serial.print("PASS");
      }
    }

    Serial.println("  ");
    Serial.println("  ");

    for (int i = 0 ; i < 8; i++) {
      if (low_data[i] > THRESHOLD) {
        touch_val |= 1 << i;

      }
    }
    for (int i = 0 ; i < 12; i++) {
      if (high_data[i] > THRESHOLD) {
        touch_val |= (uint32_t)1 << (8 + i);
      }
    }

    while (touch_val & 0x01)
    {
      trig_section++;
      touch_val >>= 1;
    }
    SERIAL.print("water level = ");
    SERIAL.print(trig_section * 5);
    SERIAL.println("% ");
    SERIAL.println(" ");
    SERIAL.println("*********************************************************");
    delay(1000);
  }
}

void setup() {
  SERIAL.begin(115200);
  Wire.begin();
}

void loop()
{
  check();
}

I could only attach two links, here is one for the 2560 board.

Elegoo Mega 2560

Nice pictures but they do not convey a lot of information. However I did notice that as the conners are on the board each one mirrors a data pin from the one before and the one after. You probably will have to skip a socket. Also if you put them in the same jar of water they will probably interfere with each other. They would require a much bigger container. If this does not solve the problem please post an annotated schematic showing all connections, power, ground and power supplies.

Hi gilshultz,

Many Thanks for your reply.
You are correct to say that the pins are mirrored from the shield to the Mega2560, however they do not need to skip a pin, I have it inserted correctly.

I can have one level sensor working by connecting it to the shield. However when I attempt to use a second sensor it is not recognized on the monitor output.

I understand this is down to how it is addressed, I don't understand addressing.

What schematic drawings are you referring too. The shield and the mega. I can attach the shield as a photo, but the shield is to big, you will have to use the link supplied below.

I think i need to start the sketch by separating the two sensors by address.

Why do you say you can change the address of the sensors? Have you read somewhere that it is possible? If so, please post a link to that.

If it is not possible to change the address of the sensor, you will need to use an i2c bus multiplexer such as tca9548.

You are on the correct tract. The last posting helps a lot. If you look it is an I2C sensor, that tells me it is on a special I2C buss designed for communications to on board chips. Setups like yours with short leads work very well. However you need to connect them properly. If you check the sensor leads are black = ground, red = VCC (5v) White = SDA (Serial DAta) and yellow = SCL (Serial SClock line). I think you just figured it out and you need to plug into the I2C jacks. I did not look real close but it appears there are no pull up resistors on SDA and SCL. If you have problems and the scanner does not find them you should add something in the 4.7K range where one end of the resistors goes to +5 and the other end of the resistors goes 1 to SDA and the other to SCL.

You can put as many devices on the I2C bus as you like but they normally each need to be a different address and that is limited to 127 and many I2C devices have only eight valid addresses. As long as the address is different they should work.

Most important thing to remember is have fun.

I under stand what you say about using up resistors, but that means bread boards and added complication.
I thought the purpose of the Base Shield was to avoid this, hence the many connections.
I may need to use a multiplexer as the sensor could have the same address, it seems the sensors only have two addresses.
How do you know what the addresses are.
image

Hi Paul,

Thank You for your input. I may have read it wrong with address, i will have to go back and find where i took that from.
Maybe the issue is that the sensors have the same address and i do need a multiplexer.
Ho do i know what address they use.
image

The "Address" on an I2C bus is like the Address you put on a letter - it's how the postman knows where to deliver it.
If two houses had the same address, how would the postman know which one should get the letter?

And so it is with I2C (and many other buses) - it's how the system knows which device it is talking to.

From the table in your post, it seems that this sensor supports two addresses:
image

The documentation for the sensor should tell you how to select which one of those two possible addresses is actually used.

Ah, no: it seems that each sensor actually uses both of those addresses - one for the "high" range, and one for the "low" range - and there is no way to select different addresses :frowning_face:

So the only way to use multiple of these sensors is to have each one on a separate I2C bus - either by using separate I2C peripherals on the microcontroller, or (as others have said) by having an I2C multiplexer.

1 Like

The schematic shows that there are pullups on the board:


https://files.seeedstudio.com/wiki/Grove-Water-Level-Sensor/res/Grove%20-%20Water%20Level%20Sensor%20(10CM)_SCH%26PCB.zip

They always need to be a different address - addresses need to be unique on the bus.

Yes the resistors are on the added schematic so you do not need to add them. Important: Start with the I2C scanner and connect only one of the sensors and see if you get the correct addresses. Then try it with the other, they should be the same. Then try it with both and expect garbage from the scan. Bild your porject as far as you can go with one sensor and get it operational. Leave room for a I3C mux and maybe several sets of pull up resistors. Each buss after the mux needs pull up resistors unless the modules have them.

The modules do have them.

Also, the I2C from the processor to the mux would need pullups

Thanks for the input guy's, I'm still trying to figure this stuff out, and this is only the start of a bigger project.
From my understanding I can't just use the base shield with the two level sensors as they both have the same address.
As I have no way of changing the address I need to use a multiplexer. If I use the multiplexer I need to use some pull up resistors.

How do I use the I2C scanner is this code ran on it's own with the sensor just connected, or do I need the level sensor sketch running also.

Sorry for the late reply, have been busy working and family, but appreciate the help.

Yes, but if you get the mux on a ready-made board it may already have them - as your sensors do.

Yes, it is.

https://playground.arduino.cc/Main/I2cScanner/

In general, yes.

But we know that this particular sensor just has fixed addresses, and no way to change it.

Adafruit tutorial (this is the same mux as used in the other tutorial I linked earlier):

Yes we know but does the hardware. The scan is not intended to be part of your software, it is used for testing similar to a multimeter. It will let you know if the processor can see the sensor, regardless if you close your eyes or not. Simply it tests to see if things are probably connected correctly. If it does not work no time fiddling with software etc.

Just in case anyone come across this thread in the future, i will try and keep it updated to conclusion.

Using the code below, I got the following on the Serial Monitor:
image
I did it with one sensor in, then tried two, there were a few other combinations but generally, it never read the second one. It would either hang or not start, it was a bit temperamental.

I understand each sensor needs an address an why they are used, i didn't know about/how to configure the sensor address.

I am going to order a TCA9548A I2C 8 Channel Multiplexer for use with the shield and two sensors, no doubt i will be back with more questions and requests for some help.

// --------------------------------------
// i2c_scanner
//
// Modified from https://playground.arduino.cc/Main/I2cScanner/
// --------------------------------------

#include <Wire.h>

// Set I2C bus to use: Wire, Wire1, etc.
#define WIRE Wire

void setup() {
  WIRE.begin();

  Serial.begin(9600);
  while (!Serial)
     delay(10);
  Serial.println("\nI2C Scanner");
}


void loop() {
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    WIRE.beginTransmission(address);
    error = WIRE.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}
1 Like