Pin change interupts

I am making a project on arduino and I want to design a ISR(Interrupt Subroutine) based in the pin change. I cant use the attachInterrupt() because it is increasing the output time and size of the program considerably. I preferred directly using the AtMega 328P registries i.e PCICR but I am not able to understand it properly. My interrupt takes place in digital pins 8,9,10,11. Can anyone help me out with it?

No experience with attachInterrupt; the function can be found in C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\WInterrupts.c (on a windows system).

Analysing it will give you the insight that you need to do whatever you want to do.

Looking at it, there seems to be very little that attachInterrupt can do to slow your code down (or increase the size of the code significantly). You might have another problem and I suggest that you show us your current code where you think attachInterrupt slows your code down (please use code tags when posting your code).

I have written some code that handles interrupts on any pin with several examples all are tested.
try these out.

I am interested in discovering your needs so that I may continue to add and improve this code.

this code has 3 parts
first part is the interrupt capture just like when attachInterrupts() is triggered it calls a function. instead of naming a function I am creating an anonymous function this is done with the ( ) and { } this is also known as a lambda function. in this case when any pin is interrupted this function is called and ti triggers the second part PinCallBack

  Interrupt.onInterrupt([ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    sei(); // re enable other interrupts at this point,
    Interrupt.PinCallBack(Time, PinsChanged, Pins);
  });

The second part handles all the work in managing the pins as well as creating an anonymous function to run every time this pin is changed at time of the interrupt. one advantage is that multiple pins could change at the same time.

This example we are activating the interrupt on pin 4 with pull up activated When this triggers we are passing the exact microsecond time and the pins that changed and all the pins states for the function to use. The function check to see if pin 4 is HIGH or LOW and outputs a value. (Note that I have re-enabled interrupts so serial will work. )

  Interrupt .onPin(4, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    if (Interrupt.CheckPin(4)) { // rising
      Serial.println(" Pin 4 Rising \t");
    } else { // Falling
      Serial.println(" Pin 4 Falling \t");
    }
  });

and part 3 consists of useful function to help with things like Ping sensors, Encoders, Switches, RC Remote Receiver input and more.

  Interrupt .onPin(12, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    EncoderCounter += Interrupt.Encoder(12, 13, Pins, true);
    Serial.print("Count ");
    Serial.print(EncoderCounter);
    Serial.print("\t Encoder \t");
    Serial.println(Interrupt.Encoder(12, 13, Pins, true));

  });
  Interrupt .onPin(13, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    EncoderCounter -= Interrupt.Encoder(12, 13, Pins, true);
    Serial.print("Count ");
    Serial.print(EncoderCounter);
    Serial.print("\t Encoder \t");
    Serial.println(-1 * Interrupt.Encoder(12, 13, Pins, true));


  });

Full Example code:

#include "Interrupts.h"
InterruptsClass Interrupt;
volatile long EncoderCounter = -2;
float microsecondsToInches(long microseconds)
{
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second).  This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return (float) microseconds / 74 / 2;
}

float microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return (float)microseconds / 29 / 2;
}

void setup() {
  Serial.begin(115200); //115200
  // put your setup code here, to run once:
  pinMode(7, OUTPUT);
  Interrupt.onInterrupt([ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    sei(); // re enable other interrupts at this point,
    Interrupt.PinCallBack(Time, PinsChanged, Pins);
  });
  Interrupt .onPin(4, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    if (Interrupt.CheckPin(4)) { // rising
      Serial.println(" Pin 4 Rising \t");
    } else { // Falling
      Serial.println(" Pin 4 Falling \t");
    }

  });
  Interrupt .onPin(5, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    uint16_t RCTime =  Interrupt.RCRemote(5, Time, Pins, true);
    if (RCTime) {
      Serial.print(" RC Time:");
      Serial.print(RCTime);
    }
  });
  Interrupt .onPin(8, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    unsigned int PingTime = Interrupt.Ping(8, Time, Pins);
    if (PingTime) {
      Serial.print("Ping \t");
      Serial.print(microsecondsToCentimeters(PingTime));
      Serial.println("cm");
    }
  });
  Interrupt .onPin(9, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    Serial.print("Switch \t");
    Serial.println(Interrupt.Switch(9, Time, 1000, false));

  });
  Interrupt .onPin(10, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    Serial.print("Switch \t");
    Serial.println(Interrupt.Switch(10, Time, 1000, false));

  });
  Interrupt .onPin(11, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    Serial.print("Switch \t");
    Serial.println(Interrupt.Switch(11, Time, 1000, false));

  });
  Interrupt .onPin(12, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    EncoderCounter += Interrupt.Encoder(12, 13, Pins, true);
    Serial.print("Count ");
    Serial.print(EncoderCounter);
    Serial.print("\t Encoder \t");
    Serial.println(Interrupt.Encoder(12, 13, Pins, true));

  });
  Interrupt .onPin(13, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    EncoderCounter -= Interrupt.Encoder(12, 13, Pins, true);
    Serial.print("Count ");
    Serial.print(EncoderCounter);
    Serial.print("\t Encoder \t");
    Serial.println(-1 * Interrupt.Encoder(12, 13, Pins, true));


  });


}

void loop() {
  // put your main code here, to run repeatedly:
  int t = 100;
  static unsigned long _ETimer;
  if ( millis() - _ETimer >= (t)) {
    _ETimer += (t);


    digitalWrite(7, LOW);
    delayMicroseconds(1);
    // digitalWrite(7, HIGH); // Trigger another pulse
    delayMicroseconds(5);
    digitalWrite(7, LOW);
  }
}

Z

Interrupts.h (5.44 KB)

Interrupts.cpp (6.57 KB)

// at top of sketch, global variables:
volatile byte lastPinState; // we need a volatile variable to keep tabs on the last state of the pins, so we can figure out which pin changed

// inside setup:

PCMSK0=0x0F; //enable it on PCINT 0~3, leave it disabled on 4~7
lastPinState=PINB&0x0F; //read port B, mask off PB4~PB7
PCICR=1; //set PCIE0 to enable PCINTs on PCINT 0~7

// and the ISR itself:

ISR(PCINT0_vect) {
 //here you write your ISR
//Read the pins, and compare to lastPinState - determine which pin changed, and do what you need to do about it. Then update lastPinState. 


}

Really quick demo. There's nothing magic about it; it's not particularly hard - Port reads are your friend.

Also, I love how OP specifically stated wanting to do it bare metal, and everyone has answered with libraries.

DrAzzy:
Also, I love how OP specifically stated wanting to do it bare metal, and everyone has answered with libraries.

Read my reply again :wink:

Did you see this recent thread?