I have a master-slave setup consisting of a nodeMCU(master) and an arduino nano(slave). I want to sent two different types of data on two different I2C addresses. Datatype 1 are integers and datatype 2 are chars.
I have written these two codes, they somewhat do what I expected but the result isn't consistent.
Master(nodeMCU):
#include <Wire.h>
void setup() {
Serial.begin(9600); /* begin serial for debug */
Wire.begin(5, 4); /* join i2c bus with SDA=D1 and SCL=D2 of NodeMCU */
}
void loop() {
int r =5;
Wire.beginTransmission(8); /* begin with device address 8 */
Wire.write(r);
Wire.endTransmission();
delay(100);
String bod = "message";
Wire.beginTransmission(9);
Wire.write(bod.c_str());
Wire.endTransmission();
delay(100);
}
The slave (arduino nano)
#include <Wire.h>
void setup() {
/* register request event */
Serial.begin(9600); /* start serial for debug */
}
void loop() {
Wire.begin(8); /* join i2c bus with address 8 */
Wire.onReceive(receiveEvent1); /* register receive event */
Wire.begin(9); /* join i2c bus with address 9 */
Wire.onReceive(receiveEvent2);
}
// function that executes whenever data is received from master
void receiveEvent1(int howMany) {
while (0 <Wire.available()) {
int c = Wire.read();
/* receive byte as int */
Serial.print(c); /* print the int */
}
Serial.println(); /* to newline */
}
void receiveEvent2(char howMany) {
while (0 <Wire.available()) {
char d = Wire.read();
/* receive byte as a character */
Serial.print(d); /* print the character */
}
Serial.println(); /* to newline */
}
The output I get also stops after a short time:
5
message
5
5
5
10910111511597103101
5
10910111511597103101
message
5
message
5
10910111511597103101
10910111511597103101
10910111511597103101
5
message
message
message
5
message
message
message
5
The expected output is out there, but not in a consistent way like:
5
message
5
message
5
message
Is there a way to get the output like this? And is there a way to fix the output from stopping after a short time?
Arduino's Wire library is designed to have a single I2C address per device. Its implementation uses a single set of global resources. This means that if you dynamically change the address of the receiving Arduino device then you would also need to synchronise the master to know what address to use.
It would be simpler to assign a single address to the slave device and have the master indicate the type of data being sent. This could be done by sending JSON or key/value pairs. e.g. the master can send the prefix
int:
before any integer andstr:
before any string. The slave can use the prefix to interpret the mode of transmission.Explaining the Output
This is the ASCII characters for the string
message
in integers. i.e. 109, 101, 115, 115, 97, 103, 101Here
receiveEvent1()
is handling the data being sent over the I2C bus and outputting each byte as an integer.Invoking
Wire.begin()
andWire.onReceive()
inloop()
will change the settings in the globalTwoWire
singleton. The underlyingtwi
library also has a single set of resources.The result of changing addresses and the receive handler (repeatedly in
loop()
) is a set of race conditions and the undefined use of the two receive handlers.This appears to include
receiveEvent1()
handling "5" andreceiveEvent2()
handling "message" as you intended. It also includesreceiveEvent1()
handling "message" resulting in the sequence of numbers.The apparent empty line is likely
receiveEvent2()
handling "5" so there is probably a non printable ASCII ENQ (enquiry) character being output. It's also likely there are periods where neither handler is configured properly and some messages are being dropped or ignored.