The fundamental difference between polling (digitalRead()
) and interrupts is that of time. Yes, I know we discussed time and interrupts at length in another of your questions, but I'm not talking about recording time here.
With an interrupt you know (pretty much) when an input changed. With polling you can only know that it changed sometime in the past. An interrupt occurs at the moment an input changes state (what that change is depends on the type of interrupt). That makes it possible for your program to remember that time (by querying millis()
for example).
With digitalRead()
the only way you can know if an input has changed state is if you manually remember what the old state was and compare it, so all you can know is that it's changed since last time you examined the input, and if those times are far apart all you can say is "sometime in the past X milliseconds it changed state".
If your input changes faster than that polling time you won't know about it. For instance, if you end up polling every 10 milliseconds, and you have a pulse on your input pin that lasts 4 milliseconds (that's an eternity in microcontroller time) but occurs part way between two polls (say from 3ms to 7ms) you'll never see it.
To put it more formally, to detect a signal of frequency f Hz you have to sample the input at minimum 2f Hz (or a period of 1/(2f) seconds. This is known as the Nyquist-Shannon theorem and applies equally to both digital and analog sampling (digital sampling is merely 1-bit analog sampling).
With interrupts, since you're not sampling based on periodic checks, but instead using a hardware trigger to detect an edge (rising, falling, or changing), and assuming you have interrupts enabled at the time an edge arrives on the pin (some code disables interrupts, and interrupts can't trigger while another interrupt routine is running), you instantly know about it regardless of whatever else you are doing.
Interrupts are said to be asynchronous, whilst polling is known as synchronous.
Which method you should choose depends on many factors: the speed of your signals (pulses from sensors, buttons pressed by humans, etc), what else your program is doing, how critical it is that you detect an input state change, etc. For slow signals, like a button, polling is perfectly fine. For high speed signals, like a hall-effect sensor or a reed switch triggered by a bicycle wheel mounted magnet, interrupts are more suitable.
For some signals (especially things like revolution counters, frequency counters, etc) where you have a large number of brief pulses coming in over a period of time where all you want to do is count them, there are even better options than interrupts.
The internal timer peripherals of the chip can run in a number of modes that are designed just for this scenario. You can run a timer with the clock source as an IO pin. That means that on each incoming pulse to that IO pin the timer counts up by one. That happens completely independently of your program. You just read the current count from the timer and reset it to 0 to start counting again at a period to suit you.
Another mode is Input Compare mode. This combines normal interrupts with a timer. The timer runs in the background at a pre-defined rate, and as soon as a specific input changes state (each timer has specific inputs for this) the timer is frozen an interrupt is triggered. This gives highly accurate time measurement of incoming signals since it's not subject to the time taken to service the interrupt. The timer is frozen immediately and you can query that time when the system is able to service the interrupt.
There is no native support in Arduino for either of those timer modes, though, so you would have to either find an advanced library that configures the timers in that way for you, or read and understand the datasheet and manually configure the timers in the right way.