help linking two Unos via any method..

Hey all

A bit new to Arduino, but been searching all day and not finding the answer - thought I'd try here.

my goal -
link two Uno boards such that I can send a few int variables from one to the other.

The challenge
the receiving board is using a TFT shield, taking up pins 4/5 normally used for SDA type transmission.

Stuff I've tried -
-tried using serial pins 1/2 - I can get transmission to work, but cant figure out how to send values (numbers)- just uses serial.begin and serial.print to send values.

-softserial - they claim they can do I2C transmission over any pin, and pins 16/17 seem to do SDA/SLC on a rev 3 board - but I cant get transmission to work.

I can post up more detail on my attempts for these methods - but I got to ask the big question - is there an easier way I am missing???? in the end, I need to send about 3-4 int vars - never thought it would turn into a quest.

thx.

Have you tried using SoftwareSerial on each board to create a second serial port on each board. You can use the examples in Serial Input Basics to receive the data. The system in the 3rd example will be most reliable.

...R

thx for your interest - I was a touch ranty yesterday. I've given up on softserial, because the only benefit I see is changing the pins, and pins 16/17 mirror pins 4/5. no need for soft serial, they are physically the same (best I can tell) and they do work.

I have the following code working, thx to Gammon and others that have written a lot on topic. however, its still not 100% right for my application. Here my confusion - it seems like I2C devices need an address to be in their "mini network" to talk, and many devices can be on the I2C bus if you will, since they have different addresses. I have I2C scanner - a very helpful and working tool, so I have all my devices hex address. the confusion - the code I can get working uses interrupts (I think?? ) and I cant figure out how to change it. ideally, I dont want to use interrupts to send, and I do need addressing to work, because 3 things will be in the I2C bus. I'' put in code comments the stuff I dont understand.

I need the addressing to work, because the display will also be on this Ic2 bus.

Master
#include <Wire.h>
#include <I2C_Anything.h> //<----this works like a GEM!

void setup()
{
Wire.begin(2); // <-----I dont understand this! shouldnt this be the hex address, like 0x27 or someting?

}
int x=100;
int y=80;
int z = 99;
unsigned int zz = 10000;

void loop()
{
delay(100);
x++;
y++;

Wire.beginTransmission(2);
Wire.write(x);
Wire.write(y);
Wire.write(z);
I2C_writeAnything(zz);
Wire.endTransmission();

}

//this side writes. this will be the main controller.

Slave***
#include <Wire.h>
#include <I2C_Anything.h>

void setup()
{
Wire.begin(2); //<--same, I dont get this. shouldnt this be ITS own address? seems like conflict, but works. ?!

Serial.begin(9600);
Wire.onReceive(receiveEvent);
}

int a = 0;
int b = 0;
int c = 0;
unsigned int cc = 0;

void loop()
{
}

void receiveEvent(int howMany) //<--dont understand the "int howMany", since it never gets passed

{
a=Wire.read();
Serial.println(a);
b=Wire.read();
Serial.println (b);
c = Wire.read();
Serial.println(c);
I2C_readAnything(cc);
Serial.println(cc);

delay(500);
}

The master device doesn't need an address in the begin call.

// on the I2C master device
  Wire.begin();

// on the slave device with address 2
  Wire.begin(2);

edit: Remove the delay(500) in the receiveEvent function. Bad idea.

ok - help me understand that a touch better. I've seen other code that uses hex addresses over I2C bus like the LCD uses stuff like #define I2C_ADDR 0x3F, and I've seen other similar I2C code using that method. is the "2" just an address value I soft define in the code??

Also I dont follow why the master doesnt need an address -because its not going to be receiving?

The I2C addresses signify which address the slave will respond to. Only one device per address on each I2C bus. I'm lucky to have a Due, which has 2 I2C buses.

The I2C slaves only respond to requests. The master receives data from the slaves only when it requests the data. It is a polling system. Master polls, slave responds.

Thx Tim - but now im more confused. do I have master/slave labeled wrong? I dont see my master polling - it just sends data (wire.write) and the slave receives it - Im guessing the receive function kicks off on interrupt?

I get the "one address per device" since that is the point of addressing, but I need to have one Uno talk to two I2C devices (its Uno peer, and a TFT or LCD board). thus - the addressing is key.

I can currently get half of this to work - the peers talk, but the slave (hooked to LCD), wont write to lcd.

Wire.write is half of it. That is how the master sends data to the slave. The second part is Wire.requestFrom(). That is how the master gets data from the slave.

ok - following you, and have read the references, still lost. in the slave write function - doesnt make since - begin transmission to 0. seems like that needs to be an address, and it doesnt work as it stands.

master - just key functions -
wire.begin(0);
wire.onRecieve(myReadFunction);

loop- wire.requestFrom(2,2);


Slave --just key functions -
wire.begin(2);
wire.onRequest(myWriteFunction);

loop-nothing -

myWriteFunction -
wire.beginTransmission(0);
wire.write(foo);
wire.endTransmission();

There is really no slave write beginTransmission function. Only interrupt driven responses. Here is my I2C slave test sketch.

#include <Wire.h>
byte array[8] = {2,4,6,8,10,12,14,16};
volatile byte regReq = 0;
volatile byte sendFlag = 0;
byte* rtnPtr;
 
void setup()
{
  Wire.begin(13);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
}

void loop()
{
  if(sendFlag)
  {
    rtnPtr = &array[regReq*2];    
    sendFlag = 0;
  }
}

void receiveEvent(int byteCount)
{
  regReq = Wire.read();
  sendFlag = 1;
}

void requestEvent()
{
  Wire.write(rtnPtr,2);
}

Could you be the awesome surfer dude you are Tim, and post the master side of this code too :slight_smile:

The "awesome" master code is on a RPi, not an Arduino. Don't know if it would be much help.

I built an I2C master for that slave code for my Due. It should work on any Arduino with an I2C port. Note I use 115200 baud.

// Wire Master Writer
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Writes data to an I2C/TWI slave device
// Refer to the "Wire Slave Receiver" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin(); // join i2c bus (address optional for master)
}

byte x = 0;

void loop() {
  Wire.beginTransmission(13); // transmit to device #13
  Wire.write(x);              // sends one byte
  Wire.endTransmission();    // stop transmitting

  delay(10);

  Wire.requestFrom(13, 2);    // request 2 bytes from slave device #13

  while(Wire.available())    // slave may send less than requested
  { 
    char c = Wire.read(); // receive a byte as character
    Serial.print(c,DEC);         // print the character
    Serial.print(" ");
  }
  Serial.println();
  
  x++;

  if(x > 3) x = 0;
  delay(1000);
}

It should show this on the master serial monitor.
2 4
6 8
10 12
14 16
2 4
6 8
10 12
14 16
...and on

********************SOLVED(I think :slight_smile: ) **************************

ok - this is working for both uno to uno transmission, and uno to I2C LCD at the same time. I am not using the interrupt method, but rather a "send data as needed" call, since the data is just for user display, doesn't need to be 100% realtime. also using the I2C SendAnything library - works nicely. I had problems with my LCD working OK, then showing garbage - I had to add a delay (or sampling rate really) for the LCD not to get boned.

The wiring for this test - if you freak out on pin 16/17 - go find a uno r3 pinout :slight_smile:

UNO "A" -or my sender.
vcc/gnd to proto board
pin 16 to Uno B Pin 16
pin 17 to Uno B pin 17

Uno "B" - or my receiver
vcc/gnd to proto board
A5 to SCL input on LCD
A4 to SDA input on LCD
pin 16 to Uno A pin 16
Pin 17 to Uno A pin 17

LCD -
vcc/gnd proto board
SLC to Uno B pin 5
SDA to Uno B pin 4

The Sender (my core unit doing the "i/o work" in my project)


#include <Wire.h>
#include <I2C_Anything.h>
unsigned int x=0;

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

}

void loop()
{

x++;
delay(1000);
MyTX();
}

void MyTX()
{
Wire.beginTransmission (13);
I2C_writeAnything(x);
Wire.endTransmission ();
}


My receiver - basic setup only, no LCD for early test


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

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

void loop()
{
Serial.print("loop");
Serial.print("\t");
Serial.print(x);
Serial.print("\n");

}

void receiveEvent(int byteCount)
{
I2C_readAnything(x);
}


receiver with LCD too - just replace first test receiver code, sender code remains the same


#include <Wire.h>
#include <I2C_Anything.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x3F // <<----- Add your address here. Find it from I2C Scanner
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7

unsigned int x=0;
unsigned int lastX = 0;

LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

void setup()
{
Serial.begin(9600);
Wire.begin(13);
Wire.onReceive(receiveEvent);
lcd.begin (16,2); // <<----- My LCD was 16x2
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
lcd.setBacklight(HIGH);
lcd.home (); // go home
lcd.clear();

}

void loop()
{
lastX=x;
Serial.print("loop");
Serial.print("\t");
Serial.print(x);
Serial.print("\n");

if(x !=lastX)
{
MyLCD();
}

}

void MyLCD()
{
lcd.setCursor (0,0);
lcd.print("SurferTim Rocks");
lcd.setCursor (0,1);
lcd.print(x);
lcd.print(" ");
}

void receiveEvent(int byteCount)
{

I2C_readAnything(x);
}