The simplest Arduino program looks like this:
This does nothing beyond build and run.
setup() function is used for one time, well, setup. This is where you initialize a sensor or connect to Wifi or set the speed of your serial port.
loop() function is where you do the work. This is intended for repetitive tasks, like reading from a sensor or uploading some information or blinking lights.
The Arduino SDK (including when it’s used on a non-Arduino chips like the ESP8266 and ESP32) is designed expecting
loop() to do a little work and then return. The
loop() function itself is called from an infinite loop.
Sometimes Arduino coders write things like:
This will completely fail on some processors. Notably the ESP8266 and the ESP32 both have “watchdog timers” which are used to help with stability. Watchdog timers are intended to catch when the software has gone into an infinite loop or otherwise failed. If they’re not reset periodically, they’ll restart the processor and your program will run over again from the beginning.
The watchdog timer is automatically reset when
loop() returns. When
loop() returns the underlying software also gets to perform certain housekeeping tasks, like handle serial I/O, perform any interrupt service it couldn’t do in the interrupt handler, and handle network protocol interactions if it has a networking stack and interface. You can also give up control from inside
loop() temporarily by calling
delay(), and some other calls may also give the underlying software a chance to run.
So it’s vital that you don’t loop indefinitely inside
loop(). Instead, structure your code to be aware of the fact that loop will be called over and over again for you.
So instead of:
People also often write:
This is fine as long as you’re not doing much inside
loop(). If you have a very simple application that only does one thing inside
loop() then calling
delay() this way is harmless.
Let’s suppose we’re doing something more. Imagine that we’re running on a wifi-enabled platform and we have a small web server. We’ll avoid details of how the web server works - there are plenty of tutorials out there and the details would be a distraction.
loop() looks something like this:
So we take a sensor reading, print it to the serial port, check if there’s a web request available and process it if there is, and then delay for ten seconds because we don’t want to output sensor readings too often.
See the problem?
This delays handling web requests for ten seconds as well.
Instead we can write
loop() like this:
Now we’re checking on web requests every run through
loop()but only handling sensor readings every second.
We can generalize this to let us handle several things with different timing needs all in the same loop just by keeping track of the time for each of them separately.
Using this structure instead of calling
loop() will let the handlers inside
loop() remain responsive while still reading the sensor only as often as it’s supposed to be read.