Port interrupts how to?

Hi I want to know how to handle ports interrupts. In my new project I'm using int0 & int1 and I want to use port interrupt for handling buttons.

What I need

AttachPortInterrupt(PORTD,buttons,RISING)

void buttons() { ... }

I prefer code than library because now I'm using Mega but finally I'll use Sanguino (atm644)

you can't use attachInterrupt inside class... I'm using the ISR() function, is a little more low level but it works ;)

This is only for showing what I mean.

Yes I know that it 'll be more complex, can You show how You use it?

i use that class to read PPM channel:

InputPin.cpp

#include "InputPin.h"
#include "Utils.h"
/*
Let You read digital pin 2,4,5,6
FROM BIRONPILOT V59, tnx to ciskje
*/

//#define MAXUNSIGNEDLONGCVALUE 4294967295
#define MASKPCINT0 (1<<2)
#define MASKPCINT1 (1<<4)
#define MASKPCINT2 (1<<5)
#define MASKPCINT3 (1<<6)


//define necessary values
#define MIN_RADIO_VALUE 1100
#define MAX_RADIO_VALUE 1950
#define maxReceiverAngle 0.5f
//maxReceiverAngle is in radiant

Utils utils;

InputPin::InputPin(){
  pinMode(2, INPUT); // 3 is used for esc
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  // interrupt on pin change FROM PCINT16 to PCINT23
  PCICR |= (1 << PCIE2);

  PCMSK2 = (1 << PCINT18) | // digital pin2
  (1 << PCINT20) | // digital pin4
  (1 << PCINT21) | // digital pin5
  (1 << PCINT22); // digital pin6
}

//putted here because interrupt dosn't want it in .h
unsigned long _startIn[4];
unsigned long _rawIn[4];
unsigned long _time;
byte _oldbit=0, _newbit, _changed;
volatile boolean _hasChanged=false;

ISR(PCINT2_vect) {
  _time=micros();
  
  _newbit=PIND;
  _changed=_newbit^_oldbit;
  
  if (_changed&MASKPCINT0){//if digital PIN2 has changed

    if (_newbit&MASKPCINT0) { //if PIN2 now is high
      _startIn[0]=_time;
    }else{
      _rawIn[0]=_time-_startIn[0];
    }
    _hasChanged=true;
  }

  if (_changed&MASKPCINT1){//if digital PIN4 has changed
    if (_newbit&MASKPCINT1) 
      _startIn[1]=_time;
    else 
      _rawIn[1]=_time-_startIn[1];
    _hasChanged=true;
  }
  
  if (_changed&MASKPCINT2){//if digital PIN5 has changed
    if (_newbit&MASKPCINT2) 
      _startIn[2]=_time;
    else 
      _rawIn[2]=_time-_startIn[2];
    _hasChanged=true;
  }

  if (_changed&MASKPCINT3){//if digital PIN6 has changed
    if (_newbit&MASKPCINT3) 
      _startIn[3]=_time;
    else 
      _rawIn[3]=_time-_startIn[3];
  }
  _oldbit=_newbit;
}

bool InputPin::getAndSetFalseHasChanged(){
  bool temp = _hasChanged;
  _hasChanged = false;
  return temp;
}

int InputPin::getDuration(int i){
  return _rawIn[i];
}

int InputPin::getDuration(int i, int minValue, int maxValue){
  return map(_rawIn[i] , MIN_RADIO_VALUE, MAX_RADIO_VALUE, minValue, maxValue );
}

float InputPin::getAngle(int i){
  return utils.mapFloat( _rawIn[i], MIN_RADIO_VALUE, MAX_RADIO_VALUE, -maxReceiverAngle, maxReceiverAngle );
}

InputPin.h

#ifndef InputPin_h
#define InputPin_h


#include "WProgram.h"

class InputPin{
  
  public:
    InputPin();
    bool getAndSetFalseHasChanged(); // send the initilization handshake
    int getDuration(int); //return the raw duration of high signal, input: channel
    float getAngle(int); //return the duration mapped from -PI to PI, input: channel
    int getDuration(int, int, int); //return the duration mapped in the range, input: channel, min value, max value
  private:
};
#endif

Thank You for the code it is very usefull :slight_smile:
There is problem when compiling with Utils utils compiler says that Utils does not name a type (arduino 0.21)
Also how to mask outher pins not only 2.4.5.6 ? :slight_smile:

Utils is a my own class that you don't need. delete the include, and all function using the class utils

With help from lesto i managed to run port change interrupts on Arduino MEGA :slight_smile:

Here is code for Interested :slight_smile:

#define B_up A8
#define B_down A9
#define B_left A10
#define B_right A11

void setupPortInt()
{
pinMode(B_up, INPUT);
pinMode(B_down, INPUT);//!!! ALL THOSE PINS MUST BE GROUNDED WITH PULLDOWN RESISTORS!
pinMode(B_left, INPUT);
pinMode(B_right, INPUT);
//SETINGS FOR MEGA interrupts on port change A8-A15(PCINT16-23)
PCMSK2 |= (1 << PCINT16) | // analog a8
(1 << PCINT17) | // a9
(1 << PCINT18) | // a10
(1 << PCINT19); // a11 (
PCICR |= (1 << PCIE2);
}

//Port interrupt function
int count[4];
ISR(PCINT2_vect)
{
_time=millis();//For futher use in debouncing
if(digitalRead(A8)==HIGH) count[0]++;
if(digitalRead(A9)==HIGH) count[1]++;
if(digitalRead(A10)==HIGH) count[2]++;
if(digitalRead(A11)==HIGH) count[3]++;
}
//----------------

Just activate the interrupts with setupPortInt() and write what arduino should do in ISR function

there is a big error. if you do

if(digitalRead(A8)==HIGH) count[0]++;
  if(digitalRead(A9)==HIGH) count[1]++;
  if(digitalRead(A10)==HIGH) count[2]++;
  if(digitalRead(A11)==HIGH) count[3]++;

inside the ISR you have 2 problem: first of all you are doing another non-nessesary function, as with

_newbit=PIND;
  _changed=_newbit^_oldbit;

you have in _changed all pin that has changed state (and all in one hit!)

seconds, digitalread is slow, and this is bad for timer.

Thanks :) I think that my code is bad but simpler to understand for beginers :) Yours is great :)