Coming from a C background, I was taught that tight loops that just burn CPU aren't desirable.
Is there any programming style guides on Arduino? Is it common practice to just let loop iterate as a tight loop forever?
Coming from a C background, I was taught that tight loops that just burn CPU aren't desirable.
Is there any programming style guides on Arduino? Is it common practice to just let loop iterate as a tight loop forever?
A microcontroller's execution path is a tight loop whether you like it or not.
If you take a CPU and connect it to empty memory the CPU will execute each empty cell in turn and loop back to the beginning of memory when it reaches the end (assuming empty memory cells equate to NOP and covers the whole memory space).
With no operating system, no scheduler, nothing except your specific code running, the CPU is always executing something.
The only time the CPU stops executing is when you manually send it to sleep to be woken by some external source (such as a timer, or a sensor sending an interrupt signal). You'd only do that, normally, to reduce power consumption.
On Arduino the loop()
function is in fact executed from within a while(1)
loop.
On microcontrollers when main()
exits, or you call exit()
it just disables interrupts and drops out to a while(1)
loop.
On a multiprocess system, like your typical desktop, you usually have way more processes than logical CPUs. When programming such systems you therefore have to avoid burning more CPU cycles than needed. Instead, when your program has nothing to do, it should just sleep, and leave the CPU available for other processes.
On an Arduino, you only have one single program running at a time. It is then not that useful to keep the CPU idle. Also, the power dissipation is so low that you will not notice the microcontroller getting even slightly warm. The extra complexity of getting into and out of sleep mode is therefore not that useful. Only when running on batteries do you care about saving every possible milliamp: then learning about sleep modes starts getting useful.
That is a difference between embedded systems programming and (many but not all) other types of programming. An embedded system is usually a controller of some kind and needs to be responsive to one or more kinds of events. Three typical ways of accomplishing this are
On processors as small as the AVRs, data memory and sometimes instruction memory, are scarce resources and an operating system is usually too expensive (in terms of memory needs) for most of them. On the ATtinys, forget it. On Uno, maybe kinda sorta, but memory will be a pretty severe limitation. On Megas, you might manage it.
ISR programming can be complex to write and is definitely more complex to debug(!). It's not out of the question, and it may be justified in a system that must be highly responsive - think automotive ABS braking, traction control, and fly-by-wire systems. On the other hand, systems like these have to be right.
Polling is the easiest to write and debug. You call each subsystem (code) in a tight loop (and there's your answer: "yes, let it iterate") that gives each one an opportunity to assess whether or not it needs to act and to do so. This is a case where burning cycles is inconsequential, while making a more responsive system.
In my hobbyists' classes, this is what I teach; it's also what use most. I call it "maybe-do" (and wrote about it here in answer to another question). In loop()
I do nothing but call a number of functions in turn, each of which does:
{
if I dont need to act now,
return;
else {
do what needs to be done -- quickly!;
return;
}
}