Interrupts: Polling

Suppose you had a program that changed the color of a circle on the LCD screen by pressing a button. We will need some implementation for capturing the button input (for now, let us disregard debouncing). We have two options: use polling to check if the button is pressed or use interrupts. Polling is described as checking for a specific condition every time the code loops. Polling can be as simple as an if statement placed at the end of a while loop. After the code has done its primary function and is ready to do it again, we can check if our condition has been met, and if so, we can perform the appropriate action (and if not, the code returns to the beginning of the loop).


With how quickly the processor can run, polling is usually a sufficient solution. This method does present some inconsistency, but when the input is being polled so quickly, the inconsistency is practically nonexistent. However, this method depends heavily on the other code within the loop. If some code takes a long time to execute (such as clearing the LCD screen), then the button input will be polled less frequently because each loop will take longer to complete. As a result, the inconsistencies become more noticeable, as the button input may not register properly if you push the button while the processor is busy executing a large piece of code (thus, it never gets to the statement that checks the button input in time).


Using interrupts may seem like the way to go, given that the button input can be registered instantaneously even if the processor is busy with a long section of code. However, using interrupts poses a plethora of other issues. For one, interrupts have to utilize global variables in order to have an effect on the code. Not only are global variables vulnerable to security threats, but they’re also difficult to debug since anything in the code can directly access and modify them.


One of the most common bugs that comes with using interrupts is a race condition. Suppose you had an ISR that modified a global variable. What if this ISR is called just before the main code assigns a value to this same global variable? When the ISR is done, the main code will then execute its next line, which overwrites the value that the ISR gave the variable. Given that the ISR can modify it at any point within the code’s execution, the variable’s behavior becomes unpredictable and difficult to debug.

Another point to consider is execution time. Although we disregarded it initially, having a debounced button input is imperative to ensuring input accuracy. With the debouncing implementation we are familiar with, we have to start a timer and wait to see if the input changes or not. While brief, keep in mind that executing an ISR momentarily stops everything else in the program execution. If there are other time-sensitive components to the code, then lengthy ISRs can mess up their timing.


Both options have their pros and cons, and typically, they each have their own situations in which they are effective. Generally, simpler implementations can afford to get away with polling if there is no urgent need to handle a specific event when it occurs. However, if a piece of code (or several with varying priorities) needs to be executed as soon as possible when a condition is met, then interrupts may serve as the better choice.