How do I detect which pin caused an interrupt in the code below? I realize it's probably simple and can be improved on, but I wanted to better understand how to detect that a interrupt happened without having to write several ISR's and then just polling to see what ISR happened.
const uint8_t LedPin = 5; //Output LED
const uint8_t interruptPin[] = {4, 12, 13, 14}; //interrupt pins
volatile byte interruptCounter = 0;
int numberOfInterrupts = 0;
void ICACHE_RAM_ATTR handleInterrupt();
void setup() {
Serial.begin(115200);
int w;
for (int w = 0; w < 5; ++w)
{
pinMode(interruptPin[w], INPUT); //Set pinmode for each interrupt
Serial.print("w="); Serial.print(w); Serial.print(", value="); Serial.println(interruptPin[w]); //Print out pinmodes
//Call the same ISR when any pin is HIGH, CHANGE OR LOW depending on setting
attachInterrupt(digitalPinToInterrupt(interruptPin[w]), handleInterrupt, HIGH); //HIGH, CHANGE OR LOW
}
pinMode(LedPin, OUTPUT); //Set pin 5 to output
}
void handleInterrupt() {
interruptCounter++; //increment counter and exit quick
}
void loop() {
if(interruptCounter>0){ //Interrupt just happened
//
// Magic code to check which interrupt was triggered
// Do stuff depending on what pin was triggered
interruptCounter--; //reset the counter
numberOfInterrupts++; // add to interupt counter
Serial.print("An interrupt has occurred. Total: "); //Print out that an interupt happend
Serial.println(numberOfInterrupts);
digitalWrite(5, HIGH); // sets the digital pin 5 on
delay(1000); // waits for a second
digitalWrite(5, LOW); // sets the digital pin 5 off
delay(1000); // waits for a second
}
}
You need to digital read each of the four pins and see which one or ones are high. As per the code, they can interrupt on "high" signal. Realizing there could be one pin, or many pins giving the interrupt.
I can do it that way, and it'll work fine, however I'm trying to avoid polling all the ports to see which one was triggered. The processor knows what interrupt happened, I just need the be able to access that magic number. I have sort of read about it but don't quite understand the function, the way it works or how to call it. You know, the usual! lol
So my understanding is, when an interrupt occurs the processor stops and processes the interrupt, then resumes. While in the interrupt no other interrupts are running unless you specifically tell them to run, and if you do then you have the potential for endless interrupt loops, so it's best not to do that. Perhaps the interrupt could be read in the isr and put into the volatile variable? Once again there must be some method to request what the interrupt number is? Maybe just dump that into the variable?
Once again there must be some method to request what the interrupt number is?
The processor knows what interrupt happened, I just need the be able to access that magic number. I have sort of read about it but don't quite understand the function, the way it works or how to call it.
Please provide a link to the references for this "method".
I don't understand the question-- unless you want to do it the hard way.
Each interrupt is attached to its own ISR.
If you have more than one interrupt, the ISR should not be where the interrupt is processed because interrupts are disabled while in an ISR. Ideally the ISR is one line of code to set a flag. In your loop() function test the flags and handle the interrupts there.
You say you don't want to poll, but how is that any different (from an overhead perspective) than testing the interrupt number?
I guess I can't do that because as you say another interrupt could happen before getting to the code to ask what interrupt just happened. So plan b is the following. Basically I set up all the interrupts and set a flag if an interrupt happens, then poll all the interrupts, store the ones that have changed, reset the flags, then run some magic code and reset everything and wait for new interrupts. The only issue I think I have is combining the name handleInterrupt and the interrupt number as in handleInterrupt0,handleInterrupt1,handleInterrupt2,handleInterrupt3,handleInterrupt4
Pretty crude code I know, but I'm trying to make it as compact as possible so I can write all the rest of my kindergarten code. lol
const uint8_t LedPin = 5;
byte val = 0;
const uint8_t interruptPin[] = {4, 5, 12, 13, 14}; //Load interupt pin
byte int0, int1,int2,int3,int4=0;
volatile byte interruptCounter = 0;
int numberOfInterrupts = 0;
int w;
void ICACHE_RAM_ATTR handleInterrupt();
void setup() {
Serial.begin(115200);
for (int w = 0; w < 5; ++w)
{
// This code doesn't work, but I'm just trying to combine the name handleinterrupt and the number 0-4
char intnum ='w'; //0-4
char intname= "handleInterrupt" + intnum; //hopefully the string is "handleInterrupt0"
///eg handleInterrupt0, handleInterrupt1,handleInterrupt2,handleInterrupt3,handleInterrupt4
pinMode(interruptPin[w], INPUT);
Serial.print("w="); Serial.print(w); Serial.print(", value="); Serial.println(interruptPin[w]);
attachInterrupt(digitalPinToInterrupt(interruptPin[w]), intname, HIGH); //HIGH, CHANGE OR LOW
}
pinMode(LedPin, OUTPUT);
}
void handleInterrupt0() {
interruptCounter++;
}
void handleInterrupt1() {
interruptCounter++;
}
void handleInterrupt2() {
interruptCounter++;
}
void handleInterrupt3() {
interruptCounter++;
}
void handleInterrupt4() {
interruptCounter++;
}
void loop() {
if(interruptCounter>0){
for (int w = 0; w < 5; ++w)
{
val= digitalRead(interruptPin[w]);
if (val==1){ //read those values quickly before they change state again.
if (w == 0) int0 = 1;
if (w == 1) int1 = 1;
if (w == 2) int2 = 1;
if (w == 3) int3 = 1;
if (w == 4) int4 = 1;
interruptCounter--; //reset counter
numberOfInterrupts++; //increment number
Serial.print("An interrupt has occurred. Total: ");
Serial.println(numberOfInterrupts);
digitalWrite(5, HIGH); // sets the digital pin 5 on
delay(1000); // waits for a second
digitalWrite(5, LOW); // sets the digital pin 5 off
delay(1000); // waits for a second
}
// Now do some magic code based on results from reading inputs and reset int0-4 back to 0
}
}
}
Well, everything I've read says do whatever in the ISR quickly, so setting a flag is really quick. I could have 5 different flags and then see which one of the flags tripped, but I think it's just as quick to read the pins.
Once outside the isr, I can leisurely see which pin(s) it was in the main loop, and do whatever I want with the results.
My goal is a good understanding of interrupts and what I can do with them, and how to structure using them so the code is most efficient.
I also like the idea of one ISR function using variables instead of 5 ISR functions, but by the sounds of it I need 5 ISR functions to be able to read the pins properly. I also like to skinny up the code as much as possible, and make it universal and reusable, so I'm trying to think ahead. For most this is kindergarten code but ya gotta start somewhere!
Once outside the isr, I can leisurely see which pin(s) it was in the main loop, and do whatever I want with the results.
I could have 5 different flags and then see which one of the flags tripped, but I think it's just as quick to read the pins.
It depends on what is causing the interrupt, and how fast the pin changes from the state which caused the interrupt. "Leisurely" may not apply. A switch case in loop depending on the flag set may be more reliable and faster then reading the pins a second time.
The Arduino ESP8266 core code that handles he interrupt vector already knows which interrupt fired. That's how it knows to call the callback function supplied in the attachedInterrut() function. In fact, once the callback is invoked, it's probably impossible to determine which interrupt it was since the associated processor flags have likely been cleared already.
You're working very hard a solving a non-existent problem. Use a separate callback for each interrupt and within it set an individual ID flag for the main code to pick up (and clear).
I thought I'd get clever (lol) and clean up the code and load up several ISR's with the same for/next loop. The result is a compiled program that crashes and burns. It says ISR not in IRAM!
What am I doing wrong in declaring the IRAM stuff? I'm trying to set up a for/next loop to set up the pinmode and attachinterrupt functions without having to write each one, which looks pretty repetitive.
I can also then scan through the ISRs to see which one(s) are HIGH using the same sort of for/next loop.
const uint8_t LedPin = 5;
byte val = 0;
const uint8_t interruptPin[] = {4, 5, 12, 13, 14}; //Load interupt pin
//I think this is the problem.
void ICACHE_RAM_ATTR(*handleInterrupt[])(void)={&handleInterrupt0, &handleInterrupt1, &handleInterrupt2,&handleInterrupt3, &handleInterrupt4};
///looks good, compiles, but bad mojo!
//trying to avoid this to keep code compact
//void ICACHE_RAM_ATTR handleInterrupt0();
//void ICACHE_RAM_ATTR handleInterrupt1();
//void ICACHE_RAM_ATTR handleInterrupt2();
//void ICACHE_RAM_ATTR handleInterrupt3();
//void ICACHE_RAM_ATTR handleInterrupt4();
byte int0, int1,int2,int3,int4=0;
volatile byte interruptCounter = 0;
int numberOfInterrupts = 0;
int w;
void setup() {
Serial.begin(115200);
// This for/next loop below I'm trying to set the pin mode and attach interrupt for each ISR.
//If this doesn't work I guess I have to do each as
// pinMode(interruptPin0, INPUT);
// attachInterrupt(digitalPinToInterrupt(interruptPin0), handleInterrupt0, HIGH);
// and do the same for all the ISRs. Seems like a lot of repetition.
for (int w = 0; w < 5; ++w)
{
pinMode(interruptPin[w], INPUT);
Serial.print("w="); Serial.print(w); Serial.print(", value="); Serial.println(interruptPin[w]);
attachInterrupt(digitalPinToInterrupt(interruptPin[w]), handleInterrupt[w], HIGH); //HIGH, CHANGE OR LOW
Serial.print("handleInterrupt="); Serial.println('handleInterrupt[w]');
}
pinMode(LedPin, OUTPUT);
}
void handleInterrupt0() {
interruptCounter++;
}
void handleInterrupt1() {
interruptCounter++;
}
void handleInterrupt2() {
interruptCounter++;
}
void handleInterrupt3() {
interruptCounter++;
}
void handleInterrupt4() {
interruptCounter++;
}
void loop() {
if(interruptCounter>0){
for (int w = 0; w < 5; ++w)
{
val= digitalRead(interruptPin[w]);
if (val==1){ //read those values quickly before they change state again.
if (w == 0) int0 = 1;
if (w == 1) int1 = 1;
if (w == 2) int2 = 1;
if (w == 3) int3 = 1;
if (w == 4) int4 = 1;
interruptCounter--; //reset counter
numberOfInterrupts++; //increment number
Serial.print("An interrupt has occurred. Total: ");
Serial.println(numberOfInterrupts);
digitalWrite(5, HIGH); // sets the digital pin 5 on
delay(1000); // waits for a second
digitalWrite(5, LOW); // sets the digital pin 5 off
delay(1000); // waits for a second
}
// Now do some magic code based on results from reading inputs and reset int0-4 back to 0
}
}
}
Well, this works but doesn't look very nice. An awful lot of repetitive code to do a simple task, and that's without actually doing anything with the results except resetting the flag. The function is the same, but the former code does it without so many lines and repetition.
The object of the whole exercise is to better understand how to write ISR's so they are nice and compact and work well. Having to basically do everything long hand creates the potential for all sorts of silly mistakes in spelling, punctuation etc.
const uint8_t LedPin = 5;
byte val = 0;
void ICACHE_RAM_ATTR handleInterrupt0();
void ICACHE_RAM_ATTR handleInterrupt1();
void ICACHE_RAM_ATTR handleInterrupt2();
void ICACHE_RAM_ATTR handleInterrupt3();
void ICACHE_RAM_ATTR handleInterrupt4();
byte int0, int1,int2,int3,int4=0;
volatile byte interruptCounter0 = 0;
volatile byte interruptCounter1 = 0;
volatile byte interruptCounter2 = 0;
volatile byte interruptCounter3 = 0;
volatile byte interruptCounter4 = 0;
int numberOfInterrupts = 0;
int w;
void setup() {
Serial.begin(115200);
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(12, INPUT);
pinMode(13, INPUT);
pinMode(14, INPUT);
attachInterrupt(digitalPinToInterrupt(4), handleInterrupt0, HIGH); //HIGH, CHANGE OR LOW
attachInterrupt(digitalPinToInterrupt(5), handleInterrupt1, HIGH); //HIGH, CHANGE OR LOW
attachInterrupt(digitalPinToInterrupt(12), handleInterrupt2, HIGH); //HIGH, CHANGE OR LOW
attachInterrupt(digitalPinToInterrupt(13), handleInterrupt3, HIGH); //HIGH, CHANGE OR LOW
// attachInterrupt(digitalPinToInterrupt(14), handleInterrupt4, HIGH); //HIGH, CHANGE OR LOW
pinMode(LedPin, OUTPUT);
}
void handleInterrupt0() {
interruptCounter0++;
}
void handleInterrupt1() {
interruptCounter1++;
}
void handleInterrupt2() {
interruptCounter2++;
}
void handleInterrupt3() {
interruptCounter3++;
}
void handleInterrupt4() {
interruptCounter4++;
}
void loop() {
if (interruptCounter0==1) interruptCounter0--;
if (interruptCounter1==1) interruptCounter1--;
if (interruptCounter2==1) interruptCounter2--;
if (interruptCounter3==1) interruptCounter3--;
if (interruptCounter4==1) interruptCounter4--;
numberOfInterrupts++; //increment number
Serial.print("An interrupt has occurred. Total: ");
Serial.println(numberOfInterrupts);
digitalWrite(5, HIGH); // sets the digital pin 5 on
delay(1000); // waits for a second
digitalWrite(5, LOW); // sets the digital pin 5 off
delay(1000); // waits for a second
// Now do some magic code based on results from reading inputs and reset int0-4 back to 0
}
I agree about it working vs not working, but it's pretty klunky code. How would a pro handle the same basic function of declaring, loading, and executing these ISR functions? I'm sure there's a better way(maybe?).