Pages: [1] 2   Go Down
Author Topic: I2C slave reply  (Read 2771 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi .

I am using a master - slave device with I2C communication on arduino ATMega boards.
I have connected the slave device to a stepper motor .
The master requests the slave to inform it once the stepper motor has finished running .
I would like to know how to make the slave send this acknowledgement to the master AFTER the stepper motor stops running . Can anyone help me ?
Here is my code for master and slave :

// I2C
MASTER

Code:
// given adressess as 4 for slave 1
//                    

#include <Wire.h>


#include <AccelStepper.h>

int incomingByte = 0;
long millisec = 0;
//int bytesSent = 0;
int a[10]= {0};
int i =0;

void setup()
{
   Wire.begin();
   //Start Serial for debuging purposes
  Serial.begin(115200); // USB comm with PC

  delay(1000);
  
  spam();
}



void spam() {
  Serial.println("--------------------");
  
  Serial.println("1: Stepper1 FORWARD");

  Serial.println("2: Stepper1 BACKWARD");
  
}


void loop()
{
  
   if(millis() > millisec) {
      millisec = millis();
    
    if (Serial.available() > 0) {
        incomingByte = Serial.read()-48;
        Serial.print("  Selection:");Serial.println(incomingByte);
        
        switch(incomingByte) {
          case 1:  Serial.println("Stepper1: forward");
                   Wire.beginTransmission(4);
                   Wire.send(1);
                   Wire.endTransmission();  
                  
                   delay(1000);
                   // to find out how many steps left for the motor
                   Wire.requestFrom(4,3);
                   while(Wire.available())
                   {
                      char c = Wire.receive();
                      Serial.print(c);
//                      
                   }
                  
                   break;
                  
          case 2:  Serial.println("Stepper1: backward");
                  
                   Wire.beginTransmission(4);
                   Wire.send(2);
                   Wire.endTransmission();
                  
                   Wire.requestFrom(4,3);
                   while(Wire.available())
                   {
                      char c = Wire.receive(); // receive a byte as character
                      Serial.print(c);         // print the character
                   }
                  
                   break;
                  
          default: spam();
                   break;
                  
        } // switch case loop
    }   //serial available loop
  }    //  millis loop
}       // void loop
                  
             

SLAVE  :

Code:
// I2C communication  1 Master- 1 Slave

// program for slave 4



#include <Wire.h>

#include <AccelStepper.h>

int incomingByte = 0;
int stepperPin = 0;
int stepperInterval = 2;
int stepperCounter = 0;
int stepCount = 0;

// timer variables
long millisec = 0;
long microsec = 0;



// stepper motor pins: STEP, DIRECTION, STEPPER ON/OFF
AccelStepper Stepper1(1,2,3);



void setup() {
  
  Wire.begin(4);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);

  
    
 //Start Serial for debuging purposes
  Serial.begin(115200); // USB comm with PC

for(int i = 0;i <54;i++) {
    pinMode(i,OUTPUT);
    digitalWrite(i,LOW);
  }

  
  
  // switch stepper chips off
  digitalWrite(4,HIGH);

  
  
    Stepper1.setMaxSpeed(1000);

}


  
 void receiveEvent(int howMany)
{

      if (Wire.available() > 0) {
       incomingByte = Wire.receive();
     }
}  
      

void requestEvent()
{


loop();
}               // as expected by master
 


void loop()
{
    Stepper1.run();
  
  if(Stepper1.run() == 0)
  {
   digitalWrite(4,HIGH);
   Wire.send("yes");
  }
  
        //Serial.print("  Selection:");Serial.println(incomingByte);
        switch(incomingByte) {
          case 1: digitalWrite(4,LOW); digitalWrite(3,HIGH); digitalWrite(2,HIGH); //Serial.println("Stepper1: forward");
                  
                  Serial.println("forward");
                  Stepper1.setCurrentPosition(0);
                  Stepper1.setAcceleration(500.0);
                  Stepper1.moveTo(4000);
                  
                  break;
          
        
          case 2:  digitalWrite(4,LOW); digitalWrite(3,LOW); digitalWrite(2,HIGH);   //Serial.println("Stepper1: backward");
                  
                  Serial.println("backward");
                  Stepper1.setCurrentPosition(0);
                  Stepper1.setAcceleration(500.0);
                  Stepper1.moveTo(-4000);
                  break;
          
        
      }
     // switch loop
     incomingByte = 0;  
} // main loop
« Last Edit: July 23, 2012, 12:14:46 pm by anishh2003 » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 50115
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I would like to know how to make the slave send this acknowledgement to the master AFTER the stepper motor stops running .
How does the slave KNOW this? If you are using the Stepper library, the step() method blocks until the function ends. At that point, send the reply.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Paul ,

I have just added my code .
I have used accelstepper library .
Would you be able to tell me how to implement Wire.send after going through this code please .
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 50115
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 When the master calls Wire.requestFrom(), that triggers the OnRequest event on the slave. You have registered requestEvent() as the event handler to be called.

Code:
void requestEvent()
{
loop();
}               // as expected by master
Calling loop() once is a silly thing to do. What you need to do, in this method, is wait for the stepper to get where it is going, then send the reply.

Use the AccelStepper::currentPosition() method to find where the stepper is. Compare that to where you told it to go. When they match, the stepper has finished moving.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Paul

I changed my SLAVE program a bit . It still doesnt seem to work . Would you be able to advise me on how to proceed now .

Code:
// I2C communication  1 Master- 1 Slave

// program for slave 4



#include <Wire.h>

#include <AccelStepper.h>

int incomingByte = 0;
int stepperPin = 0;
int stepperInterval = 2;
int stepperCounter = 0;
int stepCount = 0;

// timer variables
long millisec = 0;
long microsec = 0;



// stepper motor pins: STEP, DIRECTION, STEPPER ON/OFF
AccelStepper Stepper1(1,2,3);



void setup() {
  
  Wire.begin(4);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);

  
    
 //Start Serial for debuging purposes
  Serial.begin(115200); // USB comm with PC

for(int i = 0;i <54;i++) {
    pinMode(i,OUTPUT);
    digitalWrite(i,LOW);
  }

  
  
  // switch stepper chips off
  digitalWrite(4,HIGH);

  
  
    Stepper1.setMaxSpeed(1000);

}


void receiveEvent(int howMany)
{
     if (Wire.available() > 0) {
     incomingByte = Wire.receive();
     }
}  
      

void requestEvent()
{

  if(Stepper1.run() == false)
  {
   if(Stepper1.currentPosition() ==4000)
   {digitalWrite(4,HIGH);
   Wire.send("yes");
   }              
  }
}


void loop()
{
    Stepper1.run();
    
  
  
  
        //Serial.print("  Selection:");Serial.println(incomingByte);
        switch(incomingByte) {
          case 1: digitalWrite(4,LOW); digitalWrite(3,HIGH); digitalWrite(2,HIGH); //Serial.println("Stepper1: forward");
                  
                  Serial.println("forward");
                  Stepper1.setCurrentPosition(0);
                  Stepper1.setAcceleration(500.0);
                  Stepper1.moveTo(4000);
                  
                  break;
          
        
          case 2:  digitalWrite(4,LOW); digitalWrite(3,LOW); digitalWrite(2,HIGH);   //Serial.println("Stepper1: backward");
                  
                  Serial.println("backward");
                  Stepper1.setCurrentPosition(0);
                  Stepper1.setAcceleration(500.0);
                  Stepper1.moveTo(-4000);
                  break;
          
        
      }
     // switch loop
     incomingByte = 0;  
} // main loop

« Last Edit: July 23, 2012, 12:15:39 pm by anishh2003 » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 50115
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
  if(Stepper1.run() == false)
  {
   if(Stepper1.currentPosition() ==4000)
   {digitalWrite(4,HIGH);
   Wire.send("yes");
   }               
  }
The run() method returns true if the motor is at the desired position. If not, it returns false.

You are checking whether the motor is where it is supposed to be. If not, you check if it is at some hardcoded location. Since that location matches where you told it to go, it is unlikely to have gotten there in the interval between the two calls.

In any event, you need a while loop that keeps checking if the stepper is where it is meant to be. Checking only once is not going to work.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Paul

I did make a few changes and put a while loop as suggested
Please have a look at it .
The result is it is giving me y with two dots on top of it .  And this is while running .. not AFTER running . Please help . .

SLAVE :

Code:

// I2C communication  1 Master- 1 Slave

// program for slave 4



#include <Wire.h>

#include <AccelStepper.h>

int incomingByte = 0;
int stepperPin = 0;
int stepperInterval = 2;
int stepperCounter = 0;
int stepCount = 0;

// timer variables
long millisec = 0;
long microsec = 0;



// stepper motor pins: STEP, DIRECTION, STEPPER ON/OFF
AccelStepper Stepper1(1,2,3);



void setup() {
  
  Wire.begin(4);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);

  
    
 //Start Serial for debuging purposes
  Serial.begin(115200); // USB comm with PC

for(int i = 0;i <54;i++) {
    pinMode(i,OUTPUT);
    digitalWrite(i,LOW);
  }

  
  
  // switch stepper chips off
  digitalWrite(4,HIGH);

  
  
    Stepper1.setMaxSpeed(1000);

}


void receiveEvent(int howMany)
{
     if (Wire.available() > 0) {
     incomingByte = Wire.receive();
     }
}  
      

void requestEvent()
{

   while(Stepper1.currentPosition() == Stepper1.targetPosition())
   {digitalWrite(4,HIGH);
   Wire.send("yes");
   }              
  
}


void loop()
{
   while( Stepper1.currentPosition() != Stepper1.targetPosition())  
   Stepper1.run();
  
  
  
        //Serial.print("  Selection:");Serial.println(incomingByte);
        switch(incomingByte) {
          case 1: digitalWrite(4,LOW); digitalWrite(3,HIGH); digitalWrite(2,HIGH); //Serial.println("Stepper1: forward");
                  
                  Serial.println("forward");
                  Stepper1.setCurrentPosition(0);
                  Stepper1.setAcceleration(500.0);
                  Stepper1.moveTo(4000);
                  
                  break;
          
        
          case 2:  digitalWrite(4,LOW); digitalWrite(3,LOW); digitalWrite(2,HIGH);   //Serial.println("Stepper1: backward");
                  
                  Serial.println("backward");
                  Stepper1.setCurrentPosition(0);
                  Stepper1.setAcceleration(500.0);
                  Stepper1.moveTo(-4000);
                  break;
          
        
      }
     // switch loop
     incomingByte = 0;  
} // main loop
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 50115
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
   while(Stepper1.currentPosition() == Stepper1.targetPosition())
   {digitalWrite(4,HIGH);
   Wire.send("yes");
   }
So, you want the slave to send yes over and over again when the stepper is at the target position. Until then, do nothing.

Try again. Something like:
Code:
   while(Stepper1.currentPosition() != Stepper1.targetPosition())
   { // Do nothing }
   digitalWrite(4,HIGH);
   Wire.send("yes");

The code in loop to execute Stepper1.run() when the stepper is not at the desired point is not necessary. Just call Stepper1.run(). It will do something, or not, based on whether it is at the target position or not.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Paul ,
Thanks
This seems to work for me .
But I had to increase my delay in the master to a value greater than 5000 .  If it is lower , the stepper motor just doesnt run .
Would you be able to explain why this happens ?

And also ,
if I was to replace ur code with
Code:
while(Stepper1.currentPosition() != Stepper1.targetPosition())
   { //Wire.send("Action not complete");
   }
   digitalWrite(4,HIGH);
   Wire.send("Action complete");
 

then shouldnt it send "Action not complete" continuously ?               


Anish
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 50115
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
then shouldnt it send "Action not complete" continuously ?
Yes, and no.

No, it wouldn't send the message continuously, because the statement is commented out (and doesn't belong on the same line as the {).

If uncommented, the slave would send the message over and over, but the master is only expecting three bytes (unless you changed that). As soon as it gets three bytes, it quits listening to the slave.

Quote
But I had to increase my delay in the master to a value greater than 5000 .  If it is lower , the stepper motor just doesnt run .
What delay?

What does your debug output tell you is happening? You can use Serial.print(), Serial.println(), etc. to talk to the PC from either the master or the slave, to learn what is happening.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Paul
I gave a delay in between endTransmission and requestFrom in the Master .  If I dont give this , the motor doesnt run .
The slave acknowledges the command and activates the motor , but the motor doesnt move .

Any idea ?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 50115
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Any idea ?
Have you removed the while statement from loop()?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Paul ,
No I did not remove the while loop.
Let me post u a simplifed version of the program ... same program .. just cut off some unwanted cases ..
I would also like to know , while the stepper is in motion , does the slave relay that to the master ? I dont understand why I have to give such a big delay .

MASTER
Code:
// I2C 1 master  2 slaves

// given adressess as 4 for slave 1
//                   

#include <Wire.h>


#include <AccelStepper.h>

int incomingByte = 0;
long millisec = 0;
//int bytesSent = 0;
int a[10]= {0};
int i =0;

void setup()
{
   Wire.begin();
   //Start Serial for debuging purposes
  Serial.begin(115200); // USB comm with PC
  //Serial3.begin(115200); // master-slave comm with second Arduino
  delay(1000);
 
  spam();
}



void spam() {
  Serial.println("--------------------");
 
  Serial.println("1: Stepper1 FORWARD");

 
 
}


void loop()
{
 
   if(millis() > millisec) {
      millisec = millis();
   
    if (Serial.available() > 0) {
        incomingByte = Serial.read()-48;
        Serial.print("  Selection:");Serial.println(incomingByte);
         
        switch(incomingByte) {
          case 1:  Serial.println("Stepper1: forward");
                   Wire.beginTransmission(4);
                   Wire.send(1);
                   Wire.endTransmission(); 
                   
                   //Serial.println("Waiting for action to complete");
                   delay(1000);
                   
                   Wire.requestFrom(4,15);
                   while(Wire.available())
                   { 
                      char c = Wire.receive();
                      Serial.print(c);
                     
                   }

                 
                   break;
                   
                   default: spam();
                   break;
                 
        } // switch case loop
    }   //serial available loop
  }    //  millis loop
}       // void loop


SLAVE
Code:

// I2C communication  1 Master- 1 Slave

// program for slave 4



#include <Wire.h>

#include <AccelStepper.h>

int incomingByte = 0;
int stepperPin = 0;
int stepperInterval = 2;
int stepperCounter = 0;
int stepCount = 0;

// timer variables
long millisec = 0;
long microsec = 0;



// stepper motor pins: STEP, DIRECTION, STEPPER ON/OFF
AccelStepper Stepper1(1,2,3);



void setup() {
 
  Wire.begin(4);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);

 
   
 //Start Serial for debuging purposes
  Serial.begin(115200); // USB comm with PC

for(int i = 0;i <54;i++) {
    pinMode(i,OUTPUT);
    digitalWrite(i,LOW);
  }

 
 
  // switch stepper chips off
  digitalWrite(4,HIGH);

 
Stepper1.setMaxSpeed(1000);

}


void receiveEvent(int howMany)
{
     if (Wire.available() > 0) {
     incomingByte = Wire.receive();
     }

     

void requestEvent()
{

   while(Stepper1.currentPosition() != Stepper1.targetPosition())
   { //do nothing
   }
   digitalWrite(4,HIGH);
   Wire.send("Action complete");
                 
 
}


void loop()
{
   
   Stepper1.run();
   
 
 
        //Serial.print("  Selection:");Serial.println(incomingByte);
        switch(incomingByte) {
          case 1: digitalWrite(4,LOW); digitalWrite(3,HIGH); digitalWrite(2,HIGH); //Serial.println("Stepper1: forward");
                 
                  Serial.println("forward");
                  Stepper1.setCurrentPosition(0);
                  Stepper1.setAcceleration(500.0);
                  Stepper1.moveTo(4000);
                  break;
        }
     // switch loop
     incomingByte = 0;   
} // main loop
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 50115
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I would also like to know , while the stepper is in motion , does the slave relay that to the master ?
Look at what happens when the master requests data:
Code:
void requestEvent()
{
   while(Stepper1.currentPosition() != Stepper1.targetPosition())
   { //do nothing
   }
   digitalWrite(4,HIGH);
   Wire.send("Action complete");
}
The code blocks until the stepper gets to where it is supposed to go. Then, it sends a message. So, no, the slave does not tell the master anything while the stepper is moving.

I'll ask again. What are your debug messages telling you?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Paul

I used
Code:
Serial.println(Stepper1.currentPosition());

after Stepper.run()   .

I found that if I give a delay of '100' in Master , I get a currentPosition of the Motor as '7'
delay of 4000 -  gave currentPosition of 2547
            10,000 - gave me the currentPosition of 4000 , which I want

Is there anything else you would have me check ?  please let me know .
Also the motor just stalls after it abruptly stops .. meaning it does not switch off .. it is just stuck.

Logged

Pages: [1] 2   Go Up
Jump to: