Multiple external interrupt with same ISR

I am trying to send an email when either one digital pin value is changed. (Even Low to High or reverse)
However, the below 1st code is successful but 2nd code is unsuccessful
2nd code cannot trigger the email normally when D0 and D1 either Low or High
Because I would like to reduce the code as I can, I would use all pins for the ESP8266 board.

Void email()
{
int content = digitalread(D0)
if (content == HIGH)
{
    String body = "XXX";
    Blynk.email(email address, "Subject", body);

  }
else
{
    String body = "YYY";
    Blynk.email(email address, "Subject1", body);

  }
}

Void email1()
{
int content1 = digitalread(D1)
if (content1 == HIGH)
{
    String body = "WWW";
    Blynk.email(email address, "Subject", body);

  }
else
{
    String body = "ZZZ";
    Blynk.email(email address, "Subject1", body);

  }
}
void setup()
{
  pinMode(D0, INPUT);
  pinMode(D1, INPUT);
  attachInterrupt(digitalPinToInterrupt(D0), email, CHANGE);
  attachInterrupt(digitalPinToInterrupt(D1), email1, CHANGE);
}
Void email()
{
int content = digitalread(D0)
int content1 = digitalread(D1)
if (content == HIGH)
{
    String body = "XXX";
    Blynk.email(email address, "Subject", body);

  }
else
{
    String body = "YYY";
    Blynk.email(email address, "Subject1", body);

  }
if (content1 == HIGH)
{
    String body = "WWW";
    Blynk.email(email address, "Subject", body);

  }
else
{
    String body = "ZZZ";
    Blynk.email(email address, "Subject1", body);

  }
}


void setup()
{
  pinMode(D0, INPUT);
  pinMode(D1, INPUT);
  attachInterrupt(digitalPinToInterrupt(D0), email, CHANGE);
  attachInterrupt(digitalPinToInterrupt(D1), email, CHANGE);
}

However, my idea is like that, should I better to use virtual pins to store the email content?

Please give a description of how it is unsuccessful.

Your codes are missing semi-colons so will not compile; they're also missing loop() but I guess it's empty.

I suspect that you should not use interrupts for this. ISRs should be short (time-wise) and I think that calling Blynk functionality is slow.

From what I can understand from your code, just read the buttons in loop() and react on that.

PS
no experience with Blynk or ESP.

Sorry that I missed the core code like, loop()
I have included it already

Unsuccessful means when I changed the pin from Low to High (input 3.3V)
no email is received.

Ps. is any problem that an email is sent after 30s ~ 1min when the pin value is changed?
quite slow since the WiFi is stable

If your ISR is stuck for 30 seconds, it's extremely slow. ISRs should be below 1 ms or faster. But 30 seconds delivery time is not the same as 30 seconds stuck in the ISR.

The main difference between your two codes is that the second code will always (try to) send two emails when the state of one of the two buttons changes; one for each of the buttons.

As said, no experience with the specifics and hence I can't help further.

Keep your ISRs small and do the "heavy" processing in the mainline.

BTW, I don't believe you can tie two pins to the same ISR; you can try but I think the 2nd will simply replace the first.

So with 2 ISRs, maybe this would work (not compiled, not tested):

#include...

String emailaddress = "foo@foobar.edu"
//
String subject1 = "Subject";
String subject2 = "Subject1";
//
String bodyWWW = "WWW" );
String bodyXXX = "XXX" );
String bodyYYY = "YYY" );
String bodyZZZ = "ZZZZ" );

volatile byte
    bFlag1,
    bFlag2;
    
void setup()
{
    pinMode(D0, INPUT);
    pinMode(D1, INPUT);
    //
    attachInterrupt(digitalPinToInterrupt(D0), email_1, CHANGE);
    attachInterrupt(digitalPinToInterrupt(D1), email_2, CHANGE);
    //
    bFlag1 = 0;
    bFlag2 = 0;

}//setup

void loop()
{
    if( bFlag1 & 0x01 )
    {
        Blynk.email(    emailaddy, 
                        (bFlag1 & 0x02)?subject1:subject2, 
                        (bFlag1 & 0x02)?bodyXXX:bodyYYY );
                    
        noInterrupts();
        bFlag1 = 0;
        interrupts();
                
    }//if

    if( bFlag2 & 0x01 )
    {
        Blynk.email(    emailaddy, 
                        (bFlag2 & 0x02)?subject1:subject2, 
                        (bFlag2 & 0x02)?bodyWWW:bodyZZZ );
                    
        noInterrupts();
        bFlag1 = 0;
        interrupts();
                
    }//if
            
}//loop

void email_1( void )
{
    bFlag1 = 0x01;
    if( digitalread(D0) )
        bFlag1 |= 0x02;
    
}//email_1

void email_2( void )
{
    bFlag2 = 0x01;
    if( digitalread(D1) )
        bFlag2 |= 0x02;
}//email_2

Blackfin:
Keep your ISRs small and do the "heavy" processing in the mainline.

BTW, I don't believe you can tie two pins to the same ISR; you can try but I think the 2nd will simply replace the first.

So with 2 ISRs, maybe this would work (not compiled, not tested):

#include...

String emailaddress = "foo@foobar.edu"
//
String subject1 = "Subject";
String subject2 = "Subject1";
//
String bodyWWW = "WWW" );
String bodyXXX = "XXX" );
String bodyYYY = "YYY" );
String bodyZZZ = "ZZZZ" );

volatile byte
    bFlag1,
    bFlag2;
   
void setup()
{
    pinMode(D0, INPUT);
    pinMode(D1, INPUT);
    //
    attachInterrupt(digitalPinToInterrupt(D0), email_1, CHANGE);
    attachInterrupt(digitalPinToInterrupt(D1), email_2, CHANGE);
    //
    bFlag1 = 0;
    bFlag2 = 0;

}//setup

void loop()
{
    if( bFlag1 & 0x01 )
    {
        Blynk.email(    emailaddy,
                        (bFlag1 & 0x02)?subject1:subject2,
                        (bFlag1 & 0x02)?bodyXXX:bodyYYY );
                   
        noInterrupts();
        bFlag1 = 0;
        interrupts();
               
    }//if

if( bFlag2 & 0x01 )
    {
        Blynk.email(    emailaddy,
                        (bFlag2 & 0x02)?subject1:subject2,
                        (bFlag2 & 0x02)?bodyWWW:bodyZZZ );
                   
        noInterrupts();
        bFlag1 = 0;
        interrupts();
               
    }//if
           
}//loop

void email_1( void )
{
    bFlag1 = 0x01;
    if( digitalread(D0) )
        bFlag1 |= 0x02;
   
}//email_1

void email_2( void )
{
    bFlag2 = 0x01;
    if( digitalread(D1) )
        bFlag2 |= 0x02;
}//email_2

What is the use of bFlag and meaning for 0x01?

dangerngai:
What is the use of bFlag and meaning for 0x01?

oh i got it.
Is ESP8266 can only send a 8-bit value?
How about if I want to use all 11 digital pins in ESP8266

dangerngai:
What is the use of bFlag and meaning for 0x01?

You can use bits within a variable (bFlag in this case) to indicate something has happened and/or the level of something.

In this case, I used bit 0 (0x1) to indicate an interrupt had occurred and bit 1 (0x2) to indicate what the level of the pin was as read in the ISR. The mainline code (loop()) looks for an interrupt to have happened (0x1) and knows what subject line and body content to send (0x2).

Why didn't you post your code?
The code you're actually using?

Blackfin:
BTW, I don't believe you can tie two pins to the same ISR; you can try but I think the 2nd will simply replace the first.

Never tried it but I don't see why you can't. Don't mix up interrupt vectors with ISRs! Each individual GPIO pin on the ESP8266 (with the exception of GPIO16) can produce interrupts on rising, falling, or change. As far as I know there's nothing against having them all call the same ISR to deal with the interrupt.

Not that I know why one would actually want to do this, or why you would want to use interrupts to trigger something as slow as sending an e-mail, except when the signals on the pins are so short they can be missed when polling. If you must use interrupts to deal with the signals for whatever compelling reason (if you don't know why you should use interrupts you probably don't need them) all the ISR should do is set a flag indicating the event happened, and then let loop() deal with it.

wvmarle:
Never tried it but I don't see why you can't.

Yep, you're right. This works fine on a 2560; they should all be the same:

volatile byte
    bFlag;
    
void setup()
{
    Serial.begin(9600);
    pinMode( 2, INPUT_PULLUP );
    pinMode( 3, INPUT_PULLUP );
    attachInterrupt(digitalPinToInterrupt(2), ISR_pinHandler, FALLING );
    attachInterrupt(digitalPinToInterrupt(3), ISR_pinHandler, FALLING );
    bFlag = 0;
}

void loop()
{
    if( bFlag )
    {
        Serial.print( "Got interrupt: " ); Serial.print( (bFlag & 1) ? "Pin 2":"" );  Serial.println( (bFlag & 2) ? "Pin 3":"" ); 
        noInterrupts();
        bFlag = 0;
        interrupts();
    }
        
}

void ISR_pinHandler( void )
{
    if( digitalRead(2) == LOW )
        bFlag |= 0x1;
    if( digitalRead(3) == LOW )
        bFlag |= 0x2;
}

It seems like "not a good idea" but can definitely be done. Thanks for the clarification.

wvmarle:
Never tried it but I don't see why you can't. Don't mix up interrupt vectors with ISRs! Each individual GPIO pin on the ESP8266 (with the exception of GPIO16) can produce interrupts on rising, falling, or change. As far as I know there's nothing against having them all call the same ISR to deal with the interrupt.

Not that I know why one would actually want to do this, or why you would want to use interrupts to trigger something as slow as sending an e-mail, except when the signals on the pins are so short they can be missed when polling. If you must use interrupts to deal with the signals for whatever compelling reason (if you don't know why you should use interrupts you probably don't need them) all the ISR should do is set a flag indicating the event happened, and then let loop() deal with it.

As I just a beginner, I don't know whether using interrupts is the best method for my project.
My idea is just sample, Dry contact (3.3V) to 10 GPIO on ESP8266, each pin becomes HIGH will trigger an email to notify user what happen now.
Therefore

attachInterrupt(digitalPinToInterrupt(D0), email, CHANGE);
attachInterrupt(digitalPinToInterrupt(D1), email, CHANGE);
.
.
.
attachInterrupt(digitalPinToInterrupt(D9), email, CHANGE);

I dont know will above codes delay the operation or not.

As a rule of thumb: you don't need interrupts.

If you actually do need interrupts, you will know you do and why.

For sending e-mails, you quite certainly don't need interrupts. You also probably don't want to send e-mails twice for ever pulse received on an input.

Hi everyone,

As D3 and D4 pin have a pull up resistor internally it will return HIGH from digitalRead.
However, my project needs to know the I/Os from 0V to 3.3V to trigger email sending.

I have coding the following, but it still returns HIGH or measured 3.3V using multimeter.
Is there any other methods to setup D3/D4 in Low (0V) initially?

//Just part of codes
void setup()
pinmode(D3, INPUT);
digitalWrite(D3, LOW);

No idea about your code snippet; no experience with ESP.

But I don't understand what your problem is?

Blackfin:
You can use bits within a variable (bFlag in this case) to indicate something has happened and/or the level of something.

In this case, I used bit 0 (0x1) to indicate an interrupt had occurred and bit 1 (0x2) to indicate what the level of the pin was as read in the ISR. The mainline code (loop()) looks for an interrupt to have happened (0x1) and knows what subject line and body content to send (0x2).

For my code, the procedure is:

  1. initial state, B1Fault & B2Fault is LOW (0V), email content is 0
  2. I get the B1Fault to HIGH, email content is 1
  3. I get the B2Fault to HIGH, email content is 3 (0001 |= 0010, is 3)
  4. However when I get the B1Fault into LOW, the email content is still 3, my expected value is 2 (0010)
  5. Even I get the B2Fault into Low too, the email content is still 3, my expected value is 0 (0000)

How can I keep refresh the value of bFlag to update the content of the email?
Below is my codes

#define BLYNK_PRINT Serial

//#define BLYNK_MAX_SENDBYTES 128

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>


char auth[] = "token"; 
char ssid[] = "wifi";
char pass[] = "pass";

const String SiteNo = "SK68";
int B1Fault = digitalRead(14); //Air Blower No.1
int B2Fault = digitalRead(12); //Air Blower No.2
volatile byte bFlag1; //Status of air blower 1
volatile byte bFlag2; //Status of air blower 2
volatile byte bFlag; //Status of whole system

void setup()
{
  // Debug console
  Serial.begin(115200);
  Blynk.begin(auth, ssid, pass);
  Blynk.email("xxx@gmail.com", String(SiteNo) + "Online", "online.");
  Blynk.notify(String(SiteNo) + " online");
  pinMode(14, INPUT); //Initial is 0V
  pinMode(12, INPUT); //Initial is 0V
  attachInterrupt(digitalPinToInterrupt(14), email_B1, CHANGE);
  attachInterrupt(digitalPinToInterrupt(12), email_B2, CHANGE);
  bFlag1 = 0x00; //default value 0
  bFlag2 = 0x00; //default value 0
}
void email_B1()
{
  if (B1Fault == HIGH) //if this pin is 3.3V
    bFlag1 |= 0x01; //this byte changes to 0000 0001
   else
    bFlag1 |= 0x00; //if this pin is 0v, changes to 0000 0000
  
}

void email_B2()
{
  if (B2Fault == HIGH) //if this pin is 3.3V
    bFlag2 |= 0x02; //this byte changes to 0000 0010
   else
    bFlag2 |= 0x00; //if this pin is 0v, changes to 0000 0000
  
}

void loop()
{
  
    {
   bFlag = bFlag1 |= bFlag2; //status is logical OR within air blower 1 & 2
   //refresh an email in every 20 seconds
   Blynk.email("xxx@gmail.com", String(SiteNo), bFlag);
   Blynk.notify(String(SiteNo) + " alarm sent");
   Serial.println("Email is sent.");
   delay(20000);
   noInterrupts();
        bFlag = 0;
   interrupts();
}
  Blynk.run();
  
}

sterretje:
No idea about your code snippet; no experience with ESP.

But I don't understand what your problem is?

D3 and D4 pin is always HIGH on ESP8266 (because of inside pull up resistor)
But I would like to know the status of a 3.3V input signal to D3/D4
If they always be HIGH, even I put in an external 3.3V signal on it, it still HIGH (no change)

Because I want to sent an email when D3/D4 is changed from HIGH to LOW or reverse.

If they always be HIGH, even I put in an external 3.3V signal on it

Don't you mean "an external 0.0V signal" ?

If something is HIGH, putting another HIGH on it won't change the pin's state, or make it HIGHer.

Short the pin to ground and check for LOW instead of for HIGH. With pull-up resistors, the logic is reversed.

dangerngai:
As D3 and D4 pin have a pull up resistor internally it will return HIGH from digitalRead.

All pins have an internal pull-up resistor that can be enabled on demand (using the INPUT_PULLUP mode) except GPIO16 (D0 on NodeMCU) which as a internal pull-down resistor.

D3 = GPIO0, that one has an external pull-up resistor to allow for proper boot. It can be pulled down by pressing the FLASH button, as required to go in program mode. This pull-up can not be disabled.

D4 = GPIO2, that one requires to be pulled high upon boot, it has its internal pull-up resistor enabled during boot for this. There is no need for an external pull-up resistor, and I'm not aware of the NodeMCU having one.