I'm attempting an I²C setup in which one master Arduino controls two slaves.
I'm using two 2000 ohm pullup resistors for the I²C and all boards are Arduino Duemilanoves. Both the I²C setup and the control setup function properly when disconnected from each other, but when connected the Arduinos become unresponsive as soon as the first wire.write
function is called. I cease to receive serial messages, the slave Arduinos stop receiving messages from the master, and I loose the ability to turn the system on and off using the button.
I've tried adding short delays after each wire.write
function and have used a variety of pullup resistors in an attempt to fix the problem, but nothing seems to work. How can I fix this?
Master Code:
#include <Wire.h>
int potPin1 = 0; // Select the input pin for the potentiometer
int potPin2 = 1;
int potVal1; // Variable to store the value coming from the sensor
int potVal2;
int times=0; // All the below variables are used to control an on-off button
int state=0;
int lastState=0;
boolean pot=false;
void setup()
{
pinMode(13, OUTPUT); //LED that turns on when system is activated
pinMode(3, INPUT); //Button that turns on system
Serial.begin(9600);
Wire.begin();
}
void loop(){
state=digitalRead(3);
if(state != lastState){
if(state==HIGH){
times++;
Serial.println(times);
}
else{
Serial.println("off");
}
}
lastState=state;
if(times%2 ==1)
{
turnPotOn();
}
else
{
turnPotOff();
}
//All code in the loop up to this point turns the system on and off at button press. //The following code corresponds to I²C based upon potentiometer readings.
if(pot==true)
{
potVal1 = analogRead(potPin1); // Read the value from the sensor
potVal2 = analogRead(potPin2);
if((potVal1>700) && (300<potVal2) && (potVal2<700))
{
arduino1_motor1();
}
else if ((potVal1<330) && (336<potVal2) && (potVal2<683))
{
arduino1_motor2();
}
else if ((potVal2>683) && (330<potVal1) && (potVal1<640))
{
arduino2_motor3();
}
else if ((potVal2<336) && (330<potVal1) && (potVal1<640))
{
arduino2_motor4();
}
else if ((potVal2<336) && (potVal1<330))
{
arduino12_motor24();
}
else if ((potVal2>683) && (potVal1>640))
{
arduino12_motor23();
}
else if ((potVal2>683) && (potVal1<640))
{
arduino11_motor23();
}
else if ((potVal2<336) && (potVal1>330))
{
arduino11_motor24();
}
else
{
arduino12_still();
}
}
else
{
// arduino1_still();
// arduino2_still();
Serial.println("OFF");
}
}
void turnPotOff()
{
digitalWrite(13, LOW);
pot=false;
}
void turnPotOn()
{
digitalWrite(13, HIGH);
pot=true;
}
void arduino1_motor1()
{
Wire.beginTransmission(5);
Wire.write('A');
Wire.endTransmission();
arduino2_still();
Serial.println("A1 in M1 d");
}
void arduino1_motor2()
{
Wire.beginTransmission(5);
Wire.write('B');
Wire.endTransmission();
arduino2_still();
Serial.println("A1 in m2 d");
}
void arduino12_still()
{
arduino1_still();
arduino2_still();
Serial.println("A1 & A2 stl");
}
void arduino2_motor3()
{
arduino1_still();
Wire.beginTransmission(10);
Wire.write('M3');
Wire.endTransmission();
Serial.println("A2 in M3 d");
}
void arduino2_motor4()
{
arduino1_still();
Wire.beginTransmission(10);
Wire.write('D');
Wire.endTransmission();
Serial.println("A2 in M4 d");
}
void arduino12_motor24()
{
Wire.beginTransmission(5);
Wire.write('B');
Wire.endTransmission();
Wire.beginTransmission(10);
Wire.write('D');
Wire.endTransmission();
Serial.println("A1 & A2 in M2 and M4 d");
}
void arduino12_motor23()
{
Wire.beginTransmission(5);
Wire.write('B');
Wire.endTransmission();
Wire.beginTransmission(10);
Wire.write('C');
Wire.endTransmission();
Serial.println("A1 & A2 in M2 and M3 d");
}
void arduino11_motor24()
{
Wire.beginTransmission(5);
Wire.write('A');
Wire.endTransmission();
Wire.beginTransmission(10);
Wire.write('D');
Wire.endTransmission();
Serial.println("A1 & A2 in M1 and M4 d");
}
void arduino11_motor23()
{
Wire.beginTransmission(5);
Wire.write('A');
Wire.endTransmission();
Wire.beginTransmission(5);
Wire.write('C');
Wire.endTransmission();
Serial.println("A1 & A2 in M1 and M3 d");
}
void arduino1_still()
{
Wire.beginTransmission(5);
Wire.write('S');
Wire.endTransmission();
}
void arduino2_still()
{
Wire.beginTransmission(10);
Wire.write('S');
Wire.endTransmission();
}
Slave 1 Code:
#include <Servo.h>
#include <Wire.h>
Servo myservo1;
Servo myservo2;
void setup()
{
Serial.begin(9600); // setup serial
myservo1.attach(2);
myservo2.attach(3);
Wire.begin(5);
Wire.onReceive(receiveEvent);
}
void loop()
{
}
void receiveEvent(int howMany)
{
while(Wire.available())
{
char v = Wire.read();
if(v == 'A')
{
myservo1.write(0);
myservo2.write(180);
Serial.println("Arduino 1 in motor 1 direction");
}
else if(v == 'B')
{
myservo1.write(180);
myservo2.write(0);
Serial.println("Arduino 1 in motor 2 direction");
}
else
{
myservo1.write(90);
myservo2.write(85);
Serial.println("Arduino 1 still");
}
}
}
Slave 2:
#include <Servo.h>
#include <Wire.h>
Servo myservo3;
Servo myservo4;
void setup()
{
Serial.begin(9600); // Setup serial
myservo3.attach(2);
myservo4.attach(3);
Wire.begin(10);
Wire.onReceive(receiveEvent);
}
void loop()
{
}
void receiveEvent(int howMany)
{
while(Wire.available())
{
char v = Wire.read();
if(v == 'C')
{
myservo3.write(0);
myservo4.write(180);
Serial.println("Arduino 2 in motor 3 direction");
}
else if(v == 'D')
{
myservo3.write(180);
myservo4.write(0);
Serial.println("Arduino 2 in motor 4 direction");
}
else
{
myservo3.write(90);
myservo4.write(90);
Serial.println("Arduino 2 still");
}
}
}
the "receive event" is inside an ISR, which doesn't exit until the event function returns
oh by the way, the AVR hardware holds the I2C bus in a frozen state until this event exits, also known as clock stretching
oh guess what, Wire didn't declare the FIFO variables as volatile, so even though he has while (Wire.available()), that becomes an infinite loop because available() will never change, because it's all happening in an interrupt and rxBufferIndex and rxBufferLength are not declared as volatile
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_volatile
this is one possible cause
insert angry rant about Arduino and its terrible libraries here
solution? use another library, the TWI utilities that "Wire.h" borrows can be used directly if you know how, and it's great, I use it all the time.
This might help you out a bit:
Okay so this is going to be a wall of text and I already closed the tab once on accident before posting so I might sound angry, because this "feature" of the Arduino is really bad and it will cost you $$ if you plug a 3.3v device into it. You're using the Wire Library which enables really bad 20k internal pullups on the SDA and SCL pins.
ON EACH ARDUINO. You have a situation where the total pullup resistance is now borked(screwed up). You need to do research on how to disable the internal pullups. I recommend modifying the library. For holistic reasons this sort of control should never be done in software. Double check his math on the required external pullup. The capacitance of each SCL/SDA pin on the Arduino should be 10pF.
Here is the formula direct from the ATMEGA datasheet
http://i.imgur.com/ZAByF.png
Here is the ATMEGA datasheet, see section 21 for the I2C section
http://www.atmel.com/Images/doc8161.pdf
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With