For information about the “core and mechanics of microcontrollers with Arduino”, there are numerous articles with lots of details on the arduino.cc forum. However, most of the code posted there sucks, as does most of the code posted here on Arduino Stackexchange. That's a natural consequence of people posting code that doesn't work and they wonder why.
For a reasonably organized and accurate body of information about Arduino hardware and software, see Nick Gammon's Arduino pages. Also see arduino.land pages. For better understanding of Arduino software internals, see garretlab's “Internal Structure of Arduino Software” pages, which are well organized and quite informative about the subjects they cover.
Regarding the specific delay()
code shown in the question, first consider this slightly simpler version, from Arduino 1.6.3:
void delay(unsigned long ms) {
uint16_t start = (uint16_t)micros();
while (ms > 0) {
if (((uint16_t)micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
Ignoring data type constraints, it's evident that the while
loop counts down ms
from its original value to zero. The burden of the if
executes about once per millisecond, because start
advances 1000 microseconds each time within the if
.
The casts of micros()
– ie, where uint16_t
appears in parentheses before micros()
– tell the compiler to throw away the upper two bytes of micros()
[which is actually an unsigned long, or uint32_t
] and treat it as an unsigned 16-bit integer. The low two bytes of micros()
overflow every 65536 microseconds, on which occasions within a millisecond it will come to pass that although (uint16_t)micros()
is less than start
, due to use of unsigned arithmetic ((uint16_t)micros() - start) >= 1000
.
The code you included has one more statement in the while
loop:
yield();
For most models of Arduino, yield()
is an empty function, a do-nothing if compiled at all. On the Due, with Scheduler.h
in use to support cooperative (non-preemptive) multitasking using multiple stacks, yield()
gives the scheduler an opportunity to schedule another task, if one is ready to run. Note that if a “cooperative” but malignant task always takes just under 65536 microseconds to do its work, it can happen that delay()
as shown never returns.