I made a project by two UNO, the first one used 2 potentiometers as analog input, then send the ADC data to the second UNO via IIC, the second UNO use these data as input to 2 servos. And, my reference is here - Master Writer/Slave Receiver
the Writer code:
#include <Wire.h>
int potentioMeter2 = 0;
int potentioMeter1 = 0;
byte potentialSend1 = 0;
byte potentialSend2 = 0;
void setup()
{
pinMode(A0, INPUT);
pinMode(A1, INPUT);
Wire.begin(); // join i2c bus (address optional for master)
}
void loop()
{
potentioMeter1 = analogRead(A0);
potentioMeter2 = analogRead(A1);
potentialSend1 = map(potentioMeter1, 0, 1023, 0, 180);
potentialSend2 = map(potentioMeter2, 0, 1023, 0, 180);
Wire.beginTransmission(0); // transmit to device #0
Wire.write("Potential1 is: "); // sends 15 bytes
Wire.write(potentialSend1); // sends one byte
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(0); // transmit to device #0
Wire.write("Potential2 is: "); // sends 15 bytes
Wire.write(potentialSend2); // sends one byte
Wire.endTransmission(); // stop transmitting
delay(10); // Delay a little bit to improve simulation performance
}
the Reader code:
#include <Wire.h>
#include <Servo.h>
Servo myServo1;
Servo myServo2;
void setup()
{
Wire.begin(0); // join i2c bus with address #0
Wire.onReceive(receiveEvent1); // register event for myServo1
Wire.onReceive(receiveEvent2); // register event for myServo2
Serial.begin(9600); // start serial for output
myServo1.attach(5);
myServo2.attach(6);
}
void loop()
{
delay(100);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent1(int howMany)
{
while(1 < Wire.available()) // loop through all but the last
{
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
myServo1.write(x);
}
void receiveEvent2(int howMany)
{
while(1 < Wire.available()) // loop through all but the last
{
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
myServo2.write(x);
}
now, the problem is, when I started simulation, I found there was value in the first UNO, and there wasn't value in the second UNO, what maybe the reason for this situation?
I found the 2 receiveEvents were all works - I could see the 2 data flow changing in the Serial Monitor, but only one Servo moving, the other fixed in most of the time, and some time would just sweep a little.
I'm sorry to say, but the official examples by Arduino are wrong.
We don't use readable text with variable length for I2C. Since the I2C bus is not a stream of data, but packages of data.
I agree with DrDiettrich, it is easier to transfer fixed size binary packages.
You could for example transfer an array of 2 integers.
I2C address 0 is the special "broadcast" address.
There are other special addresses, but those are not used on the Uno board. Most Arduino examples start with I2C address 8.
Do you use Tinkercad ? Can you give a public link to your project ?
Don't use the URL of your browser, that is private and can not be opened by others. There is perhaps a button somewhere to share your project.
I think that you used a "Send To" for a shared project instead of a public link.
Is that a shared project now ? I can not make a copy for myself of it and I can not store it to my own projects.
I have added a GND wire between the Arduino boards and two text labels. Can you see that ?
You might want to remove that link in your Reply #10 or someone else might change things.
Can you change the sketch to transfer a block of binary data with a fixed size ?
Yes, I saw your GND and text labels. How to make this project shared?
Could you make a copy of it now? I have clicked "Invite people" - "Generate new link" in "Send to".
That was indeed inviting others to take part in your project.
I rather make a new project to show an example and let you fix your own project.
There should be an option to make a public link, but I don't know how to do that.
You can try to improve your sketches and show them here. That is better for everyone. I just happen to use Tinkercad now and then, but most others don't.
That is the same "share your project with others" link. I can not even save that to my own projects in Tinkercad. Please remove this link as well from this forum.
I can not find that link to make it public. Tinkercad has changed that, and not for the good. There is an option in the settings to make a project either public or private.
I'm a fan of Wokwi: https://wokwi.com/
They don't support two Arduino boards at the same time yet.
#include <Wire.h>
#include <Servo.h>
Servo myServo1;
Servo myServo2;
byte dataReceived[32] = {}; // The Wire library implementation uses a 32 byte buffer,
// therefore any communication should be within this limit.
// Exceeding bytes in a single transmission will just be dropped.
int dataIndex = 0;
void setup()
{
//Wire.begin(8); // join i2c bus with address #8
Wire.begin(8);
Wire.onReceive(receiveEvent); // register event for myServo1 and myServo2
Serial.begin(9600); // start serial for output
myServo1.attach(5);
myServo2.attach(6);
}
void loop()
{
for(int i = 0; i <15 ; i++){
Serial.print((char)dataReceived[i]);
}
Serial.println((int)dataReceived[16]);
for(int i = 16; i < 32 ; i++){
Serial.print((char)dataReceived[i]);
}
Serial.println((unsigned int)dataReceived[32]);
delay(100);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
//while(1 < Wire.available()) // loop through all but the last
while(0 < Wire.available()) // loop through all
{
//char c = Wire.read(); // receive byte as a character
//Serial.print(c); // print the character
dataReceived[dataIndex] = Wire.read();
dataIndex ++;
}
dataIndex = 0;
//int x = Wire.read(); // receive byte as an integer
//Serial.println(x); // print the integer
//myServo1.write(x);
}
As I wrote before, the official examples are bad and we don't use readable ASCII text over I2C. If you don't mind, then I will not fix your sketch, but I go straight to sending two bytes over I2C.
Can you take a look at the code. It sends two bytes and it receives two bytes. That's all.
I have also changed the variables a little, but that is just an extra.
Master (Controller) sketch:
#include <Wire.h>
const int potmeter1Pin = A0;
const int potmeter2Pin = A1;
void setup()
{
Serial.begin(9600);
Serial.println("The Master (Controller) sketch has started");
Wire.begin(); // join i2c bus (address optional for master)
}
void loop()
{
// Using local variables when they are only used local
// The analogRead() function can be used without pinMode().
int potentioMeter1 = analogRead(potmeter1Pin);
int potentioMeter2 = analogRead(potmeter2Pin);
byte dataSend[2];
dataSend[0] = map(potentioMeter1, 0, 1023, 0, 180);
dataSend[1] = map(potentioMeter2, 0, 1023, 0, 180);
Wire.beginTransmission(8); // select I2C address 8
Wire.write(dataSend[0]); // one byte
Wire.write(dataSend[1]); // one byte
Wire.endTransmission(); // finish I2C session
// Delay a little bit to improve simulation performance
// Delay a little more to prevent that the I2C bus is too busy
delay(20);
}
Slave (Target) sketch:
#include <Wire.h>
#include <Servo.h>
Servo myServo1;
Servo myServo2;
// The Wire library implementation uses a 32 byte buffer,
// therefore any communication should be within this limit.
// Exceeding bytes in a single transmission will just be dropped.
volatile byte dataReceived[2];
volatile bool newData;
void setup()
{
Serial.begin(9600); // start serial for output
Serial.println("The Slave (Target) sketch has started");
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event for myServo1 and myServo2
myServo1.attach(5);
myServo2.attach(6);
}
// No delay in the loop().
// Continously check if something needs to be done.
//
// In the loop(), the Servo functions and Serial functions
// can be called without problem.
void loop()
{
if(newData)
{
myServo1.write(dataReceived[0]);
myServo2.write(dataReceived[1]);
newData = false;
}
}
// This function executes whenever data is received from master.
// This function is registered as an event, see setup().
// This is run from a interrupt, keep the code short and fast.
void receiveEvent(int howMany)
{
if(howMany == 2) // expecting two bytes
{
dataReceived[0] = (byte) Wire.read(); // read first byte
dataReceived[1] = (byte) Wire.read(); // read second byte
newData = true;
}
}
If you have that working, then you can improve the sketch by sending and receiving an array as an array without using [0] and [1]