simple interrupt does not work

Hi! Simple routine, but I can't get why it is not working.

void setup(){
pinMode(13,OUTPUT);
pinMode(2,INPUT);
attachInterrupt(0,isr,LOW);
}

void loop(){

}

void isr (){

if(digitalRead(13)==1){
digitalWrite(13,LOW);
}
else{
digitalWrite(13,HIGH);
}

}

What is connected to pin 2 to cause the interrupt? And how is it connected?

What have you got wired up to pin 2? Can you show a schematic of what you have? When you say it doesn't work, what actually does happen?

Keep in mind that with the interrupt set to LOW, it will keep firing over and over and over again as long as the pin is low.

pic2pic2pic:
Hi! Simple routine, but I can't get why it is not working.

Usage of interrupts is hardware dependent, even when using Arduino library functions.

So please describe:
What type of Arduino board are you using?
What circuit is connected to pin-2 on that board?

Please consider, that an interrupt on LOW will happen always when the pin is LOW. This can happen several thousand of times per second, and if it does it will look as if the LED is always on.

How do you know that your isr() is not firing?

Thank you. I use Arduino UNO. I try to use just one part of rotary encoder, so switch A is on pin 2 and switch B is on pin 4. And pin 2 is connected over 2* 10 kohm to + power suplly. Becouse for bouncing reasons it is connected over RC filter i.e. 10 Kohm and capacitor 0,1 uF . When I turn left or right the handle of the encoder I see that LED is turn on but like half of brightness, next turn it becomes fully bright, next turn it turns of and so on but it is of random brightness . Like brightness is randomly turned fully , half brightness, and of. Also I tried to make small and simple routine that will make LED blink 10 times when I turn rotary encoder. That small routine works well inside "void loop()" routine but not in the interrupt routine where it just flashes just one time led. At the moment it is not important if interrupt is triggered by rotary encoder or switch. I just play around

encoder schematics :

https://ccrma.stanford.edu/workshops/2006/PID/sensors/encoder.html

pic2pic2pic:
Thank you. I use Arduino UNO.

OK, in case of an UNO you have interrupt-0 on pin-2 and interrupt-1 on pin-3.

pic2pic2pic:
I try to use just one part of rotary encoder, so switch A is on pin 2 and switch B is on pin 4. And pin 2 is connected over 2* 10 kohm to + power suplly. Becouse for bouncing reasons it is connected over RC filter i.e. 10 Kohm and capacitor 0,1 uF . When I turn left or right the handle of the encoder I see that LED is turn on but like half of brightness, next turn it becomes fully bright, next turn it turns of and so on but it is of random brightness . Like brightness is randomly turned fully , half brightness, and of. Also I tried to make small and simple routine that will make LED blink 10 times when I turn rotary encoder. That small routine works well inside "void loop()" routine but not in the interrupt routine where it just flashes just one time led. At the moment it is not important if interrupt is triggered by rotary encoder or switch. I just play around

Normally you read mechanical buttons and mechanical encoders by sampling the inputs at a fixed rate.

You can do it by polling from the loop or by using a timer interrupt (one timer interrupt for reading all inputs). Polling is easier and more friendly to code for beginners.

The problem is that you attached on LOW. You want FALLING, or CHANGE, but definitely not LOW. With the interrupt firing on LOW when the encoder is turning and the signal goes low for a millisecond the ISR runs a few hundred times over. Whether or not the LED is on or off at the end of that depends on whether the last run of the ISR turned it on or off. It's totally random. While the encoder is turning, the ISR is just continuously firing as fast as it can and the LED looks like it is half on.

Thank you . I tried fallowing code:

int pin = 13;
volatile int state = LOW;

void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, CHANGE);
}

void loop()
{
digitalWrite(pin, state);
}

void blink()
{
state = !state;
}

but still LED sometimes not not turn on or turn off when it is supposed to. I really hate that I do not understand this ...

Have you tried pulling the encoder out and trying it with a regular button?

Have you actually wired it according to the schematic? Can you post a clear photo please?

pic2pic2pic:
but still LED sometimes not not turn on or turn off when it is supposed to. I really hate that I do not understand this ...

When any mechanical switch is connected in your circuit, including the A and B switches of a rotary encoder, the switch must be

  • either connected to an external pull-down resistor
  • or connected to an external pull-up resistor
  • or you must activate the Atmegas internal pull-up resistor in your software sketch

So if you want easy cabling and use the internal pull-up resistors connect your rotary encoder:
encoder A - to Arduino pin-2
encoder GND - to Arduino GND
encoder B - to Arduino pin-3 (not used in the following demo sketch)

The encoder GND pin is the middle pin between A and B pins.

And use code like that:

#define A_PIN 2
#define B_PIN 3 // B_PIN is not used in this demo sketch
#define LED_PIN 13

volatile int state;

void setup()
{
  pinMode (A_PIN, INPUT_PULLUP); // activate internal pull-up resistor
  pinMode (B_PIN, INPUT_PULLUP); // activate internal pull-up resistor
  pinMode(LED_PIN, OUTPUT);
  attachInterrupt(0, encoderA, CHANGE);
}

void loop()
{
  digitalWrite(LED_PIN, state);
}

void encoderA()
{
  state = !digitalRead(A_PIN);
// state = digitalRead(A_PIN);  // or maybe inverted if you like
}

I think I have to repeat what I wrote before:
Normally you read mechanical buttons and mechanical encoders by sampling the inputs at a fixed rate.

You can do it by polling from the loop or by using a timer interrupt (one timer interrupt for reading all inputs). Polling is easier and more friendly to code for beginners.

So trying to use hardware interrupts with rotary encoders might lead to very bad results.

Thank you for the answers. I changed a little bit schematic. Now instead of encoder there is a switch. It is really nothing big. Nothing works well. I agree that polling can work, but external interrupt also must work.

switch for arduino interrupt.jpg

pic2pic2pic:
Thank you for the answers. I changed a little bit schematic. Now instead of encoder there is a switch. It is really nothing big. Nothing works well. I agree that polling can work, but external interrupt also must work.

Throw away all resistors and capacitors from your circuit and use the code and cabling I posted in reply #12!

Ok. I’v removed capacitor an resistors. I use your code but still have strange results. LED is turn on as long as I hold button pressed. I changed your code a little bit to make 10 flashes of LED, but the result is the same as in your code, just one flash on press and release of button. What is wrong with this code ?

#define A_PIN 2
#define B_PIN 3 // B_PIN is not used in this demo sketch
#define LED_PIN 13

volatile int state;

void setup()
{
pinMode (A_PIN, INPUT_PULLUP); // activate internal pull-up resistor
pinMode (B_PIN, INPUT_PULLUP); // activate internal pull-up resistor
pinMode(LED_PIN, OUTPUT);
attachInterrupt(0, encoderA, RISING);
}

void loop()
{
digitalWrite(LED_PIN, state);
}

void encoderA()
{
for (int i=1;i<10;i++){
digitalWrite(LED_PIN, HIGH);
delay(500);

digitalWrite(LED_PIN, LOW);
delay(500);
}
//state = !digitalRead(A_PIN);
//state = digitalRead(A_PIN); // or maybe inverted if you like
}

Your code seems working, I suspect o bad switch. Also It looks like delay() does not working on interrupt, I don know why , but it looks like that. Thank you all, I'll consider this kind of solved :slight_smile:

pic2pic2pic:
Ok. I’v removed capacitor an resistors. I use your code but still have strange results. LED is turn on as long as I hold button pressed.

OK, you have got it!
This is not “very strange results”, but this is what I have programmed as a demo.

pic2pic2pic:
I changed your code a little bit to make 10 flashes of LED, but the result is the same as in your code, just one flash on press and release of button. What is wrong with this code ?

The first thing going wrong is that you try to use “delay()” in an interrupt handling routine.
This is absolutely(!) forbidden!

Interrupt handling must be quick.
ALWAYS!!!

So if you want the interrupt to initialize 10 flashes of an LED, you would do that:

  • in the interrupt handling ==> set a “flag” variable that tells, the LED must be flashing
  • if in the loop function you see that the LED must be flashing, flash it as slow as you like
  • after finished flashing, reset the “flag” variable
#define BUTTON_PIN 2
#define LED_PIN 13

volatile boolean LEDmustFlash;

void setup()
{
  pinMode (BUTTON_PIN, INPUT_PULLUP); // activate internal pull-up resistor
  pinMode(LED_PIN, OUTPUT);
  attachInterrupt(0, encoderA, FALLING);
}

void loop()
{
  if (LEDmustFlash)
  {
    for (int i=0;i<10;i++) // This loop runs 10 times
    {
      digitalWrite(LED_PIN, HIGH);
      delay(500);
      digitalWrite(LED_PIN, LOW);
      delay(500); 
    }
    LEDmustFlash=false;
  }
}

void encoderA()
{ // quick(!) interrupt handling
  LEDmustFlash=true;
}

Thank's bro :slight_smile: . I never knew that delay () is not allowed in ISR. That seems strange to me. Why is that forbidden ? Any limitation how long ISR should be ? Any other restrictions for ISR ?

Why is that forbidden ?

In an ISR interrupts are turned off. delay() uses interrupts to know how much time has elapsed. So it is likely to hang forever.

Any other restrictions for ISR ?

Read the link above.