How to create 3th interrupt

Thanks FusiveResonance for the wonderfull explanation. :wink:

Still need to try this, was a bit bussy with real life (family and things).

Can this be modified to have FALLING or RISING interupts, or do I simply check inside the ISR the pins for HIGH or LOW?

Greetings,
EriSan500

Can this be modified to have FALLING or RISING interupts, or do I simply check inside the ISR the pins for HIGH or LOW?

No, this is strictly for pin CHANGE interrupts.

Yes, you will have to implement your own system of detecting rising vs falling.

Mind you, remember to keep your interrupt service routine short, as when in a heavy ISR block, you run the risk of missing another interrupt. Depending on the device you have hooked up on this pin, consider debouncing.

Finally, turn off interrupts when you're inside an ISR, as you shouldn't allow an interrupt while you're already servicing one.

#define atomic(off) PCICR = 0x07 //sets the pin change interrupt control register to B00000111
#define atomic(on) PCICR = 0x00 //sets the pin change interrupt control register to B00000000

Now in your ISR you may write something like:

ISR ( PCINT1_vect)
{
   atomic(on); //masks all interrupts. ie. sets the interrupt mask

   //some code

   atomic(off); //resets the interrupt control registers to enable interrupts
}

Be warned, depending on whether or not you are actually using all 3 pin change interrupt capabilities, you might need to modify the hex values in the atomic(on) define statement above. Please see section 12.2.4 in the atmel data sheet for more details.

Some good reading, although doesn't have anything on pin change interrupts, but I believe that you will need to include the headers that they include in their code snippet. gonium.net » Blog Archive » Handling external Interrupts with Arduino

Good luck. Let me know if you have issues, as I haven't tested the above code.

Finally, turn off interrupts when you're inside an ISR, as you shouldn't allow an interrupt while you're already servicing one.

This is not necessary. The processor automatically handles it for you.

This is not necessary. The processor automatically handles it for you.

Wow. never knew that. Thanks.

I am getting this error with your code

error: '__vector_3' was not declared in this scope

I gave it a try too, and i'm also getting an error:

#include <avr/interrupt.h>  
#include <avr/io.h>


void setup() {
//pin change interrupt on digital pin 5
//this corresponds to PCINT0_vect  
 PCICR |= (1 << PCIE0);
 PCMSK0 |= (1 << PCINT21);

//pin change interrupt on digital pin 6
//this corresponds to PCINT1_vect
 PCICR |= (1 << PCIE1);
 PCMSK1 |= (1 << PCINT22);

//pin change interrupt on digital pin 7
//this corresponds to PCINT2_vect
 PCICR |= (1 << PCIE2);
 PCMSK2 |= (1 << PCINT23); 
}

[glow]ISR_0( PCINT0_vect )[/glow]
{
      //do something
}

ISR_1( PCINT1_vect )
{
      //do something else
}

ISR_2( PCINT2_vect )
{
      //do something different
} 

void loop()
{

}

error pointing to highlighted line:

error: expected constructor, destructor, or type conversion before '(' token

Any idea what i might be doing wrong?

Greetings,
EriSan500

ok, made some progress (dunno if this is correct though).

I changed

ISR_0( PCINT0_vect )
{
      //do something
}
ISR_1( PCINT1_vect )
{
      //do something
}
ISR_2( PCINT2_vect )
{
      //do something
}

to

ISR( PCINT0_vect )
{
      //do something
}
ISR( PCINT1_vect )
{
      //do something
}
ISR( PCINT2_vect )
{
      //do something
}

and it compiled without errors.
Will test this as soon as my new arduino's arrive.

Do i use DigitalRead(pin) inside the ISR to check if the port is HIGH or LOW ? Or is there a better way?

All i need to happen inside the ISR is to increase a counter.

Greetings,
EriSan500

Yes you may use digitalRead inside the ISR, but if you're finding it too slow you might have to ready the binary data directly from the register.

Don't forget to declare any variables used by the ISR as volatile.

Also, at the end of your setup() method, you'll want to call sei(). This will set the global interrupt enable bit. In case you ever want to reset the bit, (thereby turning off interrupts), you may use cli().

I finally got my 2nd arduino and got a chance to test this.

And yes, it does not work as expexted. See below code, if you spot the mistake I made, please let me know.

#include <avr/interrupt.h>  
#include <avr/io.h>


void setup() {
  pinMode(5, INPUT);
  Serial.begin(9600);

//pin change interrupt on digital pin 5
//this corresponds to PCINT0_vect  
 PCICR |= (1 << PCIE0);
 PCMSK0 |= (1 << PCINT21);

//pin change interrupt on digital pin 6
//this corresponds to PCINT1_vect
 PCICR |= (1 << PCIE1);
 PCMSK1 |= (1 << PCINT22);

//pin change interrupt on digital pin 7
//this corresponds to PCINT2_vect
 PCICR |= (1 << PCIE2);
 PCMSK2 |= (1 << PCINT23);
}

ISR( PCINT0_vect )
{
      //do something
Serial.println("interrupt on 5");
}

ISR( PCINT1_vect )
{
      //do something else
}

ISR( PCINT2_vect )
{
      //do something different
}

void loop()
{

}
//pin change interrupt on digital pin 5
//this corresponds to PCINT0_vect
 PCICR |= (1 << PCIE0);
 PCMSK0 |= (1 << PCINT21);

//pin change interrupt on digital pin 6
//this corresponds to PCINT1_vect
 PCICR |= (1 << PCIE1);
 PCMSK1 |= (1 << PCINT22);

//pin change interrupt on digital pin 7
//this corresponds to PCINT2_vect
 PCICR |= (1 << PCIE2);
 PCMSK2 |= (1 << PCINT23);

I haven't used PC interrupts on AVR, but according to my reading, ALL of (arduino) pins 5, 6, and 7 are controlled by PCMSK2 and PCIE2, and interrupt via PCINT2_vector.
The advantage of the external interrupt pins is that you get one interrupt vector per pin, and have control of rising/falling/low causing the interrupt. With the pin-change interrupt, you get one interrupt vector per port, and get interrupted on any change to any (un)masked bit in that port.

Westfw is definitely right. You're code is trying to do too many magical things

Try this first. Remember to implement small chunks of code first, whilst testing along the way. As slow as it seems, its actually faster than banging out a whackload of code and hoping for the best when you hit upload.

#include <avr/interrupt.h>
#include <avr/io.h>


void setup() {
  pinMode(5, INPUT);
  Serial.begin(9600);

//pin change interrupt on digital pin 5
//this corresponds to PCINT0_vect
 PCICR |= (1 << PCIE2);
 PCMSK2 |= (1 << PCINT21);

}

volatile bool print_flag = false;

ISR(PCINT2_vect)
{
      print_flag = true;
}

void loop()
{
      if(print_flag == true)
      {
            Serial.println("interrupt on pcint0");
            print_flag = false;
      }

}

Understand this code before you attempt to modify it (unless it doesn't work, in which case do write back). It seems like you've arbitrarily assigned the pcint vectors and the pcmask registers in your code, but it doesn't work that way.

Have you read: http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
If not then begin reading. In particular, start reading section 12 on external interrupts.

If this all seems too intimidating, then do not be concerned, we are still here to help.

I hope that you won't shy away from asking more questions. On the flipside, do realize that I simply yearn for you to find the answer yourself, as that is the always the most rewarding route.

//this corresponds to PCINT0_vect

You left the comment wrong. The code looks OK, though. PCIE2, PCMSK2, PCINT2_vect...

(pet peeve against untrue comments!)

Thanks guy's, will give this a try this evening. Will report back.

Greetings,
EriSan500

Sorry westfw, that one slipped.

Erisan500, I failed to mention one item.

Notice how I displace the serial.print statement from the ISR into the loop(). This is because, as a general rule of thumb, you should always keep your ISR code short and fast. A rather common way of writing ISR's is to have them modify flags which are then polled by loop().

Untested Code !!!

#include <avr/interrupt.h>
#include <avr/io.h>


void setup() {
  pinMode(5, INPUT);
  Serial.begin(9600);

//pin change interrupt on digital pin 5
//this corresponds to PCINT2_vect
 PCICR |= (1 << PCIE2);
 PCMSK2 |= (1 << PCINT21);

}

volatile unsigned long counter = 0;
volatile bool print_flag = false;

ISR(PCINT2_vect)
{
      counter++;
        print_flag = true;
}

void loop()
{
      if(print_flag == true)
      {
            Serial.println(counter);
            print_flag = false;
      }

}

So this should increase the counter variable every-time the change interrupt fires (twice if we go from LOW to HIGH to LOW) if i understand this correctly?

Now how can i check fast if port 5 is HIGH or LOW, because i only want to increment the counter when the pin goes from LOW to HIGH?

I suppose DigitalRead in the ISR is not the way to go? Looking at the print_flag suggestion made by FusiveResonace, maybe I should also set a 2nd flag pinState = ???? inside the ISR, and check inside the loop if pinState is HIGH, only, what goes in place of the ???? ?

I know that's allot of questions, but I do wanna learn this stuff.

If anyone want's to know why I need this, I'll be happy to explain it.

Many greetings and thanks for the wonderful help so far.
EriSan500

PS: westfw, I corrected the comment :wink:

Read here for info on fast read of digital inputs...

You'll replace ???? with 'true'. Also note that this...
if (myValue == true)
when replaced by
if (myValue)
will evaluate as true as long as myValue is != 0.

I thought pointing out this optimization might help a little with the boolean logic concept in discussion here.

What I was looking for is this:

ISR(PCINT2_vect)
{
      counter++;
        print_flag = true;
        pinState = ???? //faster alternative for digitalread(5)
}

So I think what you are saying

You'll replace ???? with 'true'.

is not correct because pinState will allways be TRUE.

EriSan500

Sorry, 'true' that wasn't meant to be a direct injection into your code.

Rather...

ISR(PCINT2_vect)
{
    if (PIND & B00100000) // evaluates to TRUE when PortD bit #5 (Arduino digital pin #5) is HIGH
    {
        counter++;
        print_flag = true;
    }
}

Thanks Mitch_CA,

that was exactly what i was looking for.

To check for LOW instead of HIGH, I do this right? (or is there a leaner way?)

    if (PIND & B00100000 == LOW) // evaluates to TRUE when PortD bit #5 (Arduino digital pin #5) is LOW
    {
        counter++;
        print_flag = true;
    }
if (!(PIND & B00100000))...