ESP8266 Detecting which pin caused interrupt -Solution?

I have seen a couple of posts about this and I think I have a method that seems to work.

unsigned long previousMillis = 0;
const long interval = 200;
int pin12 = 12;
int pin14 = 14;
      
void *arg12 = &pin12;
void *arg14 = &pin14;

void setup() {

	        Serial.begin(115200);

            pinMode(pin12, INPUT_PULLUP);
            pinMode(pin14, INPUT_PULLUP);

            attachInterruptArg(digitalPinToInterrupt(pin12), ISR, arg12, CHANGE);
      		attachInterruptArg(digitalPinToInterrupt(pin14), ISR, arg14, CHANGE);

}

ICACHE_RAM_ATTR  void ISR(void * myarg){

    if (millis() - previousMillis >= interval) {
        printf("interrupt: = %d\n", *( (int*)myarg) );
        reviousMillis = millis();        
    }
}

void loop() 
{
}

Interested to hear feedback on this approach. Am I doing something stupid?

Thanks.

Links please?

No link, but see "...\esp8266\3.0.2\cores\esp8266\Arduino.h":

void attachInterruptArg(uint8_t pin, void (*)(void*), void* arg, int mode);

So, attachInterruptArg() takes an argument of type 'void *' that will be passed to the ISR when it's called.

https://forum.arduino.cc/t/esp8266-detecting-which-pin-caused-interrupt/683899?u=ear9mrn

A much more interesting application of attachInterruptArg() is the ability to call a class instance function (somewhat indirectly) as an ISR:

class MyClass {
public:
	MyClass(uint8_t p) : pin(p) {}

	void begin() {
		pinMode(pin, INPUT_PULLUP);
		attachInterruptArg(digitalPinToInterrupt(pin), classIsr, this, CHANGE);
	}

private:
	ICACHE_RAM_ATTR static void classIsr(void *p) {
		MyClass *ptr = (MyClass*) p;
		ptr->instanceIsr();
	}

	ICACHE_RAM_ATTR void instanceIsr() {
	}

	uint8_t pin;
};

Thanks. This look potentially much more useful. I am reaching the limit of my knowledge here. How do I get the value of the pin in the instanceIsr method?

I tried with;

ICACHE_RAM_ATTR static void classIsr(void *p) {
          MyClass *ptr = (MyClass*) p;
          ptr->instanceIsr(ptr->pin);      
        }

Followed by:

void ICACHE_RAM_ATTR instanceIsr(uint8_t thepin) {
          Serial.println("testing: " + String(thepin) + "\n" );
        }

But clearly that is wrong (compiler error)!.. any guidance would be gratefully appreciated.

Thanks.

Once you're inside an instance function -- in this case instanceIsr() -- you have access to all instance variables -- in this case 'pin'. No need to pass anything around.

I just realized there's an even slicker way to call instance function ISRs when using ESP8266 (or ESP32). That's by using FunctionalInterrupt.h. For example:

#include "FunctionalInterrupt.h"

class MyClass {
  public:
    MyClass(uint8_t p) : pin(p) {}

    void begin() {
      pinMode(pin, INPUT_PULLUP);
      std::function<void(void)> stdFunct {std::bind(&MyClass::instanceIsr, this)};
      attachInterrupt(digitalPinToInterrupt(pin), stdFunct, FALLING);
    }

    void poll() {
      if (fired) {
        fired = false;
        Serial.printf("Interrupt Fired on Pin %d\n", pin);
      }
    }

  private:
    volatile bool fired = false;
    IRAM_ATTR void instanceIsr() {
      fired = true;
    }

    uint8_t pin;
};

MyClass objects[] = {0, 4, 13, 12};

void setup() {
  Serial.begin(115200);
  delay(1000);
  for (MyClass &obj : objects) {
    obj.begin();
  }
}

void loop() {
  for (MyClass &obj : objects) {
    obj.poll();
  }
}

Slight variation with an array....

unsigned long previousMillis = 0;
const long interval = 200;

uint8_t pin12[] = {12,99};
uint8_t pin14[] = {14,66};

void *arg12 = &pin12;
void *arg14 = &pin14;

void setup() {

        Serial.begin(115200);

        pinMode(pin12[0], INPUT_PULLUP);
        pinMode(pin14[0], INPUT_PULLUP);

        attachInterruptArg(digitalPinToInterrupt(pin12[0]), ISR, arg12, CHANGE);
        attachInterruptArg(digitalPinToInterrupt(pin14[0]), ISR, arg14, CHANGE);

}

ICACHE_RAM_ATTR  void ISR(void * myarg){

    if (millis() - previousMillis >= interval) {

        uint8_t thepin = ((uint8_t *)myarg)[0];
        uint8_t val    = ((uint8_t *)myarg)[1];

        printf("interrupt: = %d, Value: %d\n", thepin, val );
        previousMillis = millis();

    }

}

void loop()
{
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.