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("."); }
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
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. 🙂
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
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.
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.
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.
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Â
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
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
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