PIN change interrupt

Hi all,
I am trying to understand the PIN change interrupt in Arduino UNO. I am using Proteus for simulating the UNO. Even after goign throught the datasheet and various forums and demo codes, i can not see whats the mistake that I am making in this code. The simple code that I wrote toggles a variable and displays as an LEd output. I also, attached another LED to see if the PIN is reading properly. I can see the Button is pressing and reading in the main loop, but it seems that the ISR is not processing. If anyone could have a look at the code and please guide if there are any mistakes in the code.

#include <avr/interrupt.h>
#define cbi(sfr,bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr,bit) (_SFR_BYTE(sfr) |= ~_BV(bit))


volatile int button=1;
volatile int toggle=1;

ISR(PCINT2_vect)
  {
    toggle= ~digitalRead(7);
  }

void setup()
  {
    //sbi(PCICR,PCIE0);
    PCMSK2= 0b10000000;
    //PCMSK2|=(1<<PCINT23);
    PCICR = B00000100;
    //PCICR |= (1<<PCIE2);
    //sbi(PCIFR,PCIF0);
    //PCIFR |= B00000100;
    //sbi(PCMSK2,PCINT5);  //PD7=PCINT23
    
    PCMSK1=0;
    PCMSK0=0;    
    sei();
    
    pinMode(7,INPUT);
    digitalWrite(7,HIGH);
    pinMode(A0,OUTPUT);
    pinMode(13,OUTPUT);  
  }

void loop()
  {
    digitalWrite(13,digitalRead(7));
    digitalWrite(A0,toggle);
  }

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

Your mistake will become apparent when you print toggle.

I like interrupts and so I'm interested in the discussion. Coding Badly your answer is vague but is it because of the bitwise NOT ~ causing the problem instead of using boolean NOT ! toggle= ~digitalRead(7); toggle= !digitalRead(7);

Hi all,
Thank you for the replies.
I tried to implement the change, but the result is the same the ISR is not running. I changed the code slightly, and its simpler now. Just blinks the LED connected to A0 if the ISR running.

I am attaching the proteus project that I have for members reference.

Also, if anyone has a working code snippet of the interrupt on change, please share it with me so that it can be a reference to me.

CODE:-

#include <avr/interrupt.h>
#define cbi(sfr,bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr,bit) (_SFR_BYTE(sfr) |= ~_BV(bit))


ISR(PCINT2_vect)
  {
    digitalWrite(A0,HIGH);
    delay(500);
    digitalWrite(A0,LOW);    
     
  }

void setup()
  {
    
    //sbi(PCICR,PCIE0);
    PCMSK2= B10000000;
    //PCMSK2|=(1<<PCINT23);
    PCICR = B00000100;
    //PCICR |= (1<<PCIE2);
    //sbi(PCIFR,PCIF0);
    //PCIFR |= B00000100;
    //sbi(PCMSK2,PCINT5);  //PD7=PCINT23
    sei();
    PCMSK1=0;
    PCMSK0=0;    
    
    
    pinMode(7,INPUT);
    digitalWrite(7,HIGH);
    pinMode(A0,OUTPUT);
    pinMode(13,OUTPUT);  
  }

void loop()
  {
    digitalWrite(13,digitalRead(7));    
  }

Arduino_ISR.zip (23.3 KB)

You can NOT use delay in an ISR. Even if you could, blinking an LED means turning it on, waiting, turning off AND WAITING AGAIN.

You could change your blink code to toggle the led every time the isr is triggered avoiding the delay issue.

digitalWrite(A0,!digitalRead(A0));

The ISR is a peculiar thing.

As for testing interrupts Have you tried the function attachInterrupt? You will need to change to pin 2 for your interrupt pin for this to work. Example in the Arduino reference I changed the led pin to A0

const byte ledPin = A0;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

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

void blink() {
  state = !state;
}

Yes, I hav etried the attache interrput function. And I think that wouldnot serve my purpose. I would like to connect 4 buttons to the arduino, and would like them to be read with the interrupt. I wouldnot want to polle for the switches.

Also, in real code I will not be using the delay in the ISR, the delay in that was just kept to see if the ISR is functional.

So could anyone see what I am missing to enable the interrput on change

I would like to connect 4 buttons to the arduino, and would like them to be read with the interrupt. I wouldnot want to polle for the switches.

This is the part that you need to explain. Why is polling the switches not adequate?

I would like to learn how the pin change interrupt works. And like to implement it. I have tried and implemented the polling methode for the button reading. And also, as the projects get bigger, I believe button read from the interrupt is more easier to code.

And also, as the projects get bigger, I believe button read from the interrupt is more easier to code.

In the interrupt handler, you read the state of the switch, and set a flag. In loop(), you check the state of the flag and take some action.

Or, in loop(), you read the state of the switch and take some action.

I can't see that an interrupt is easier. YMMV.

I am using Proteus for simulating the UNO.

Forget that crap. Ditch the simulator; go straight for the real thing.

Aside from all that, there have been problems pointed out in the code that you have posted. Have you corrected those? What does your code look like now? What does it do? How does that differ from what you want?

Unfortunately I dont have an Arduino Handy, but ordered a Arduino Mega yesterday, and will be in hand in couple of days.

I implemented all the suggestions and the the code looks like as follows…
can anyone, if possible, see if the code works on your Arduino?

Also, it would be a great help if anyone has a working code that you can share with me.

#include <avr/interrupt.h>
#define cbi(sfr,bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr,bit) (_SFR_BYTE(sfr) |= ~_BV(bit))

#define ISR_LED A0
#define Main_LED 13
#define Button 7



volatile int ISR_flag=1;

void setup()
  {
    
    
    PCMSK2= B10000000;    
    PCICR = B00000100;     
    PCIFR = B00000111;
    sei();
    PCMSK1=0;
    PCMSK0=0;    
        
    pinMode(Button,INPUT);      // setting the Switch as input
    digitalWrite(Button,HIGH);  // Enabling the pullup resistor 
    pinMode(ISR_LED,OUTPUT);    // Setting the main loop LED pin as Output 
    pinMode(Main_LED,OUTPUT);   // Setting the ISR LED as output
    digitalWrite(ISR_LED,HIGH); // Checking the ISR LED Blimk-ON
    delay(500);                 // Checking the ISR LED Delay
    digitalWrite(ISR_LED,LOW);  // Checking the ISR LED Blink Off
  }

void loop()
  {
    digitalWrite(Main_LED,digitalRead(7));    
    if(ISR_flag==1)
      {
        digitalWrite(ISR_LED,HIGH);
        delay(500);
        digitalWrite(ISR_LED,LOW); 
        ISR_flag=0;
      }
  }


  ISR(PCINT_vect)
  {
    ISR_flag=1;   
     
  }

hi everyone, I got my Mega today and I tried in that as well, but the PIN Change interrupt is not woring. I have searched and analyzed various codes, and I cant see why the interrupt is not working without using any library function. can any moderators shead light on this please. Also, again requesting if anyone has a working code for the PIN change interrupt, please share.....

    PCMSK2= B10000000;   
    PCICR = B00000100;     
    PCIFR = B00000111;
    sei();
    PCMSK1=0;
    PCMSK0=0;

Some comments regarding what you think this code is doing are definitely in order.

Not all pins on the Mega support pin change interrupts. You need to confirm that the pins you are trying to use do indeed support pin change interrupts.

ISR(PCINT_vect)

Is a valid vector name for only the ATtiny2313 and the ATtinyX61 family.

It is not a valid vector name for any of the ATmega processors.

OK, I have changed the vector name to detect PCINT on PIN22 on AtMega560. But the result is still the same!!!!

Does anyone worked on PCINT pls input their comments.

volatile int ISR_flag=0;

#define ISR_LED 13
#define Button 22



// the setup function runs once when you press reset or power the board
void setup() 
{
    cli();               // Clearing any interrupt flags
    PCICR |= 0b00000100; // PCIE2=1, enabling PCINT23:16     
    PCIFR |= 0b00000100; // PCIF2=0, Clearing the PCIF2 flag
    // the above line is not as per the manual, as it says write logical 1 to it to clear the flag
    
    PCMSK2|= 0b01000000; // PCINT22, Enabling the PCINT on Pin 22
    PCMSK1|=1;           // Disabling PCINT 15:8 
    PCMSK0|=1;           // Disabling PCINT 0:7
    sei();
  
  
  pinMode(13, OUTPUT);  
  pinMode(Button,INPUT);
  //digitalWrite(Button,HIGH);// Used a physical pullup resistor on the Pin 22

  Serial.begin(9600); 
  
}



  ISR(PCINT2_vect)
  {
    ISR_flag=1;  
    Serial.println("From ISR");
    
     
  }


// the loop function runs over and over again forever
void loop() {
    
    if(ISR_flag==1)     //if ISR is enables the blinking is enabled 
      {
        digitalWrite(ISR_LED,HIGH);
        delay(1000);      
        digitalWrite(ISR_LED,LOW); 
        ISR_flag=0;
      }
}
  ISR(PCINT2_vect)
  {
    ISR_flag=1; 
    Serial.println("From ISR");
  }

Don't do serial prints inside an ISR.


OK, I have changed the vector name to detect PCINT on PIN22 on AtMega560. But the result is still the same!!!!

Pin 22 does not support pin-changes interrupts.

See the page about SoftwareSerial.

Not all pins on the Mega and Mega 2560 support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69).

Pin 22 is not in that list.

PCIFR |= 0b00000100; // PCIF2=0, Clearing the PCIF2 flag

That is not how Pin Change Interrupt flags are cleared. Remove the bitwise-or.

    PCMSK1|=1;           // Disabling PCINT 15:8
    PCMSK0|=1;           // Disabling PCINT 0:7

Nope. Those two lines do not disable anything. They do the exact opposite of "disable".

PCINT22 is Port K / Bit 6 which is mapped to Analog Input 14 (A14).