I2C between Nano and Uno R4

I am using a Nano to scan multiple IR sensors, and send the results to an R4 via I2C. I can form the string on the Nano, and it prints locally correctly. When the R4 sees it it is just a number that has no meaning. What am I doing wrong?


//Nano Ir sensor scanner
// must use ATMega328P OLD BOOTLOADER
#include <Wire.h>

// Define sensor pin and data variable

const int sensor1Pin = A0;
const int sensor2Pin = A1;
const int sensor3Pin = A2;

int sensor1Value;
int sensor2Value;
int sensor3Value;

void setup() {
  Serial.begin(9600);
  Wire.begin(8); // Set Nano as I2C slave with address 8
  Wire.onRequest(requestEvent); // register event
}

void loop() {
  delay(1000);
  sensor1Value = digitalRead(sensor1Pin); 
  sensor2Value = digitalRead(sensor2Pin);
  sensor3Value = digitalRead(sensor3Pin);
  char values[100];
  sprintf(values,"%d%d%d ", sensor1Value,sensor2Value,sensor3Value);
  Serial.println(values); // forms the string as 3 digits, 0 or 1
 
}

void requestEvent() {
    Serial.println("Sending");
  sensor1Value = digitalRead(sensor1Pin); 
  sensor2Value = digitalRead(sensor2Pin);
  sensor3Value = digitalRead(sensor3Pin);
  // form a char string with 3 sensor states
  char values[100];
  sprintf(values,"%d%d%d ", sensor1Value,sensor2Value,sensor3Value);
  Wire.write(values); // Send sensor data to master
}
#include <Wire.h>
// Listener
void setup() {
  Wire.begin(); // Initialize as I2C master
  Serial.begin(9600);
  Serial.println("Listening");
}

void loop() {

  Wire.requestFrom(8, 1); // 
  Serial.println("Receiving");
  int receivedData = Wire.read(); // Read data received
  Serial.println(receivedData); // Print sensor data
  delay(1000); // Add a delay
}

Did you forget to use code tags when you posted your sketch ?

Posting your code using code tags prevents parts of it being interpreted as HTML coding and makes it easier to copy for examination

In my experience the easiest way to tidy up the code and add the code tags is as follows

Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

Please edit your post and add code tags

1 Like

Make a simple check of your I2C Network by reading data = 0x1234 from the Slave and then try with data = 13.75 and try with your Sensor data.
Arduino UNOR4: Master Sketch:

#include <Wire.h>
// Listener
void setup() 
{
  Wire.begin(); // Initialize as I2C master
  Serial.begin(9600);
  Serial.println("Listening");
}

void loop() 
{
  Wire.requestFrom(8, 2); //reading two bytes from Slave 
  Serial.println("Receiving");
  byte receivedDataH = Wire.read(); // Read MSByte of data received
  byte receivedDataL = Wire.read(); // Read LSByte of data received
  int receivedData = receivedDataH << 8 | receivedDataL;
  Serial.println(receivedData); // shows: 1234
  delay(1000); // Add a delay
}

Arduino NANO: Slave Sketch:

#include <Wire.h>
// Define sensor pin and data variable
int data = 0x1234;

void setup() 
{
  Serial.begin(9600);
  Wire.begin(8); // Set Nano as I2C slave with address 8
  Wire.onRequest(requestEvent); // register event
}

void loop() 
{
  
 
}

void requestEvent() 
{
    Wire.write(highByte(data));
    Wire.write(lowByte(data));
}

You send a character array:

and then try to read it as an int:

And you are surprised that the result appears to be nonsense?

Consider the following bit of non Arduino code:

me@home:~ $ cat xyz.cpp
#include <stdio.h>
int main(int argc, char *argv[]) {
   char buf[100];
   int i=1;
   int j=0;
   int k=1;
   sprintf(buf, "%d%d%d", i, j, k);
   printf("%s\n", buf);
   printf("%d\n", buf);
   return 0;
}
me@home:~ $ gcc -o xyz xyz.cpp
me@home:~ $ ./xyz
101
-1092534176
me@home:~ $ 

Is it clear to you now what mistake you are making?

Golam, I ran this code, it returns 4660, not 1234

An int on the Nano is 2 bytes but an int on the R4 is 4 bytes

Instead of ints try using variables declared as type uint16_t to force them to be the same size, ie 2 bytes

1 Like

Apparently I'm just talking to myself here. I'll make one last effort and then call it.

You are writing a character array. Three ASCII digits and a trailing null.

You are reading a single byte. Which in this case is the first ASCII digit you sent. A '0' or a '1', whose ASCII decimal values are 48 and 49. And then assigning that to an int and expecting I honestly don't know what.

You must read data in the same representation it was written in. If you write it in ASCII, you must read it in ASCII.

2 Likes

I get it, I am passing one sensor now as 0 or 1, just need to get the other 2

That's because this

prints the value in decimal. You get 1234 with

 Serial.println(receivedData,HEX); // shows: 1234
1 Like

1234 Hex = 4660 decimal.

So, use the following code to print the received value as hex at the Master side:

 Serial.println(receivedData, HEX); // shows: 1234

Got it. All working fine now. Thanks all.

For the benefit of anyone finding this topic please explain what the problem was and how you fixed it

As was pointed out above, I was creating a char array and then reading it as an int. I send the values of 3 IR senors as 0 or 1.
The code on the read side that works is:

 Wire.requestFrom(8, 4); //reading two bytes from Slave 
  Serial.println("Receiving");
  byte receivedDataH = Wire.read(); // Read MSByte of data received
  byte receivedDataL = Wire.read(); // Read LSByte of data received
  int receivedData = receivedDataH<< 8 | receivedDataL;
 Serial.println(receivedData); // shows sensor state

This prints the following

000
001


100
111 depending on the values sent.

Now i need to get this passed into s0, s1 and s2 to represent the 3 inputs.

Hi, @neil28461

Can you tell us why you need two controllers, the R4 should be able to do it all?

Tom.... :smiley: :+1: :coffee: :australia:

The remote slave will monitor multiple sensors, the master is a webserver posting the sensor states(hopefully) on a control panel and i want to keep them apart. I agree one r4 can do it all, just thinking ahead. I will need separation between the 2 up to about 3ft eventually.

It might be a good idea to check that distance now.
I2C is designed for ON BOARD communications, not for relatively long cable uses.

Google;

extended range I2C

If you have any problems.

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

1 Like

I know the limitation, i have looked into i2c extenders.

Comms via UART and an RS485 physical layer would probably be a better choice.

It might work but will be buggy. Use something designed to communicate over distances. I use CAN as it is inexpensive and multi master good for a few thousand feet.

1 Like

You may go with UART Communication which can travel up to 50 feet and if using RS232 logic, the signal can travel up to 150 feet.