Need some help figuring out my code

So we have a fascinating phenomenon here. Three days ago, a new poster joined the Arduino forums with a slightly confused observation about a particular simple module from the typical "beginner" kit.

He(?) has subsequently embarked on a persistent vendetta here as I first noted in #20, nine posts so far, to convince the OP to embark on a totally inappropriate diversion in his project.

Clearly "the blind leading the blind"! :crazy_face:

Advice to OP: Do not even read any such unsafe posts. :sunglasses:

Your assumption of my gender is correct.

What would you suggest I use then?

Kind regards

I think you're confused; you are not the subject of reply #61.

The suggestion is that you poll the switch.

...and stay away from Instructables

I wasn't guessing your gender, but the enthusiastic interjector. :grin:

This whole thread has been severely muddled by the unhelpful suggestions, 63 posts so far is just ridiculous. Let's get back to your OP.

Which is exactly what you have to do. :+1:

There are - as I understand it - three parts to your system. A song which is to be read from a table of notes (array), a LED pattern similarly read from an array, and a button to toggle the whole shebang on and off.

So your program loop needs to be a "state machine" involving three steps. Let's say the first step is to monitor the button. Has it just been pressed (that is, was previously not pressed and now is)? If so, a button timer (millis) is started. If it was started on a previous pass in the loop and is still pressed (otherwise it is cancelled), millis() is checked to see if it has been consistently pressed long enough (about 10 ms) to be a genuine press and if so, the "run/ stop" flag is toggled.

Next step: Check the song table. How long (millis) has the current note been playing? If not long enough, just keep playing it. If ready for the next note, OK, go to the next note.

Third step: Check the LED pattern table. How long (millis) has the current pattern been playing? If not long enough, just keep playing it. If ready for the next pattern, OK, go to the next pattern.

This loop() containing three steps keeps repeating forever. The second and third steps are of course dependent on the "run/ stop" flag; if it was set to "stop" then any note is switched off as is the LED pattern. You have an option here as to whether the button causes a pause or a re-start of the patterns.

Note that although there are other ways of doing it, the loop() runs extremely fast. It presumes you use the "tone" function to generate the sound independently of the main program and you only change the "tone" when you need to.

Great, thank you. I'm heading of to bed now but will attempt to try this tomorrow.

Kind regards

Nooobody expects the Spanish Inquisition...

Understood ... However in some of my ESP32 projects routines that e.g. transmit emails take several seconds (calling the smtp server, authentification, ...) Would be a lot of work to integrate the required polling routines in the smtp libs (unless you have a best practice how to handle that?)... There it is nice that a keypress is registered (and visualized by a LED switched on by ISR to serve human feedback hunger) and taken care of immediately after the time consuming functions have finished ... As I said it depends on the application, every routine that consumes second(s) may loose a short keypress (fair enough; you may probably handle this by clever programming, but that).

I know the downsides of interrupt handling (especially their weaknesses when it comes to EMI where debouncing is much safer), but also those of polling and do not want to argue against both of them ... You should have the ability to choose ... as long as you know what you are doing (not only in software but also on the hardware side which is mostly neglected). If you don't you may make some interesting experiences.... That's just my point.

..and there it is, in a nutshell.

This guy hasn't even figured arrays.

On discworld people are using a wooden postbox with an imp inside who will hoist the "flag" at the box everytime the post(wo)man delivers mail (and - sometimes - even move the mail to the magician's huge office mail storage, thus clearing the small mailbox , and the "flag" again of course) ... If the magician has no time (e.g. due to a fight with a dragon) he can easily work himself through his staple of mail after the quarrel ...

May be astonishing for you, but there are examples even on

planet A (rdunio) : arduino projecthub and best microcontroller-projects (in the later scroll down to " Interrupt switch debouncing" ...

planet E (SP32):

planet P (ic): circuitdigest

and so on. I am not arguing downsides of interrupt handling, but correctly implemented they do have their advantages where polling or using a timer is not feasible. Agree?

That's great, so in future, each time a noob persists with an inappropriate use of interrupts, we can poke your mailbox imp, and get you to come to the rescue, and the rest of us can have the evening off.

The best thing to come out of this discussion has been your link to Jack Ganslle's classic article

In that case why argue about interrupts? With your wording: Even a monkey could do it. Enable an interrupt to register a RISING/FALLING edge. Disable the interrupt when an edge was detected and set a flag. Re-enable the interrupt again after the deboucing period has elapsed ...

Will monkeys be a threat for software development by AI? I guess not, because the use of AI instead of monkeys reduces the danger of slipping on banana skins/peels ...

Okay, I was a little flip with the monkey reference. But implementing an interrupt properly requires a lot more than having opposible thumbs. It's extremely common to see people post botched interrupt code here.

Your description sounds a little like you haven't actually done this. Perhaps you should post your code. But please, a real world ISR not one that just toggles an LED. That's not a fair example because it can be done quickly, and with interrupts disabled - two of the major reasons why an interrupt event will eventually need to be polled, as if it were a switch event, in the first place.

Please feel free to have a look at #54 in this thread. I would consider it an example that works under real world conditions (although here without the feedback LED which is realy easy going). (Forgot to add that I tested that on my desk with an UNO and a cheap button, connected to my digital scope running in single trigger mode, directly connected to the button pins, sometimes "brilliant edges" but sometimes nice bouncing).

ISR just waiting for a falling edge (where I think with 20/50 kOhm internal pullup spikes by EMI should be a rare case, would not do that with high impedance inputs ...), the ISR disables itself and will/shall be enabled after a certain time. This can also be quite late when a "start button" is of use again. Of course you could also toggle the button's task from start to stop and so on.

I fully agree with you that polling is much easier to understand for beginners. It is just that I also like the advantages of interrupt (event/timer) driven actions ...

And of course beginners have to learn in addition how to design non blocking functions in the loop :wink:

I would not consider #54 to be an example that works under real world conditions. First, any time a keypress is detected, you force a 200ms delay. That will break a lot of non-blocking code. Second, it will itself break if any blocking code is in the loop, since the polling will be delayed. If you depend on non-blocking code in loop(), it defeats the common purpose of using an interrupt - to circumvent blocking code. So it does not offer beginners any "get out of jail free card" to fix blocking code. When a non-blocking condition is already expected of code in loop(), an opportunity to implement a non-blocking keypress detection is an obvious choice, since anything more is not necessary and merely serves to multiply the complexity for no good reason.

Although you refer to "advantages" I submit that you really haven't identified or defended them. Really, all you are saying is that it works, and you like it. Well, it's fine to have your pet peccadillo, but practical and realistic people would want to see some use cases in which it can be adequately demonstrated that there is some real performance or coding advantage.

You spoke of blocking routines in some ESP code but there are at least two ways to fix that, one is to make them non-blocking using round robin multitasking, the other is to use an RTOS which I'm pretty sure is available for that chip.


Read the OP's original question. The first thing you tell them in #4 is wildly inappropriate even without noting that it comes in the form of an Instructable.

To lead the OP into messing with timer peripherals and interrupts is a serious disservice.


1 Like

My but is he ever persistent! :astonished:

1 Like

While I have given information to verify my point of view, I am still waiting for technical rationales regarding counter-arguments ... Rationales are the proper way to discuss technical issues, not assertions or degradation (even - and especially - when a lack of understanding is assumed).

The use of timers (periodic timers for periodic activities and interrupts for events like switches have been stated to be inappropriate while Professor Dr. Valvano at the University of Texas at Austin (lecturer, author of books like "Embedded Systems: Introduction to ARM CORTEX-M Microcontrollers") seems rather to share my point of view:

Click the Link and scroll down to fig 12.10 and program 12.7

Is there anything that Prof. Dr. Valvano has overlooked?

I think not. Here is an excerpt from the document you linked:

"Many factors should be considered when deciding the most appropriate mechanism to synchronize hardware and software. One should not always use busy wait because one is too lazy to implement the complexities of interrupts. On the other hand, one should not always use interrupts because they are fun and exciting. Busy-wait synchronization is appropriate when the I/O timing is predictable and when the I/O structure is simple and fixed. Busy wait should be used for dedicated single thread systems where there is nothing else to do while the I/O is busy. Interrupt synchronization is appropriate when the I/O timing is variable, and when the I/O structure is complex".

(busy wait is just another name for polling)

1 Like

I think the good doctor has done a very thorough job . . . debouncing?

It's a pity he didn't have access to the Arduino framework for the ARM Cortex, to hide all that nasty bit-shuffling.

And further quotes:
"Interrupts allow for quick response times to important events."

The "newbie" misunderstanding is that a button press is an "important event" in this context. Of course you obviously want your code to respond to the button, but a "quick response" is not required in the context of microprocessor time.

"The challenge is under most situations the software executes much faster than the hardware. ... During this time, the software could execute tens of thousands of instructions. "

And this is true in the case in point. A button press is an extremely slow event. The (properly written) code will spend almost all of its time "busy waiting" for the time to pass as millis() - which is already based on a "SysTick" interrupt in the parlance of that article - is polled.

But "busy waiting" is easily misinterpreted - or mis-coded. If the only thing that the code is polling is a particular event, then clearly nothing else can happen, but you simply do not write such code if you need to do more than one thing. The description I gave in #64 of "state machine" coding represents genuine "busy waiting" where the code is actually very busy waiting for any one of many events, and doing so with admirable efficiency and promptness.