Hi all,
I'm trying to make a connection between two Arduinos for a game. I'm using the MasterWriter Tutorial to do this (http://arduino.cc/en/Tutorial/MasterWriter). I have two Arduino Uno's connected to each other using A4 and A5 and the slave gets power from the master. Also, the grounds are connected. I am using Arduino 1.0 on OS X.
With the code below I was expecting to see messages go from Master to Slave and back again. By using the Serial connection I can see that messages from the master to the slave are correctly sent and received ("M10"), but messages from the slave to the master are garbled on reception by the master. The slave does send the correct values ("S20").
I can't figure out what's wrong! The message received by the Master is 3 bytes as expected, but instead of "S20", I get the bytes "0-255-255".
Does anybody have a clue?
Thanks in advance!
(I've removed all references to Serial.print in the code below to make it more legible)
/** Master */
#include <Wire.h>
byte GAME_IS_OURS = 0;
byte GAME_IS_THEIRS = 1;
byte move_count = 0; // we never have a board which allows more than 255 moves
byte mode = GAME_IS_OURS; // we begin, because we are the master
byte next_move = 0; // which column we want to put a block in
byte opponent_last_move = 0;
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
}
void loop()
{
mode = GAME_IS_OURS;
next_move = calculate_next_move();
move_count++;
// Send our move to opponent
sendBoardStatusWire();
mode = GAME_IS_THEIRS;
// Get the opponent's move:
while(!receiveWireMessage())
{
Wire.requestFrom(4, 3);
delay(500);
}
if(move_count > 30)
while(true)
{;}
}
byte calculate_next_move()
{
return move_count % 5; // sends a new column everytime (makes horizontal four in a row)
}
void sendBoardStatusWire()
{
Wire.beginTransmission(4); // transmit to device #4
Wire.write('S'); // sends one bytes
Wire.write(move_count);
Wire.write(next_move);
Wire.endTransmission(); // stop transmitting
}
boolean receiveWireMessage()
{
// the only message we will accept is {<char>, <byte>, <byte>}, with <char> == "M"
char control = 'X';
byte opponent_move_count = 1;
byte opponent_move = 1;
if(Wire.available())
control = Wire.read();
else
return false;
if(Wire.available())
opponent_move_count = Wire.read();
else
return false;
if(Wire.available())
opponent_move = Wire.read();
else
return false;
if(control != 'M')
return false;
if(opponent_move != (move_count + 1))
return false;
opponent_last_move = opponent_move;
move_count++;
return true;
}
/** Slave */
#include <Wire.h>
byte GAME_IS_OURS = 0;
byte GAME_IS_THEIRS = 1;
byte move_count = 0; // we never have a board which allows more than 255 moves
byte mode = GAME_IS_THEIRS; // the opponent starts, because we are such nice people
byte next_move = 0; // which column we want to put a block in
byte opponent_last_move = 0;
void setup()
{
Wire.begin(4); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // register event
}
void loop()
{
delay(1000);
// The game is ours, we have to do something!
if(mode == GAME_IS_OURS)
{
// TODO the next line should be made smarter!
next_move = opponent_last_move; // <- we block a vertical four in a row
mode = GAME_IS_THEIRS; // we've 'calculated' our move, now it's up to them!
move_count ++;
}
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
char control = 'A';
byte opponent_move_count = -1;
byte opponent_move = -1;
// message should equal 3 characters
if(howMany != 3)
return;
if(Wire.available())
control = Wire.read(); // receive byte as a character
if(Wire.available())
opponent_move_count = Wire.read(); // receive byte
if(Wire.available())
opponent_move = Wire.read(); // receive byte
// Let's check if the message was correctly received. We expect an "S" first:
if(control != 'S')
return;
// then we expect that the move_count is one more than we had:
if(opponent_move_count != move_count + 1)
return;
// We received a correct message, let's store it so we can calculate our next move
opponent_last_move = opponent_move;
move_count ++;
// The ball is in our park now :)
mode = GAME_IS_OURS;
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
// The opponent asks us to send our new move
// We'll send it only when we've calculated it
if(mode == GAME_IS_THEIRS)
{
Wire.write('M');
Wire.write(move_count);
Wire.write(next_move);
}
else
{
byte zero = 0;
// we're not ready yet!
Wire.write('A');
Wire.write(zero);
Wire.write(zero);
}
}