0

I have read before that you can't use delay() inside I2C receiveEvent because it is an ISR.

What I want to do is as follows: I have a servo connected to my Arduino Uno and I want to control that using an I2C signal. Since I want to decrease the speed of the servo, I was previously using a loop with delay inside, which doesn't work when the function is called by I2C.

This is the code that I used before to control the servo:

void setServo(bool status) {
    if (status) {
        for (int pos = 0; pos <= 180; pos += 5) {
            servo.write(pos);
            delay(50);
            Serial.println(pos);
        }
    } else {
        for (int pos = 180; pos >= 0; pos -= 5) {
            wasteFlapServo.write(pos);
            delay(50);
            Serial.println(pos);
        }
    }
    servoStatus = status;
}

How could I still control the speed of the servo even if I use I2C? Thanks for your help.

Kind regards, Moritz

  • You are using 2 servos : servo and wasteFlapServo ? – DataFiddler Jul 6 at 13:11
  • Note that Serial.println() is another no-no during an ISR. Any sort of serial communication is quite slow. – Duncan C Jul 6 at 14:04
  • @DuncanC Though there the problem is more with the serial data not getting send. print() just places the data in the buffer. The actual transmission is done via ISRs, which place each byte into the UART hardware register. So all the data would fill the buffer, untils it's full. And the data would only get send, when going out of the ISR. I think in the newer core versions print will also not block at full buffer, when inside an ISR, though I don't remember, where I read that – chrisl Jul 6 at 14:14
3

The general way of doing long things triggered by an ISR is to simply set a flag insode the ISR, which then gets checked inside void loop().

volatile byte flag = 0;

void loop(){
    if(flag){
        // Do something here
        flag = 0; // reset the flag
    }
}

void receiveEvent(int howMany){
    flag = 1; // set flag, if correct data was received
}

Here keep the following in mind:

  • The loop() needs to run fast to react fast. Long delays are doing other long stuff there will impact the responsiveness of the code. Depending on your plans for the exact behavior, the usage of delay() is generally not good. You should look into the BlinkWithoutDelay example, that comes with the Arduino IDE. It is worth learning that rather early.

  • flag mus be declared volatile, to tell the compiler, that is may change at any time. Otherwise it might optimize the variable away.

  • flag is of type byte here. It is imprtant, that this flag only has a single byte, because reading and writing of a single byte cannot be interrupted. Multi-byte variables get read or written in multiple COU cycles, thus it would be possible, that the interrupt writes parts of the variable, while you are reading it in the main code. That would lead to garbled data. By using a single byte, you avoid using critical sections for keeping the reading in main code save. For a flag thats way simpler.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.