Mega 2560 runs stepper while uno runs HC-SR04 ultrasonic senor until condition

Hey everyone,
I’m new to the arduino forums but relatively experienced with arduino. I haven’t ever asked a question in the forums because I hate bothering people with a question that I can figure out myself or has already been answered. This time I’ve hit a wall and I can’t seem to solve this problem on my own with research. This might be trivial and I might be just over looking something…

I’m trying to get my master mega to run a stepper motor while through I2C its slave an Uno controls an ultrasonic sensor, then when a condition is met with the ultrasonic sensor on the Uno it would let the master know, which the master would then know to stop the stepper motor and continue on to the next program.

What I have been able to accomplish is get the master to run the stepper and I’ve gotten the ultrasonic sensor to activate on the salve, but I don’t know how to make it pulse continually in the receiveEvent on the Slave until a condition is met.

Also I do realize that the Mega is completely capable of running several sensors and motors, for my project it has to be simultaneous and the pulses being fit in between steps slows the motor down way too much. So i figured have a slave run the processing for the sensor while the master continues the stepper movement. thank you for any help.

Master code

//Master Code
#include <Wire.h>
#include<AccelStepper.h>
// the stepper that the master will run while the slave controls the ultrasonic sensor
AccelStepper stepper1(AccelStepper::DRIVER, 9, 8);

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
Wire.begin();
delay(100);
Wire.beginTransmission(5);//slave is at address (5)
Wire.write('H');//tells slave to start pinging the sensor
Wire.endTransmission();
}

void loop() {
  // put your main code here, to run repeatedly:


    stepper1.setMaxSpeed(2400.0);// stepper starts moving while slave is pinging
    stepper1.setAcceleration(4200.0);
    stepper1.moveTo(7000);
    stepper1.run();
 


}

Slave Code

// slave i2c
#include<Wire.h>

int Led = 10;//led to indicate ultrasonic measurements have started
int trigPin = 4; //trigger pin
int echoPin = 5;// echo pin


void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
Wire.begin(5);
delay(100); //I've read that putting a small delay in helps?
Wire.onReceive(receiveEvent);
pinMode(trigPin,OUTPUT);
pinMode(echoPin,INPUT);
pinMode(Led,OUTPUT);
digitalWrite(Led,LOW); //set led off before process starts

}

void loop() {
  // put your main code here, to run repeatedly:
}
void receiveEvent(int howMany)
{
  while(Wire.available())
  {
    char c = Wire.read();  //How can I make the following if statement run until a condition is met?
    if(c=='H')
    {
 
  digitalWrite(Led,HIGH);
 
  long duration,distance,durationB,distanceB;
  digitalWrite(trigPin,HIGH);//first ultrasonic measurement start
  
  delayMicroseconds(1000);
  digitalWrite(trigPin,LOW);
  duration=pulseIn(echoPin,HIGH);
  distance=((duration/2)/29.1); //first distance reading
 
  Serial.print(distance);
  Serial.println("CM");
  delay(5000);
  digitalWrite(Led,LOW); //turn off led to show that second measurement has started

  digitalWrite(trigPin,HIGH);
  delayMicroseconds(1000);
  digitalWrite(trigPin,LOW);
  durationB=pulseIn(echoPin,HIGH);
  distanceB=((durationB/2)/29.1);
  
  Serial.print(distanceB);
  Serial.println("CM");
  delay(5000);
  digitalWrite(Led,HIGH);// led on to show last measurement has been taken

  Serial.print(distance-distanceB); 
// in the end I'm trying to get the senor to keep pinging until the 2 distances
// are different by a value I set. The math programming is not the issue, its how to
// keep this pinging until condition is met and then writing back to the master
// so it will stop the stepper motor.
// a side note, I noticed delay() is way off in here, is that because this functions like an ISR?
  

  }



 }
  }

I’m trying to get my master mega to run a stepper motor while through I2C its slave an Uno controls an ultrasonic sensor, then when a condition is met with the ultrasonic sensor on the Uno it would let the master know, which the master would then know to stop the stepper motor and continue on to the next program.

You need to rethink which device is master, and which is slave.

A slave can NOT initiate communication with the master, and can not keep a channel open. It can only respond to a request for data from the master, and can only supply a response one time.

but I don’t know how to make it pulse continually in the receiveEvent on the Slave until a condition is met.

I’m not sure what you mean by “pulse continually”, but the receiveEvent() function is called once when the slave provides a response. You can’t stay in the receiveEvent() function reading data continuously.

The receiverEvent() function is an interrupt service routine. ISRs need to be lightening fast.

I have to say Paul what an Honor it is to get a response from you, in my recent attempts at trying to solve this problem by researching forums on this, I learned a lot by coming across your responses to peoples questions.

You need to rethink which device is master, and which is slave.

A slave can NOT initiate communication with the master, and can not keep a channel open. It can only respond to a request for data from the master, and can only supply a response one time

I think I may have worded it wrong which would lead you to say that.
The master would initiate the communication with the slave. So once the master reaches the code to start the stepper motor, it would immediately initiate the communication with the slave and send the event for the slave to measuring distances from the ultrasonic sensor. Once the slave reads a change in distance that I set, then it sends a signal back to the master, then when the master reads that signal it will know to stop.

Maybe this is something I don't understand about I2C communication with Masters and Slaves. To put this another way: Say you are operating a hand crank Paul and this hand crank moves a basket sideways that I am in. So you (being the master) start turning that hand cranks that moves my basket sideways along a wall and just as you start turning the hand crank you tell me "Hey Scooby, (H)." Now I know that hearing the letter (H) means look at the wall and when I don't see a wall send (C) back. so i sit there in my basket looking at the wall while i move along it in my basket thinking to myself yup there's still a wall over and over again and then all of a sudden there is no wall and I'm looking into an empty room. I would then immediately yell over to you "Hey Paul, (C)" which you would then know to stop. Now I'm not telling you to stop because you are the master, you just told me (the Slave) to do function (H) and I know to do (H) until there is no wall then yell to you (C), Upon hearing that I said (C) you know to stop turning the hand crank.

I don't know if that helped or not.

Generally, a master reads a register from a slave.
In your case, the master could keep reading the same register, the slave would just put different data into it to be read out when conditions at the slave end changed.

Read thru Nick Gammon’s page on I2C and see if that makes more sense
http://www.gammon.com.au/i2c

So once the master reaches the code to start the stepper motor, it would immediately initiate the communication with the slave and send the event for the slave to measuring distances from the ultrasonic sensor. Once the slave reads a change in distance that I set, then it sends a signal back to the master, then when the master reads that signal it will know to stop.

The master will make one request? Then, it will interrupt what the slave is doing, and the slave will provide ONE response.

If that is not what you want, the master will need to keep asking, until it gets an answer it likes.

The slave will NOT be doing a measurement in the ISR that is triggered. It will have to be measuring continuously. In the ISR, it will simply return the most recent value.

The master will make one request? Then, it will interrupt what the slave is doing, and the slave will provide ONE response.

If that is not what you want, the master will need to keep asking, until it gets an answer it likes.

ahhh I think we are getting somewhere. So the master/slave set up can either do (1) have the master tell the slave to start gathering measurements and then at some point ask for info from the slave and the slave will tell it what ever it knows at that point.

or case (2) the master can signal the slave to start measuring and stay in constant contact with the slave until the salve measures something the master is looking for?

If my 2 statements above are correct, neither of those options would work for my application correct?

(1) would not work because having the master ask for info from the slave at a random point, would be completely random. the slave might or might not be at the right point, but most likely it wont be.

and
(2) the master would stay in constant contact with the slave, so when the right measurement was retrieved by the slave the master would know, but the issue there for my application is the same as with the master running both the motor and the ultrasonic sensor together. The steps would be slowed down because after every step the master would be contacting the slave asking for info correct?

Now as I was just typing that above something occurred to me, which might be a solution for me... What if I reversed what the master and slave operate. So instead of the master operating the stepper motor and telling the slave to start taking measurements. If I had the master start operating the ultrasonic sensor itself and immediately telling the slave to start operating the stepper motor, then when the master saw the measurement it was looking for, it then signaled the slave to stop the stepper motor? that way the master doesnt have to ask the slave for info all the time. the master just tells the slave go, while the master itself checks its own measurements and then tells the slave stop. That should work perfectly right? and if it does.. man do I feel stupid, because I swear I went down that path in my head before posting to the forum but now I don't see why that wouldn't work?

Also CrossRoads thanks for the response, i'll head over and check out that link to learn some more stuff.

Maybe my idea to switch things around and have the master run the sensor and the slave run the stepper was wrong but I don’t know why…

I even went back to the basics, I took out the sensor all together and Just set up the master to send (H) to the slave and when the Slave received (H) it would then just step the stepper motor and that’s it. Yet I couldn’t get it to even do that. What am I missing here?
I tried the identical set up but to simplify it even more I had the slave just turn on and off and LED, which worked fine. Yet if I put any kind of stepper code in nothing would happen, I can hear the coils tense the motor up but thats it. I even tried putting the LED on then stepping the motor then putting the LED off, but the LED just stayed on. In case the stepper code that wasn’t running was blocking, I tried it back with the non blocking AccelStepper library. Still no movement from the stepper.

What am I doing wrong here?
//master code

#include<Wire.h>
#include<AccelStepper.h>
int trigPin = 6; //trigger pin
int echoPin = 5;// echo pin
void setup() {
Serial.begin(9600);
Wire.begin();
pinMode(trigPin,OUTPUT);
pinMode(echoPin,INPUT);
Wire.beginTransmission(5);//slave is at address (5)
Wire.write('H');//tells slave to start running stepper motor
Wire.endTransmission();
}

void loop() {


    }

//slave code

#include<Wire.h>
#include<AccelStepper.h>
AccelStepper stepper1(AccelStepper::DRIVER,10,11);
int ledPin = 13;
void setup() {
Wire.begin(5);
Wire.onReceive(receiveEvent);
pinMode(ledPin,OUTPUT);
digitalWrite(ledPin,LOW);


}

void loop() {

}



void receiveEvent(int howMany)
{
  while(Wire.available())
  {
    char c = Wire.read();
    if(c =='H')
    {
      digitalWrite(ledPin,HIGH);
      stepper1.setMaxSpeed(700);
      stepper1.setAcceleration(500);
      stepper1.moveTo(2355);
      stepper1.run();
      digitalWrite(ledPin,LOW);
    }
  
  }
}