Send/Receive Integer Value via i2c

I know this problem has been talked about here in many posts but try as I might I can't get this working. From my Master, I want to request an integer value from a Slave but all I'm getting in the Serial Monitor is "-1" when it should be 9.

Master

#include <Wire.h>

int numPWMChannels = 0;

void setup() {
  Wire.begin();        // join I2C bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {

  Wire.requestFrom(2, 2);     // request 2 bytes from secondary device #2

  byte x1, x2;
  x1 = Wire.read();  //x1 holds upper byte of received numPWMChannels
  x2 = Wire.read();  //x2 holds lower byte of received numPWMChannels
  numPWMChannels = (int)x1 << 8 | (int)x2;

  Serial.print("numPWMChannels: ");
  Serial.println(numPWMChannels);

  delay(500);
}

Slave

#include <Wire.h>

int NUM_PWM_CHNLS = 9;

void setup() {
  Wire.begin(2);                // join I2C bus with address #2
  Wire.onRequest(requestEvent); // register event
}

void loop() {
//  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {

  Wire.write(highByte(NUM_PWM_CHNLS)); 
  Wire.write(lowByte(NUM_PWM_CHNLS));

}

Not enough information.

What type of Arduino is the master, and what is the slave?

What value pullup resistors are you using on SDA and SCL?

Did you connect the grounds? Please post a wiring diagram.

2 Likes

Master: Polulu A-Star 328U4
Slave: Arduino Uno

I don't have any pull-up resistors on SDA/SCL. The GNDs are connected together. I've been using i2c with the Wire library quite successfully until now - the only problem is sending/receiving integer values.

Low value pullup resistors are absolutely required for I2C to function reliably. They are part of the bus specification! Add 4.7K resistors from Vcc to SDA and SCL, and try again.

The internal pullups (typically 10K to 30K) are enabled by default and sometimes they are enough, but not in most situations. Especially not when you have long wires (> 10 cm) connecting master and slave.

1 Like

what are values of x1 and x2 bytes?

I suspect your I2C Bus wiring connection?

1. Upload the following sketches to check that the I2C connection is alright by detecting the presence of the Slave.

Master Sketch:

#include<Wire.h>

void setup()
{
    Serial.begin(9600);
    Wire.begin();
    Wire.beginTransmission(0x08); //address: 0x00 - 0x07 are reserved
    byte busStatus = Wire.endTransmission();
    if(busStatus !=0)
    {
        Serial.println("SLave is not found.");
        while(1);  //wait for ever
    }
    Serial.println("Slave is found.");
}

void loop(){}

Slave Sketch:

#include<Wire.h>

void setup()
{
    Serial.begin(9600);
    Wire.begin(0x08);
}  
void loop(){}

2. If Slave is not found, then power down of both Arduinos. Connect 2x4.7k or 2x10k pull-up resistors with I2C Bus at the Master side. Power up both Arduinos and then press RESET buttons of both Arduinos.

3. If wiring is correct and the Arduinos are healthy, you must see the following message on the SM of Master.

Slave is found.
1 Like

I don't see Wire.available() used before you use Wire.read()

There is no need to execute Wire.available() instruction as the requestFrom() method waits until all the requested data bytes are in Master's FIFO Buffer.

Both show as 255.

@RossAWaddell sometimes a bunch of different opinions flood a topic, causing only confusion. In this topic however, there are only good suggestions. You have to try a few things and give more information. Please read all the replies once more and follow the suggestions. At this moment your Master and Slave are not communicating, there is no I2C bus between them.

Connections are fine (apart from the 4.7k pullups I need to add). I can send text strings, just not an integer value.

The connections are good. As I said, I can send & receive text, just not integer values.

I loaded the Wire example sketches ("master_reader", "slave_sender") onto my boards and I see "hello" in the serial monitor as expected.

That's likely a clue. Wire is an instance of the TwoWire class. That inherits from the Stream class. The Stream class's read() function returns -1 if there's not an actual byte to read. So, I'd first try printing the value of Wire.available() to see if the library thinks there's anything to read.

Next, I'd get a Low-Cost Logic Analyzer and start snooping to see what's actually happening on the I2C bus.

In my project I have two slaves connected to the one master - do I need two sets of 4.7k resistors on each board, or can I have just one set on the SDA & SLC on the master?

Just one set. Brush up on I2C communications here:

1 Like

This is consistent with your -1 result. What requestFrom returns? it should return 2

Wire.available() shows as "0" in the serial monitor.

How do I check that? Is it as simple as:

  Serial.print("Wire.requestFrom(2, 2): ");
  Serial.println(Wire.requestFrom(2, 2));

With the Wire.requestFrom() you are trying to read from the Slave, but the Master can not find the Slave and stops the I2C session and returns zero for Wire.available().

Please try the sketches of post #6.

1 Like

byte result = Wire.requestFrom(2, 2);
Serial.println((int)result);

1 Like