I2C communication

I’m controlling several slave arduinos with my master arduino and from my master arduino i want to send commands like “M100” which moves the motor of the slave arduino to position 100. Sending the command works but with the interpretation of the receiver i have some problems

that’s what i got so far:

#include <Wire.h>;

uint8_t bufferCount;

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);
  
}

void loop()
{
    
}

void receiveEvent(int howMany)
{
  //char buff[howMany];
  uint8_t buff[howMany];
  
  Serial.print("Bytes received: ");
  Serial.println(howMany);
  
  Serial.print("Data received: ");
  
  for (int i = 0; i < howMany; i++)
  {
      buff[bufferCount] = Wire.receive();
      Serial.print( buff[bufferCount] );
      bufferCount++;
  }
  
  bufferCount = 0;
  
  Serial.println();
  
  if( buff[0] == 'M')
  {
      
       Serial.print("move command received with following argument: ");
   
      /*for (int j = 0; j < howMany; j++)
      {
         
      }*/
   
      Serial.print(buff[1]);
      Serial.print(buff[2]);
      Serial.println(buff[3]);
      
  }
  
}

i don’t know how to access the received argument … can someone help me?

in the arduino serial monitor when the master sends “M100” i get “move command received with following argument: 100” but when the master sends for example “M9” i get “move command received with following argument: 9”.

also it’s not enough to display the argument the right way in the serial monitor but i need to convert it to int or something to pass it to my motor movement function

Is this the code for the master or the slave.

slave

Replace:- Serial.print(buff[1]); with Serial.print(buff[1], HEX); then you can see exactly what bytes you are getting. You should see ASCII characters (if that is what you send). The is if you send ASCII 9 you will see the hex number 39 back.

thanks but i ran into another problem :frowning:

Wire.h and Stepper.h library seem to clash…

If i try this simple sketch for the slave:

//#include <math.h>
#include <Wire.h>;
#include <Stepper.h>;

// change this to the number of steps on your motor
#define STEPS 48

Stepper stepper(STEPS, 6, 9, 10, 11, 1);

void setup()
{
  stepper.setSpeed(200);
  stepper.step(48*3);

  Wire.begin(4);             
  Wire.onReceive(receiveEvent);


}

void loop()
{

}



void receiveEvent(int howMany)
{
  stepper.step(48*3);
}

the movement from setup() is done properly, but as soon as the slave receives the first data over Wire/I2C the motor TRIES to do one step (its more of a tiny microstep) and the arduino seems to freeze

any ideas?

It only clashes because you are making it clash with the line:- Stepper stepper(STEPS, 6, 9, 10, 11, 1);

Pins 10 & 11 are used by the SPI hardware, use other ones and you should be fine.

hmmm before i used 3, 5, 6 and 9 and it didn't work as well.

i changed it to 6, 9, 10, 11 because i thought pins 4 and 5 are used by I2C

hmmm :(

There is nothing wrong with your pin assignments as they do not conflict with I2C communication (using analog 4 and 5).

The receiveEvent is an interrupt handler and you should not call any stepper library functions from within this handler. Rather you need to restrict yourself to collect the data (write to a global buffer) and then do the actuall processing of the data from within your loop function.

because i thought pins 4 and 5 are used by I2C

It is analogue pins 4 & 5 that are the I2C lines.

Pins 10 & 11 are used by the SPI hardware

This is true but as you are not using SPI then it is not an issue for you, sorry for the confusion.

You shouldn't be using print statements from an ISR, they take too long.

The receiveEvent is an interrupt handler and you should not call any stepper library functions from within this handler. Rather you need to restrict yourself to collect the data (write to a global buffer) and then do the actuall processing of the data from within your loop function.

thanks for the hint, did you mean something like that:

#include <Wire.h>;
#include <Stepper.h>;

// change this to the number of steps on your motor
#define STEPS 48
Stepper stepper(STEPS, 6, 7, 8, 9, 1);

int steps_to_make = 0;

void setup()
{
  
  Serial.begin(9600);
  Wire.begin(4);             
  Wire.onReceive(receiveEvent);
  stepper.setSpeed(200);
  
}

void loop()
{
    
    if( steps_to_make > 0)
    {
        stepper.step(steps_to_make);
        steps_to_make = 0;
    }
   
}



void receiveEvent(int howMany)
{
  steps_to_make = 150; 
}

when i run this sketch the motor does the full movement the FIRST time, but after that nothing happens although i’m still sending I2C data to the slave every 5 seconds…

oops i guess thats my fault, shitty code :smiley:

ok i think i got it!

stupid mistake :D

i never called "Wire.receive()" in my sketch so i got something like a "buffer overflow" and the command was only received once at the beginning

works for now ... thanks for your help!

This is looking better ...

Global variables modified within an interrupt handler need a volatile prefix. Otherwise the compiler may not add code to reload the variable and check that it actually changed.

Following your example, you need:

volatile int steps_to_make = 0;

You may also want to change "steps_to_make" to a byte quantity (as opposed to a 16-bit int) or else you are likely to run into a number of other issues.