I am attempting to build a keyboard controller using a Leonardo(MASTER) and an MEGA(SLAVE)
The Leonardo is sensing the toggle switches and writing to the state to the Slave which turns on LEDS
Problem is the code is hanging on the Wire.write command
been trying for days to figure this out
here are the sketches for the Master and Slave
Why is it hanging up at the Write command?
hang can be seen on the serial monitor also
when the wire codes are omitted the sketch does not hang and serial monitor reports toggles correctly
/* Master Arduino code (Leonardo)
uses 2 Arduino's
1 set as master the other set as slave more less to double I/O pins
Master collects digital input button toggles and sends them to slave
via Wire.write using I2C method
Slave acts as the output indicator controlling multiple LEDS that indicate
which buttons on the master are toggled on or off
Also in addition the Master functions as a Keyboard relaying a keystroke
When the switches are togggled from either position.
*/
#include <Wire.h>
const int button1Pin = 3;
int button1State = 0;
int previousButton1State = HIGH; // for checking the state of button1
void setup() {
Serial.begin (9600);
Keyboard.begin ();
pinMode (button1Pin, INPUT_PULLUP);
Wire.begin();
// put your setup code here, to run once:
}
void loop() {
// Start of Button1
int button1State = digitalRead(button1Pin);
// if the button state has changed,
if ((button1State != previousButton1State)
// and it's currently pressed:
&& (button1State == HIGH)) {
Serial.println ("2Released");
Serial.println ("2NEXT");
delay(70);
Wire.beginTransmission(5);
Wire.write ('L');
Wire.endTransmission();
delay(70);
Serial.println ("2end");
//Keyboard.print ('L');
}
if ((button1State != previousButton1State)
// and it's currently pressed:
&& (button1State == LOW))
{
Serial.println ("1Pressed");
Serial.println ("1NEXT");
delay(70);
Wire.beginTransmission(5);
Wire.write ('H');
Wire.endTransmission();
Serial.println ("1end");
//Keyboard.print ('H');
}
previousButton1State = button1State;
// End of Button1
}
/* SLAVE Arduino CODE (MEGA2560)
uses 2 Arduino's
1 set as master the other set as slave more less to double I/O pins
Master collects digital input button toggles and sends them to slave
via Wire.write using I2C method
Slave acts as the output indicator controlling multiple LEDS that indicate
which buttons on the master are toggled on or off
Also in addition the Master functions as a Keyboard relaying a keystroke
When the switches are togggled from either position.
*/
#include <Wire.h>
void setup()
{
pinMode(13, OUTPUT);
digitalWrite (13, LOW);
Wire.begin(5);
Wire.onReceive(receiveEvent);
}
void loop()
{
}
void receiveEvent(int howMany)
{
while(Wire.available())
{
char c = Wire.read();
if(c == 'H')
{
digitalWrite(13, HIGH);
}
else if (c == 'L')
{
digitalWrite(13, LOW);
}
}
}
Nick Gammon is right, it is more likely that Wire.endTransmission() is hanging.
Could you print a message to the Serial monitor after Wire.write() with a delay(100).
The delay makes it possible that the message will be transmitted.
If your I2C is faulty, the Wire.endTransmission() could stop the sketch.
Did you power the Slave ?
And connect it like this:
SDA to SDA
SCL to SCL
GND to GND
Yes that is how I have it connected and sharing power.
The serial monitor stalls in the if statment between the curley's while the button is pressed, upon release of the button the rest of the information is processed picking up dead in the middle of the if curly statment.
This can be seen on the serial monitor. I have also switched the mega(slave) to a uno for testing to to see if the i2c was faulty. However another master sketch I have where I just type H or L into the serial monitor and send turns the LEDs on on the slave just fine but thats not what I'm shooting for. I need the command sent on button press and release only 1 time per press or release.
Yes the i2c is working. As I was saying the stall is happening in between the brackets of the if true run these codes statement. If the wire is omitted altogether the sketch runs fine using the current sketches delay for debouncing. If the wire writes is taken out of the run these statements if true the sketch runs as technically intended and button toggles work fine and read out as intended on serial monitor. On debouncing I really need to read up some more to fully understand the purpose of it but I'm thinking debouncing is not the issue here since the sketch run fine without wire codes.
I still don't understand why it would run if the Wire is omitted. But this time I took a closer look at your sketches.
You declared variable button1State twice.
I would use the if-statements in a different way.
Pin 3 is the SCL of the I2C bus for the Arduino Leonardo board. You have to use another pin. http://arduino.cc/en/Main/arduinoBoardLeonardo
In the receiveEvent() it is possible to use the "howMany" instead of the the Wire.available.
I made those changes, and I used two Arduino Uno boards with I2C. This works.
Master
/* Master Arduino code (Leonardo)
uses 2 Arduino's
1 set as master the other set as slave more less to double I/O pins
Master collects digital input button toggles and sends them to slave
via Wire.write using I2C method
Slave acts as the output indicator controlling multiple LEDS that indicate
which buttons on the master are toggled on or off
Also in addition the Master functions as a Keyboard relaying a keystroke
When the switches are togggled from either position.
*/
#include <Wire.h>
const int button1Pin = 4; // pin 4 is not the I2C bus for the Leonardo
int previousButton1State = HIGH; // for checking the state of button1
void setup() {
Serial.begin (9600);
while(!Serial); // wait for the serial monitor for the Leonardo
Serial.println(F("Master started"));
Keyboard.begin (); // only available in the Leonardo
pinMode (button1Pin, INPUT_PULLUP);
Wire.begin();
// put your setup code here, to run once:
}
void loop() {
// Start of Button1
int button1State = digitalRead(button1Pin);
// check if the button state has changed.
if (button1State != previousButton1State) {
if( button1State == HIGH) {
Serial.println ("2Released");
Serial.println ("2NEXT");
Wire.beginTransmission(5);
Wire.write ('L');
Wire.endTransmission();
Serial.println ("2end");
//Keyboard.print ('L');
}
else {
Serial.println ("1Pressed");
Serial.println ("1NEXT");
Wire.beginTransmission(5);
Wire.write ('H');
Wire.endTransmission();
Serial.println ("1end");
//Keyboard.print ('H');
}
previousButton1State = button1State;
}
// End of Button1
delay(50); // slow down loop
}
Slave
/* SLAVE Arduino CODE (MEGA2560)
uses 2 Arduino's
1 set as master the other set as slave more less to double I/O pins
Master collects digital input button toggles and sends them to slave
via Wire.write using I2C method
Slave acts as the output indicator controlling multiple LEDS that indicate
which buttons on the master are toggled on or off
Also in addition the Master functions as a Keyboard relaying a keystroke
When the switches are togggled from either position.
*/
#include <Wire.h>
void setup()
{
Serial.begin(9600);
Serial.println(F("Slave started"));
pinMode(13, OUTPUT);
digitalWrite (13, LOW);
Wire.begin(5);
Wire.onReceive(receiveEvent);
}
void loop()
{
}
void receiveEvent(int howMany)
{
// we are expecting just a single byte
if (howMany == 1)
{
char c = Wire.read();
if (c == 'H')
{
digitalWrite(13, HIGH);
}
else if (c == 'L')
{
digitalWrite(13, LOW);
}
}
}
Nick, thanks for the clarification that Wire.write ("B1H1"); is indeed the correct way to send the 4 byte string, but there is something going on in the slave sketch thats only seeing 1 byte instead of the 4. i attempted to change
the if (howMany == 1) to (howMany == 4) but i still cant figure it out. serial monitor has been showing me everything but the correct 4 bytes all day
here is the slave code at this current moment
#include <Wire.h>
const int button1LedGreen = 13;
const int button1LedRed = 12;
const int button2LedGreen = 11;
const int button2LedRed = 10;
void setup()
{
Serial.begin(9600);
//Serial.println(F("Slave started"));
Serial.println ("Slave Started");
pinMode(button1LedGreen, OUTPUT); // output for LED1 from toggle Button 1 ON
pinMode(button1LedRed, OUTPUT); // output for LED2 from toggle Button 1 OFF
pinMode(button2LedGreen, OUTPUT); // output for LED2 from toggle Button 2 ON
pinMode(button2LedRed, OUTPUT); // output for LED2 from toggle Button 2 OFF
digitalWrite (button1LedGreen, LOW);
digitalWrite (button1LedRed, LOW);
digitalWrite (button2LedGreen, LOW);
digitalWrite (button1LedRed, LOW);
Wire.begin(5);
Wire.onReceive(receiveEvent);
}
void loop()
{
}
void receiveEvent(int howMany)
{
// we are expecting just a single byte
if (howMany == 1)
{
char c = Wire.read();
// Start of LED1 for Button1
if (c == 'B1H1')
{
digitalWrite(button1LedGreen, HIGH);
digitalWrite(button1LedRed, LOW);
Serial.println ("Button1Pressed");
Serial.println (c);
}
if (c == 'B1HL')
{
digitalWrite(button1LedRed, HIGH);
digitalWrite(button1LedGreen, LOW);
Serial.println ("Button1Depressed");
Serial.println (c);
// End of LED1 for Button1
}
// Start of LED2 for Button2
if (c == 'B2H1')
{
digitalWrite(button2LedGreen, HIGH);
digitalWrite(button2LedRed, LOW);
Serial.println ("Button2Pressed");
Serial.println (c);
}
if (c == 'B2L1')
{
digitalWrite(button2LedRed, HIGH);
digitalWrite(button2LedGreen, LOW);
Serial.println ("Button2Depressed");
Serial.println (c);
// End of LED2 for Button2
}
}
}
The receiveEvent() is called from an interrupt from the Wire library. It is not allowed to use the Serial functions inside the receiveEvent().
The variable 'c' is a single character, it can hold just one character.
please shed some insight on how i should go about fixing the code here are the 2 most current master and slave sketches
Master
/* Master Arduino code (Leonardo)
uses 2 Arduino's
1 set as master the other set as slave more less to double I/O pins
Master collects digital input button toggles and sends them to slave
via Wire.write using I2C method
Slave acts as the output indicator controlling multiple LEDS that indicate
which buttons on the master are toggled on or off
Also in addition the Master functions as a Keyboard and joystick relaying keystrokes
When the switches are togggled from either position.
*/
#include <Wire.h>
const int button1Pin = 4; // pin 4 is not the I2C bus for the Leonardo
const int button2Pin = 5;
const int JoyDown1ThrottlePin = 8;
const int JoyUp1ThrottlePin = 9;
int previousJoyUp1ThrottleState = HIGH;
int previousJoyDown1ThrottleState = HIGH;
int previousButton1State = HIGH; // for checking the state of button1
int previousButton2State = HIGH; // for checking the state of button2
void setup() {
Serial.begin (9600);
//while(!Serial); // wait for the serial monitor for the Leonardo
Serial.println(F("Master started"));
Keyboard.begin (); // only available in the Leonardo
pinMode (button1Pin, INPUT_PULLUP);
pinMode (button2Pin, INPUT_PULLUP);
pinMode (JoyUp1ThrottlePin, INPUT_PULLUP);
pinMode (JoyDown1ThrottlePin, INPUT_PULLUP);
Wire.begin();
// put your setup code here, to run once:
}
void loop() {
// Start of Joy1UpThrottle
int JoyUp1State = digitalRead(JoyUp1ThrottlePin);
// check if the button state has changed.
if (JoyUp1State != previousJoyUp1ThrottleState) {
if( JoyUp1State == HIGH) {
Serial.println ("JoyUpThrottleAxisCentered");
//Wire.beginTransmission(5); //REMoved not controlling a LED here
//Wire.write ('S'); //REMoved not controlling a LED here
//Wire.endTransmission(); //REMoved not controlling a LED here
//Keyboard.release (KEY_LEFT_SHIFT);
}
else {
Serial.println ("Joy1UpThrottleUp");
//Wire.beginTransmission(5); //REMoved not controlling a LED here
//Wire.write ('W'); //REMoved not controlling a LED here
//Wire.endTransmission(); //REMoved not controlling a LED here
//Keyboard.press (KEY_LEFT_SHIFT);
}
previousJoyUp1ThrottleState = JoyUp1State;
}
// End of JoyUp1Throttle
// Start of Joy1DownThrottle
int JoyDown1State = digitalRead(JoyDown1ThrottlePin);
// check if the button state has changed.
if (JoyDown1State != previousJoyDown1ThrottleState) {
if( JoyDown1State == HIGH) {
Serial.println ("Joy_Y_Axis_Centered");
//Wire.beginTransmission(5); //REMoved not controlling a LED here
//Wire.write ('S'); //REMoved not controlling a LED here
//Wire.endTransmission(); //REMoved not controlling a LED here
//Keyboard.release (KEY_LEFT_CTRL);
}
else {
Serial.println ("Joy_Y_Axis_+");
//Wire.beginTransmission(5); //REMoved not controlling a LED here
//Wire.write ('W'); //REMoved not controlling a LED here
//Wire.endTransmission(); //REMoved not controlling a LED here
//Keyboard.press (KEY_LEFT_CTRL);
}
previousJoyDown1ThrottleState = JoyDown1State;
}
// End of JoyDown1Throttle
// Start of Button1
int button1State = digitalRead(button1Pin);
// check if the button state has changed.
if (button1State != previousButton1State) {
if( button1State == HIGH) {
Serial.println ("Button1Released");
Wire.beginTransmission(5); // Assign a destination
Wire.write ("B1H1"); // Queing into memory to send 1 byte
Wire.endTransmission(); //Transmit the byte
//Keyboard.print ('Later_Defined');
}
else {
Serial.println ("Button1Pressed");
Wire.beginTransmission(5); // Assign a destination
Wire.write ("B1HL"); // Queing into memory to send 1 byte
Wire.endTransmission(); //Transmit the byte
//Keyboard.print ('Later_Defined');
}
previousButton1State = button1State;
}
// End of Button1
delay(50); // slow down loop
// Start of Button2
int button2State = digitalRead(button2Pin);
// check if the button state has changed.
if (button2State != previousButton2State) {
if( button2State == HIGH) {
Serial.println ("Button2Released");
Wire.beginTransmission(5); // Assign a destination
Wire.write ("B2HL"); // Attempt at Queing 2 bytes
Wire.endTransmission(); //Transmit the bytes
//Keyboard.print ('Later_Defined');
}
else {
Serial.println ("Button2Pressed");
Wire.beginTransmission(5); // Assign a destination
Wire.write ("B2H1"); // Attempt at Queing 2 bytes
Wire.endTransmission(); //Transmit the bytes
//Keyboard.print ('Later_Defined');
}
previousButton2State = button2State;
}
// End of Button2
}
Slave
/* SLAVE Arduino CODE (MEGA2560)
uses 2 Arduino's
1 set as master the other set as slave more less to double I/O pins
Master collects digital input button toggles and sends them to slave
via Wire.write using I2C method
Slave acts as the output indicator controlling multiple LEDS that indicate
which buttons on the master are toggled on or off
Also in addition the Master functions as a Keyboard relaying a keystroke
When the switches are togggled from either position.
*/
#include <Wire.h>
const int button1LedGreen = 13;
const int button1LedRed = 12;
const int button2LedGreen = 11;
const int button2LedRed = 10;
void setup()
{
Serial.begin(9600);
//Serial.println(F("Slave started"));
Serial.println ("Slave Started");
pinMode(button1LedGreen, OUTPUT); // output for LED1 from toggle Button 1 ON
pinMode(button1LedRed, OUTPUT); // output for LED2 from toggle Button 1 OFF
pinMode(button2LedGreen, OUTPUT); // output for LED2 from toggle Button 2 ON
pinMode(button2LedRed, OUTPUT); // output for LED2 from toggle Button 2 OFF
digitalWrite (button1LedGreen, LOW);
digitalWrite (button1LedRed, LOW);
digitalWrite (button2LedGreen, LOW);
digitalWrite (button1LedRed, LOW);
Wire.begin(5);
Wire.onReceive(receiveEvent);
}
void loop()
{
}
void receiveEvent(int howMany)
{
// we are expecting just a single byte
if (howMany == 1)
{
byte c = Wire.read();
Serial.print (c);
// Start of LED1 for Button1
if (c == 'B1H1')
{
digitalWrite(button1LedGreen, HIGH);
digitalWrite(button1LedRed, LOW);
Serial.println ("Button1Pressed");
Serial.println (c);
}
if (c == 'B1HL')
{
digitalWrite(button1LedRed, HIGH);
digitalWrite(button1LedGreen, LOW);
Serial.println ("Button1Depressed");
Serial.println (c);
// End of LED1 for Button1
}
// Start of LED2 for Button2
if (c == 'B2H1')
{
digitalWrite(button2LedGreen, HIGH);
digitalWrite(button2LedRed, LOW);
Serial.println ("Button2Pressed");
Serial.println (c);
}
if (c == 'B2L1')
{
digitalWrite(button2LedRed, HIGH);
digitalWrite(button2LedGreen, LOW);
Serial.println ("Button2Depressed");
Serial.println (c);
// End of LED2 for Button2
}
}
}
Four bytes are transmitted, therefor the parameter howMany in the Slave will be 4.
You have to use 4 times the Wire.read() or read them all 4 at once with Wire.readBytes().
The four bytes can be put into a string (character array) and that can be tested with strcmp().
Or every byte can be tested on its own.
Thanks both after thinking about what you both said, I finally got it after 13 hours of trial and error. ill be a pro in no time.. the method you suggested Peter is working so far
this is how i have fixed it so far trial and error somewhat to say
so far button 2 is working
partial master code
Wire.beginTransmission(5); // Assign a destination
Wire.write ('B');
Wire.write ('2');
Wire.write ('L'); // successful attempt at Queing 3 bytes
Wire.endTransmission(); //Transmit the bytes
partial slave code
if (howMany == 3)
{
char c = Wire.read();
char d = Wire.read();
char b = Wire.read();
int x = (c + b + d);
Serial.print (x);
// Start of LED1 for Button1
if (x == 191)
{
digitalWrite(button1LedGreen, HIGH);
digitalWrite(button1LedRed, LOW);
Serial.println ("Button1Pressed");
Serial.println (c);
}
if (x == 187)
{
digitalWrite(button1LedRed, HIGH);
digitalWrite(button1LedGreen, LOW);
Serial.println ("Button1Depressed");
Serial.println (c);
// End of LED1 for Button1
}
// Start of LED2 for Button2
if (x == 192)
//int led2stat1 = (c + d)
//if (led2stat1 == 'B0')
{
digitalWrite(button2LedGreen, HIGH);
digitalWrite(button2LedRed, LOW);
Serial.println ("Button2Pressed");
Serial.println (c);
Serial.println (d);
}
if (x == 188)
{
digitalWrite(button2LedRed, HIGH);
digitalWrite(button2LedGreen, LOW);
Serial.println ("Button2Depressed");
Serial.println (x);
Serial.println (c);
Serial.println (d);
// End of LED2 for Button2
}
Did you use a different language before using 'c' and 'c++' ?
Could you google for : strcmp
The 'strcmp' function is used to compare a string (character array).
Please remove the Serial.println() from the recevieEvent().