Using Interrupts for push buttons with I2C

Hello,
I'm currently making an RC submarine for a mechatronics project. I'm using two arduinos where one handles the inputs from the user while the others drives the appropriate motors. Thus, one will be on the sub and the other on the remote. I'm using I2C as the communication protocol between the two devices. My problem is that I'm trying to use the two interrupt pins on the remote arduino to control one of the motors. I've got three motors, and I'm controlling the direction of each one. I was initially using pulling, which worked fine, but I noticed that the motors got weaker as continued to add more motors (resulted in more if statements in the code). Thus, I'm trying to now control one of three motors via the two interrupt pins rather than through polling. The basic idea is that as long as the push button is pressed down (digital pin value of LOW) the motor will be turned on. Thus, I was thinking the mode of the interrupt would be LOW but I have been unsuccessful in getting it work so far. Any help would be greatly appreciated.

// Master code
#include <Wire.h>

// Assigned all appropriate variables for each pin to be used
int buttonMotorAForward = 9;
int buttonMotorAReverse = 8;
int buttonMotorBForward = 7;
int buttonMotorBReverse = 6;
int buttonBallastRise = 10;
int buttonBallastSink = 11;

void setup()
{
// Assign appropriate I/O 
pinMode(buttonMotorAForward, INPUT);
pinMode(buttonMotorAReverse, INPUT);
pinMode(buttonMotorBForward, INPUT);
pinMode(buttonMotorBReverse, INPUT);
pinMode(buttonBallastSink, INPUT);
pinMode(buttonBallastRise, INPUT);

// Enable pull resistors for button pins
digitalWrite(buttonMotorAForward, HIGH);
digitalWrite(buttonMotorAReverse, HIGH);
digitalWrite(buttonMotorBForward, HIGH);
digitalWrite(buttonMotorBReverse, HIGH);
digitalWrite(buttonBallastSink, HIGH);
digitalWrite(buttonBallastRise, HIGH);


Wire.begin();
}

void loop()
{

// Forward
if (digitalRead(buttonMotorAForward) == LOW && digitalRead(buttonMotorBForward) == LOW)
{
  Wire.beginTransmission(5);
  Wire.write('A');
  Wire.endTransmission();
}

// Reverse
else if (digitalRead(buttonMotorAReverse) == LOW && digitalRead(buttonMotorBReverse) == LOW)
{
  Wire.beginTransmission(5);
  Wire.write('B');
  Wire.endTransmission();

}

// Spin right
else if (digitalRead(buttonMotorAForward) == LOW && digitalRead(buttonMotorBReverse) == LOW)
{
  Wire.beginTransmission(5);
  Wire.write('C');
  Wire.endTransmission();
}

// Spin left
else if (digitalRead(buttonMotorAReverse) == LOW && digitalRead(buttonMotorBForward) == LOW)
{ 
  Wire.beginTransmission(5);
  Wire.write('D');
  Wire.endTransmission();
}

else 
{ Wire.beginTransmission(5);
  Wire.write('K');
  Wire.endTransmission();
} 
}

// Slave code
#include <Wire.h>

// Assigned all appropriate variables for each pin to be used
int AIN1 = 7;
int AIN2 = 6;
int BIN1 = 5;
int BIN2 = 4;
int PWMA = 11;
int PWMB = 3;
int ballast1 = 12;
int ballast2 = 13;
int PWMballast = 9;

void setup()
{
pinMode(AIN1, OUTPUT);
pinMode(AIN2, OUTPUT);
pinMode(BIN1, OUTPUT);
pinMode(BIN2, OUTPUT);
pinMode(10, OUTPUT);
pinMode(PWMA, OUTPUT);
pinMode(PWMB, OUTPUT);
pinMode(ballast1, OUTPUT);
pinMode(ballast2, OUTPUT);
digitalWrite(AIN1, LOW);
digitalWrite(AIN2, LOW);
digitalWrite(BIN1, LOW);
digitalWrite(BIN2, LOW);
digitalWrite(ballast1, LOW);
digitalWrite(ballast2, LOW);
analogWrite(PWMA, 0);
analogWrite(PWMB, 0);
analogWrite(PWMballast, 0);
Wire.begin(5);
Wire.onReceive(receivedEvent);
}

void loop()
{}

void receivedEvent(int howMany)
{
while (Wire.available())
{
  char C = Wire.read();
  
  if (C == 'A')
  {
    digitalWrite(10, HIGH);
    digitalWrite(AIN1, HIGH);
    digitalWrite(AIN2, LOW);
    digitalWrite(BIN1, LOW);
    digitalWrite(BIN2, HIGH);
    analogWrite(PWMA, 255);
    analogWrite(PWMB, 255);
    digitalWrite(ballast1, LOW);
    digitalWrite(ballast2, LOW);
    analogWrite(PWMballast, 0);
  }
  
  else if (C == 'B')
  {
    digitalWrite(10, HIGH);
    digitalWrite(AIN1, LOW);
    digitalWrite(AIN2, HIGH);
    digitalWrite(BIN1, HIGH);
    digitalWrite(BIN2, LOW);
    analogWrite(PWMA, 255);
    analogWrite(PWMB, 255);
    digitalWrite(ballast1, LOW);
    digitalWrite(ballast2, LOW);
    analogWrite(PWMballast, 0);
  }
  
  else if (C == 'C')
  {
    digitalWrite(10, HIGH);
    digitalWrite(AIN1, HIGH);
    digitalWrite(AIN2, LOW);
    digitalWrite(BIN1, HIGH);
    digitalWrite(BIN2, LOW);
    analogWrite(PWMA, 255);
    analogWrite(PWMB, 255);
    digitalWrite(ballast1, LOW);
    digitalWrite(ballast2, LOW);
    analogWrite(PWMballast, 0);
  }
  
  else if (C == 'D')
  {
    digitalWrite(10, HIGH);
    digitalWrite(AIN1, LOW);
    digitalWrite(AIN2, HIGH);
    digitalWrite(BIN1, LOW);
    digitalWrite(BIN2, HIGH);
    analogWrite(PWMA, 255);
    analogWrite(PWMB, 255);
    digitalWrite(ballast1, LOW);
    digitalWrite(ballast2, LOW);
    analogWrite(PWMballast, 0);
  }
  else
  {
    digitalWrite(10, LOW);
    digitalWrite(AIN1, LOW);
    digitalWrite(AIN2, LOW);
    digitalWrite(BIN1, LOW);
    digitalWrite(BIN2, LOW);
    analogWrite(PWMA, 0);
    analogWrite(PWMB, 0);
  }
  
}
}

Please use [ code ] tags. You can go back and edit your message.

As Morgan said, you really do need to edit and place your code within code tags.
(Edit, select your code, then press the </> button.)
Otherwise manually like this:-

[code]Paste your code here[/code]
It will appear in a block like this

Shouldn't the first parameter in each of the below be the interrupt numbers, rather than the pin numbers:-
(Ignore this if you're using a Due - you didn't say.)

attachInterrupt(buttonBallastRise, rise, LOW);
attachInterrupt(buttonBallastSink, sink, LOW);

If it's a UNO or Mega2560, it should be:-

attachInterrupt(0, rise, LOW);
attachInterrupt(1, sink, LOW);

Have a read of the documentation on 'attachInterrupt()' in 'Reference'.

Edit: Just looking further, I see that you do a 'Wire.write()' in your ISR routines. I'm not sure, but that might not be a good idea. Does 'Wire.write()' use interrupts? If so, you should just flag the event in each ISR, then do the actual write in 'loop()'.

Why use interrupts. Polling, used properly, would almost certainly work.

but I noticed that the motors got weaker as continued to add more motors (resulted in more if statements in the code).

What do you mean by that? I usually associate this 'weaker' with 'insufficient power to drive the motors' and hence a power issue. I might be wrong though.

As the motors are controlled in the slave, I wonder why you think that using interrupts in the master code will solve the problem? You send one command to the slave and the slave does a few things; and that is it. Next you send another command, slave processes it and (again) that is it.

Side note:
As far as I can figure it out, Wire uses interrupts. I wonder if it's a good idea to send data via Wire in an interrupt routine. But this is not my area of expertise :wink:

UKHeliBob:
Why use interrupts. Polling, used properly, would almost certainly work.

Ha. Yeah, you're quite right Bob. I forgot to mention that. :blush:

OldSteve:
If it's a UNO or Mega2560, it should be:-

attachInterrupt(0, rise, LOW);

attachInterrupt(1, sink, LOW);

Actually,

attachInterrupt(digitalPinToInterrupt(buttonBallastRise), rise, LOW);
attachInterrupt(digitalPinToInterrupt(buttonBallastSink), sink, LOW);

is better.

@rhumphrey : Please edit your post, select the code, and put it between [code] ... [/code] tags.

You can do that by hitting the "Code" icon above the posting area. It is the first icon, with the symbol: </>

Please use code tags.

Read this before posting a programming question


void rise()

{
 Wire.beginTransmission(5);
 Wire.write('I');
 Wire.endTransmission();
}

I don't think this will work. Inside an ISR interrupts are turned off, and I'm pretty sure that Wire.endTransmission() needs interrupts to be on.

I suggest reworking.

... but I noticed that the motors got weaker as continued to add more motors (resulted in more if statements in the code)

More power is required, not more "if" statements.

aarg:
Actually,

attachInterrupt(digitalPinToInterrupt(buttonBallastRise), rise, LOW);

attachInterrupt(digitalPinToInterrupt(buttonBallastSink), sink, LOW);



is better.

Good point. That way it's clear which pin the interrupt relates to.

I don't particularly like LOW interrupts. You know they keep firing while the pin is LOW don't you? This can drag the processor speed right down.

It was said before. Can your power supply supply enough current to both motors at the same time?

Since you are continuing on with this, can you not go back and put code tags in, as was requested several times?

Alright, thanks for all the helpful advice everyone. Sorry about not using code tags. This is all new to me. I got it work just using polling. There were a few "if" statements that should have been "else if". Once I changed those, it seemed to fix the problem. The only issue I see now is that the two thrust motors slow down significantly when operating together (cases A-D in the code - I've only included those four cases in the code). I'm not sure if there's a remedy for this. I'm using the TB6612FNG as my motor driver chip if that changes anything.

sterretje:
It was said before. Can your power supply supply enough current to both motors at the same time?

I used an external DC power supply in lab to power the motors at 12V (the voltage rating the pump being used). I'm having an eight pack AA battery holder come in today which will supply the 12 V for all the motors. It'll also be used to power the arduino (either through its power jack or the Vin pin). When at home, I just operate everything using the 5V pin from the Uno. At 12 V, the thrust motors perform better but still significantly slow down when they're both being run together. Additionally, the motors will make a high pitch sound which is not the case for when they're being run individually.

Did you remove your earlier post? My reply #11 now doesn't make sense.

Your Arduino can more than likely not deliver enough power (and we're talking current, not voltage). I don't know enough about batteries to be able to give a solid advise.

rhumphrey:
I got it work just using polling. There were a few "if" statements that should have been "else if". Once I changed those, it seemed to fix the problem.

Of course you did.

Whenever someone posts a topic with "Interrupts" and "push buttons", I instinctively know what the problem is. :grinning: