Hello,
First time posting!
I am troubleshooting a project where I am using two arduinos to communicate.
The components are:
Encoder:
- A signal, B signal, 5v, gnd
Arduino Nano 328: - Reads encoder using encoder.h library via D2 and D3
- saves long encoder value in a union then sends individual bytes over i2c SDA & SCL
Adafruit Metro 328 (Uno clone): - requests 4 bytes from nano via i2c SDA & SCL
- saves 4 bytes into union in the same order they were sent
- reads long from union
Here's the problem: When I set everything up to read the encoder value with the nano and then send it over i2c, nothing appears on the serial monitor connected to the Metro. I suspect this has to do with interrupts and/or delays messing with the i2c or encoder library, but I am out of my depth here.
Here's the nano/encoder code:
#include <Wire.h>
#include <Encoder.h>
#define ENCODER_USE_INTERRUPTS
#define ENCODER_OPTIMIZE_INTERRUPTS
// Initializations
#define encoderPinA 2
#define encoderPinB 3
// #define encoderPinZ 4
Encoder myEnc(encoderPinA, encoderPinB);
long ePos = -999; // encoder position
union u_tag { // allow long to be read as 4 seperate bytes
byte b[4]; // 4 bytes to be sent over I2C
long LePos; // encoder position as 4 byte long
} u;
void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
delay(100);
}
void requestEvent() { // i2c sending function
// respond with message of 4 bytes
// as expected by master
digitalWrite(LED_BUILTIN, LOW);
ePos = myEnc.read(); // read encoder value (2 byte int)
u.LePos = ePos;
Wire.write(u.b[0]); // send 4 bytes over I2C
Wire.write(u.b[1]); // reconstructed in the same order by master
Wire.write(u.b[2]);
Wire.write(u.b[3]);
delay(100); // allow all bytes to send
digitalWrite(LED_BUILTIN, HIGH);
}
Note: I have tried with and without delays and the LEDs, but am too scared to try using nointerrupts() for fear of losing an encoder reading pulse.
Here is the master reader code on the Metro:
#include <Wire.h>
long ePos = 0; // encoder position
union u_tag { // allow long to be read as 4 seperate bytes
byte b[4]; // 4 bytes to be received over I2C
long LePos; // encoder position as 4 byte long
} u;
void setup() {
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
Serial.println("Serial Start");
}
void loop() {
Wire.requestFrom(8, 4); // request 6 bytes from slave device #8
Serial.print("Incoming: ");
byte index = 0;
while (Wire.available()) { // slave may send less than requested
if(index == 0){
u.b[index] = Wire.read();
}
if(index == 1){
u.b[index] = Wire.read();
}
if(index == 2){
u.b[index] = Wire.read();
}
if(index == 3){
u.b[index] = Wire.read();
}
index++;
}
Serial.print(u.LePos, DEC );
Serial.print(" = ");
Serial.print(u.b[0], HEX );
Serial.print(" : ");
Serial.print(u.b[1], HEX );
Serial.print(" : ");
Serial.print(u.b[2], HEX );
Serial.print(" : ");
Serial.print(u.b[3], HEX );
Serial.println();
delay(100);
}
I have successfully gotten the unions (first time with those) to correctly save a value, increment the value, and send the bytes over i2c to the uno, where it is constructed and then printed to the serial monitor. Using a single arduino, I have also successfully read and then printed the encoder value to the serial monitor using a union to print the individual bytes.
To test the i2c functionality I commented out the encoder sections and manually incremented the 'encoder value' then sent it over i2c. This works, and using the master code from above, the Metro prints the long value correctly after saving it to the union.
Here's the test code:
// Wire Slave Sender
// by Nicholas Zambetti <http://www.zambetti.com>
// Demonstrates use of the Wire library
// Sends data as an I2C/TWI slave device
// Refer to the "Wire Master Reader" example for use with this
// Created 29 March 2006
// This example code is in the public domain.
#include <Wire.h>
// #include <Encoder.h>
// #define ENCODER_USE_INTERRUPTS
// #define ENCODER_OPTIMIZE_INTERRUPTS
// Initializations
// #define encoderPinA 2
// #define encoderPinB 3
// #define encoderPinZ 4
// Encoder myEnc(encoderPinA, encoderPinB);
long ePos = -999; // encoder position
union u_tag { // allow long to be read as 4 seperate bytes
byte b[4]; // 4 bytes to be sent over I2C
long LePos; // encoder position as 4 byte long
} u;
void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
delay(100);
ePos += 1;
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
// respond with message of 4 bytes
// as expected by master
// digitalWrite(LED_BUILTIN, LOW);
// ePos = myEnc.read(); // read encoder value (2 byte int)
u.LePos = ePos;
Wire.write(u.b[0]); // send 4 bytes over I2C
Wire.write(u.b[1]); // reconstructed in the same order by master
Wire.write(u.b[2]);
Wire.write(u.b[3]);
// delay(100);
// digitalWrite(LED_BUILTIN, HIGH);
}
I've been furiously scratching my head, please help save my hair!
-Trev