3

I have this code I got from YouTube for communicating between two Arduinos. By typing 'R' manually into the serial monitor of the 'master' Arduino, the 'slave' will print "Success". I'm trying all this for the basis of a project I'm starting.

After success with the code, I am now trying to make it automatic. I want the 'master' Arduino to print "R" itself and for the 'slave' to read this and print "Success". println doesn't work here, maybe it'll work if the slave code is changed? Both original codes are below, any ideas on how to do what I need?

Master:

#include <Wire.h>
char incomingByte;
int x = 0;

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

void loop() 
{
  Wire.beginTransmission(9);
  if (Serial.available()) {
    while (Serial.available() > 0) {
      incomingByte = Serial.read();
      Wire.write(incomingByte);
      Serial.println(incomingByte);
      Wire.endTransmission();
  }
  }

}

Slave:

#include <Wire.h>

int x = 0;

void setup() {
  Wire.begin(9);
  Wire.onReceive(recieveEvent);  
  Serial.begin(9600);
}

void recieveEvent(int bytes) {
  x = Wire.read();

}

void loop() {

  if (x == 'R'){
    Serial.println("Success");
    delay(100);
  }
}
  • Your Master supposedly should send 'R'. Where is the place in the code this happen? – smajli Mar 7 at 23:17
  • Look at what the master is doing. It's reading from serial and writing what it reads to Wire. How do you think you would make it send an R rather than what it reads from serial? – Mark Smith Mar 8 at 2:44
  • make x volatile. volatile int x = 0; – Juraj Mar 8 at 7:51
  • @MarkSmith That's what I'm unsure of. I am new at this so I don't know what to change in either codes. – Josh Mar 8 at 15:34
  • @smajli I have to manually type 'R' into the serial monitor. – Josh Mar 8 at 15:40
2

The I2C communication is not easy and there are many things that can go wrong. Two Arduino boards instead of one board are often used for the wrong reason in the first place.

Using a serial port is easier. The Arduino Leonardo has an extra hardware serial port, you could use the serial port to communicate between two Arduino boards. The Arduino Mega 2560 has three extra serial ports.

Sometimes two Arduino boards are used because multiple things have to be done at the same time.
When you use the Blink Without Delay example with millis, then the Arduino can do many things at the same time.

Sometimes two Arduino boards are used because there is some distance between the Arduino boards.
The I2C bus is a "bus", but that does not mean that you can use a long cable. You can go up to 20 inch (50 cm).

When two Arduino Uno boards are connected with the I2C bus, then three wires are needed:

  1. GND to GND
  2. SDA to SDA (plus pullup resistor)
  3. SCL to SCL (plus pullup resistor)

For a small test with short jumper wires, it is possible to do that without pullup resistors. For the final project pullup resistors should be used for SDA and SCL, for example 4k7 or 10k.

The example below uses a flag in the Slave Arduino. That extra variable makes it easier.
In the Slave receiveEvent function, there is a extra check to check if exactly one byte is received. That extra check is not required, but it can be useful.

I show this example as something to start with, because there are too many bad examples for I2C between Master and Slave.

Master

#include <Wire.h>

byte dataTransmit;

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

void loop() {
  Wire.beginTransmission(9);   // sending to slave with i2c address 9
  Wire.write(dataTransmit);    // the data to send
  Wire.endTransmission();

  dataTransmit++;              // all numbers from 0 to 255

  delay(250);                  // 250ms delay, to send 4 times per second
}

Slave

#include <Wire.h>

volatile byte dataReceive;
volatile bool newData;    // a flag to indicate that new data has arrived

void setup() {
  Wire.begin(9);          // create i2c slave at i2c address 9
  Wire.onReceive(receiveEvent);  
  Serial.begin(9600);
}

void loop() {
  if(newData) {           // is there new data?
    Serial.print("Received: ");
    Serial.println(int(dataReceive)); // convert to integer to print the number
    newData = false;      // reset flag
  }
}

void receiveEvent(int howMany) {
  if(howMany == 1) {      // extra check, to check if one byte is received
    dataReceive = Wire.read();
    newData = true;       // set flag, there is new data
  }
}
0

Here is my proposal to solve your issue:

  • Use the second Serial communication line of the master by connecting Rx and Tx Pins of Serial2 (this done only on master, practically a shortcut between Rx and Tx on Master)
  • Setup Serial2 if necessary: HardwareSerial Serial2(2); (that how it is necessary/done for my M5Stack)
  • Define baud rate for Serial2: Serial2.begin(9600);
  • Start your Automation by Serial2.write("R\n"); at an appropriate place in your code
  • Change conditions of if(..) and while(..) in your master's code from Serial.available() to Serial2.available()
  • Change incomingByte = Serial.read(); to incomingByte = Serial2.read();

With that solution you can still see your start signal printed out on your Serial monitor via the first Serial communication line. The communication to the slave is still working over IC2, Serial2 is only the proposal for the automation solution on master. Looks complicated, but this is how I understood the question, of course you also could directly use incomingByte="R\n"; to start your Automation and skip all that stuff with Serial2 :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.