• Skip to main content
  • Skip to primary sidebar

RNTLab.com

The Ultimate Shortcut to Learn Electronics and Programming with Open Source Hardware and Software

  • Courses
  • Forum
    • Forum
    • Ask Question
  • Shop
  • Account
  • Blog
  • Login

NodeMCU ESP8266 Interrupts not working correctly

Q&A Forum › Category: ESP8266 › NodeMCU ESP8266 Interrupts not working correctly
0 Vote Up Vote Down
Steve Angell asked 5 years ago

Hello All.

This is my first time posting as I just joined yesterday. I just received a few NodeMCU ESP8266 modules and right off the bat I am having troubles with interrupts. They do not seem to work the same as Arduino as I was lead to believe. I am not sure how to paste my code in here, but I will do my best and If I mess up hopefully someone can tell me the correct way to do it.

The issue I have is when I put a 10 – 30 Hz signal into the interrupt pin, the digital output XMitLED which is in the interrupt routine will only pulse once in a while. So slowly I have a hard time finding the signal with my scope. I should be getting a pulse on every positive edge of my sensor signal which is feeding the interrupt pin.

Hopefully someone can help me understand what I am doing wrong. Thanks in advance for any help.

void setup(void)
{

  pinMode(flowsensor, INPUT_PULLUP);               // Use optional Internal Pull-Up.
  pinMode(XMitLED,OUTPUT);                         // Use built in LED to indicate data being transmitted.               
  digitalWrite(XMitLED, HIGH);
  Serial.begin(115200);                              // Set serial baud rate to computer.
  //BTserial.begin(38400);                           // HC-06 serial speed set to 38400. 

  attachInterrupt(digitalPinToInterrupt(flowsensor), flow, RISING);                // Setup Interrupt
  interrupts();                                    // Enable interrupts
  currentTime = millis();
  loopTime = currentTime;
} // End of setup     

Start your code here

void loop(void)
{
currentTime = millis();
// Every second, calculate and send data.
if(currentTime >= (loopTime + 1000)) {
loopTime = currentTime; // Updates loopTime
// Calculate water flow.
oneSecond = flow_frequency / 3785.412;
totalFlowValue += oneSecond;

flow_frequency = 0; // Reset Counter
#ifdef DEBUG
Serial.print(oneSecond, 2); // Print gallons/second
Serial.print(" Gal/Sec ");
Serial.print(totalFlowValue, 2);
Serial.println(" Total Gals Used.");
#endif
}

/*****************************************************************
 * Interrupt routine for water flow sensor
 * Interrupt rate is 29.5735 pulses/ounce.
 */
ICACHE_RAM_ATTR void flow()
{
  digitalWrite(XMitLED, HIGH);
  flow_frequency++;
  digitalWrite(XMitLED, LOW);
  Serial.print(".");
}
Question Tags: Interrupts
10 Answers
0 Vote Up Vote Down
Sara Santos Staff answered 5 years ago

Hi.

Which pins are you using for the flowmeter and for the output LED?

In your flow() function, the XMitLED doesn’t have any time to send a signal. Try to add a delay between the digitalWrite(XMitLED, HIGH); and digitalWrite(XMitLED, LOW); depending on how long you want your output pulse to be.

I hope I’m understanding this correctly.

Let me know if this helps.

Regards,
Sara

0 Vote Up Vote Down
Steve Angell answered 5 years ago

Hi Sara.
Thanks for responding. I think you understood. What I expected was a very short 50uS-100uS pulse, which would be fine. Anyway, I have the interrupts working now as of late last night. The code I posted here was a couple programs mashed together and I think I just missed something somehow. I wrote a new one with just the interrupt and the led output and it worked. So I have to believe I just missed something somewhere.
Thanks again for the reply.
Now I am on to the next issue. Stay tuned for that question. 🙂
 

0 Vote Up Vote Down
Sara Santos Staff answered 5 years ago

Hi Steve.
I’m happy everything is working now.
I’ll close this issue. 
If you need further help, you just need to open a new question.
Regards,
Sara

0 Vote Up Vote Down
Steph answered 5 years ago

Hi, Steve & Sara,

I don’t think using a delay() in an interrupt handler is a good idea. Let me explain:

You must not lose sight of one very important thing about interrupt handlers: when an interrupt is triggered and handled by its routine, the normal execution of the main program is interrupted! At that point, the interrupt routine takes control and runs. Once the routine has finished, the main program resumes control and runs normally again (until the next interruption). It is therefore crucial to ensure that an interrupt routine runs as quickly as possible so that it does not disrupt the normal course of the main program too much. Here, the delay() function is also blocking! The microcontroller is therefore unable to do anything else but wait for the pause to end . This management can be extremely penalizing and generate undesirable behaviors. The delay() function is therefore to be avoided here!

Here is another way to proceed:

// ----------------------------------------------------------------------------------
// Definition of useful pins
// ----------------------------------------------------------------------------------

#define LED_PIN         LED_BUILTIN // to be replaced by the pin of your choice
#define FLOW_SENSOR_PIN 33          // to be replaced by the pin of your choice

// ----------------------------------------------------------------------------------
// Definition of global constants and variables
// ----------------------------------------------------------------------------------

const uint8_t FLASH_DURATION = 5; // milliseconds

uint32_t flowCount;
uint32_t lastMeasureTime;
bool     flashing;

// ----------------------------------------------------------------------------------
// Interruption manager
// ----------------------------------------------------------------------------------

void IRAM_ATTR flow() {
    digitalWrite(LED_PIN, HIGH);
    flowCount++;
    lastMeasureTime = millis();
    flashing        = true;
}

// ----------------------------------------------------------------------------------
// Initialization
// ----------------------------------------------------------------------------------

void setup() {
    pinMode(LED_PIN, OUTPUT);
    pinMode(FLOW_SENSOR_PIN, INPUT_PULLUP);

    flowCount       = 0;
    lastMeasureTime = 0;
    flashing        = false;

    attachInterrupt(digitalPinToInterrupt(FLOW_SENSOR_PIN), flow, RISING);
}

// ----------------------------------------------------------------------------------
// Main control loop
// ----------------------------------------------------------------------------------

void loop() {
    if (flashing) {
        if (millis() - lastMeasureTime > FLASH_DURATION) {
            digitalWrite(LED_PIN, LOW);
            flashing = false;
        }
    }
}

Here, the length of time the LED is on may be important, depending on the frequency of the signal you are measuring. For the demo, I have set it to 5 ms, which allows you to distinguish a signal whose frequency is lower than 1000 / 5 = 200 Hz. Of course, if the frequency of your signal is higher, the LED will appear permanently lit.

Hopefully this will answer your question about how to manage what you want to do correctly.

0 Vote Up Vote Down
Steve Angell answered 5 years ago

Hi Stephane.
Thanks for your explanation, although I do not believe I have a delay() function in my interrupt routine. Maybe I copied the code to the forum incorrectly. I do know you never want anything like delay in the interrupt routine. I never use print statements either except here I did just to see if I was getting into the routine. Because I just bought a new USB scope I was not sure I had it set up correctly to capture the short LED pulse I expected.
Anyway, it is working now. I am very new to the NodeMCU ESP8266 module and I am sure I just missed something somewhere. Thanks again for your reply. It might help someone down the road for sure.

0 Vote Up Vote Down
Steph answered 5 years ago

Hello, Steve,

Don’t worry, the code you posted was clear enough about how you were going to do it. I wasn’t saying you used a delay()! I was reacting to the solution Sara suggested (which was to use a delay()).

Nevertheless, I didn’t really understand the interest of using an LED here if your goal is to detect the signal on an oscilloscope… I thought the goal was to highlight the pulse by flashing an LED… In which case, I think the code I’ve given you is the right way to do it.

Indeed, in the interrupt handler of your initial code, the time between digitalWrite(XMitLED, HIGH) and digitalWrite(XMitLED, LOW) is much too short for you to see anything! Probably only a few microseconds (or maybe even nanoseconds) elapse between these two moments. That’s why Sara suggested you to put a delay(), so that you have time to see the LED light up… but the use of delay() is very often to be avoided, because it blocks the execution of the code. And inside an interrupt handler, its effect can be worse.

0 Vote Up Vote Down
Sara Santos Staff answered 5 years ago

Hi Stéphane.
Thanks for answering. I’ve suggested a little delay() precisely because of that (even though it might not be a good solution).
Anyway, I’m glad Steve’s project is working now.
Thank you all for sharing your thoughts.
Regards,
Sara 

0 Vote Up Vote Down
Steph answered 5 years ago

Hello Sara,

Yes, I had understood that you had proposed it to allow Steve to have time to see the LED flash! But as you didn’t talk about the consequences of the delay(), I preferred to specify it because they can be harmful… and especially in the context of an interrupt handler!

I hope you don’t blame me for insisting on this point.

Friendly,
Steph

0 Vote Up Vote Down
Steve Angell answered 5 years ago

HI Guys,
I just reread what Sara posted. Now I see why you said a delay is bad. I also see why Sara suggested it. This is the unfortunate part of typing and not talking. I just used an output that was defined to control an LED as a short paulse generator. It was only for debugging and not intended to be seen by human eyes. I do this lots when debugging where I just use a defined LED pin for generating a scope signal I can measure. 
So now to learn about ESP-NOW. That is where all this is heading.
Thank you both for helping me out.
Regards,
Steve

0 Vote Up Vote Down
Sara Santos Staff answered 5 years ago

Hi Stéphane and Steve.
Don’t worry about it. What matters is that everything is working now and that we can exchange knowledge and ideas with each other.
It seems that this interrupt issue is solved now. So, I’ll mark this question as resolved.
If you guys need further help or want to discuss a new subject, just create a new question.
Thank you for supporting our work.
Regards,
Sara

Primary Sidebar

Login to Ask or Answer Questions

This Forum is private and it’s only available for members enrolled in our Courses.

Login »

Latest Course Updates

  • [New Edition] Build ESP32-CAM Projects eBook – 2nd Edition April 16, 2025
  • [eBook Updated] Learn ESP32 with Arduino IDE eBook – Version 3.2 April 16, 2025

You must be logged in to view this content.

Contact Support - Refunds - Privacy - Terms - MakerAdvisor.com - Member Login

Copyright © 2013-2025 · RandomNerdTutorials.com · All Rights Reserved

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.