Using Interrupts to read clicked button on IR transmitter

Hello,

I have some issues with setting up a program using interrupts. I understand the basic examples I see on the Net, to get it working for the situation I have is however not working…
The behaviour I want is;

Press button 1 on remote control > Servo motor turns 180 degrees clockwise
Press button 2 on remote control > Servo motor turns 180 degrees ant-clockwise

The rotation for the 180 degrees is purposely slow. When button 1 or 2 is clicked while the servo is running it should stop and execute the routine for that button from start.

I am not sure how to setup the interrupts to just interrupt and get back to the loop() again. It just does some random stuff I don’t understand.

The IR receiver is connected to pin 11 and to pin 2 (interrupt 0).

The code is below, I hope someone can explain me how to use interrupts correctly for this instance.


#include <IRremote.h>
#include <Servo.h>

Servo myservo;
int RECV_PIN = 11;
int pos = 0; // variable to store the servo position
volatile int interrupted = 0;

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
myservo.attach(9); // attaches the servo on pin 9 to the servo object
myservo.write(pos);
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
attachInterrupt(0, ir_interrupt, CHANGE);
}

void ir_interrupt() {
loop();
}

void loop() {
if (irrecv.decode(&results)) {
if(results.value == 16601263) { servo_up(); }
if(results.value == 16584943) { servo_down(); }
irrecv.resume();
}

}

void servo_up() {
for(pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable ‘pos’
delay(50); // waits 15ms for the servo to reach the position
}
}

void servo_down() {
for(pos = 180; pos>=1; pos-=1) // goes from 180 degrees to 0 degrees
{
myservo.write(pos); // tell servo to go to position in variable ‘pos’
delay(50); // waits 15ms for the servo to reach the position
}
}

No real need to use interrupts, and certainly never call ‘loop’ directly.
Polling would be sufficient.

In each of your loops that are moving the servo, add

if (irrecv.decode(&results))
   break;

Then, if a button is pressed on the remote, the loop will be ended immediately (well, after the current delay(), anyway).

So why would you want to use the interrupts then? And how should the interrupt be used in this example to get it working correctly?

Many thanks! Bastiaan

So why would you want to use the interrupts then?

You wouldn't.

If you insisted, you'd have to have something connected to pin 2 that went high when the remote was clicked. Right now, it appears that you are using pin 9 for the IR receiver. That would need to be changed to pin 2.

Then, in the ISR, you would set a flag showing that in interrupt had occurred. You'd still need to modify your for loops to check that flag.

In this case, the use of an interrupt gains you nothing.

I'm no expert but I have used interrupts before so I'll take a stab at it.

Instead of this:

void ir_interrupt() { loop(); }

void loop() { if (irrecv.decode(&results)) { if(results.value == 16601263) { servo_up(); } if(results.value == 16584943) { servo_down(); } irrecv.resume(); }

I would do this:

void ir_interrupt() {
  if (irrecv.decode(&results)) {
      if(results.value == 16601263) { servo_up(); }
      if(results.value == 16584943) { servo_down(); }
      irrecv.resume();
}

void loop() {
    
    }

This has the sketch doing nothing most of the time (ie, loop(){}) until the interrupt happens, then it goes to the interrupt function.

Hope that helps!

Doug

I'm no expert but I have used interrupts before so I'll take a stab at it.

Effectively?

Did you read the first part of the thread? The question was how to use an interrupt to stop the servo moving, not to get it started moving. The functions that you want to call in the ISR take a long time to complete. Do you really think that they are appropriate to call from an ISR?

@ Paul, I have connected the receiver to pin 2 as well, so it detects any change from the IR receiver.

@DBB, WhatI understood so far is that the interrupt should be as small of a program as possible, so it does not interfere with the internal clock

There is one thing which keeps me guessing; If you call the interrupt from the loop(), once it has completed the interrupt where exactly does the program resume? - Start of Loop - Exactly where it left of?

So would a while loop in the loop() be the best option? > while (interrupt_flag == 0) { tadadadadada }

Finally as all examples on interrupts are as easy as the one I am describing, can someone explain to me when an interrupt is actually needed / has a benefit?

thanks a bunch for all the good information!

There is one thing which keeps me guessing; If you call the interrupt from the loop(), once it has completed the interrupt where exactly does the program resume? - Start of Loop - Exactly where it left of?

Exactly where it left off.

can someone explain to me when an interrupt is actually needed / has a benefit?

They're useful when the condition indicated by the interrupt isn't going to last very long, or is going to be replaced by another condition very soon, and the overhead of polling in code would be too onerous. Serial character reception is one such example.

Cool, I will be testing this tonight. One worry I have is that the delay for the servo causes the loop to end too late and therefore missing part of the data for the IR, or am I wrong on that?

One worry I have is that the delay for the servo causes the loop to end too late and therefore missing part of the data for the IR, or am I wrong on that?

Typically, a remote sends the bit stream for a switch press over and over, until you release the button. As long as you hold the switch down for 50+ milliseconds, the IR receiver and code should capture the switch press.

If you are really concerned, you could get rid of the delay() calls. All you are doing is moving a servo to a new position, and waiting, doing nothing, for a period of time.

Change the logic, so that you compute a new state (a new position for the servo), and see if it is time to make that new state a reality (command the servo to move to a new position). Look at the blink without delay example.

Or, you could just try it, and see if your fears are a reality.