Runtime Support: The main() Function
Compilers used with Linux, Windows, and Mac OS X systems provide a platform-specific
library of functions called the runtime library. On a GCC-based system this is typically
called libgcc.a or libgcc_s.so.1, and on Windows the runtime libraries usually go by
the names MSVCRT.DLL for C and MSVCPP.DLL for C++. The AVR version is avr-libc,
which is discussed in Chapter 6. The runtime library will contain commonly used
functions specific to a particular platform. These can be common math operations,
low-level I/O functions, system timers, support for printf()
, and so on.
The Arduino also has its own additional runtime support module, but with a twist. By
itself, a program sketch won’t do much. It has no main()
function to get it started
and no way to continuously execute once it does start. The Arduino runtime support
includes the necessary main()
function, along with other startup configuration
functions. As can be seen from Example 5-4, it’s actually very simple, and
is a typical design for small microcontrollers.
Example 5-4. Arduino main() function
int
main
(
void
)
{
init
();
initVariant
();
#ifdefined(USBCON)
USBDevice
.
attach
();
#endif
setup
();
for
(;;)
{
loop
();
if
(
serialEventRun
)
serialEventRun
();
}
return
0
;
}
The calls to init()
, initVariant()
, and (if applicable) USBDevice.attach()
are determined at compile time based on the type of Arduino target hardware
selected in the IDE. These comprise the primary components of the runtime
support code specific to each type of Arduino board. In a larger realtime
operating system (RTOS) these might be part of the board support package
(BSP) supplied by the RTOS vendor or created by a developer. The functions are described here:
init()
-
Located in Arduino/hardware/arduino/avr/cores/arduino/wiring.c, this function initializes various AVR peripheral components such as timers, timer/counter prescaling, A/D converter prescaling, and PWM output modes according to the AVR part used with a particular Arduino board.
initVariant()
-
This provides a “hook” in the form of a so-called weak function declaration. Typically used to provide additional runtime initialization for hardware not covered by the definitions and code supplied with a standard Arduino development environment.
USBDevice.attach()
-
This refers to the
attach()
method of theUSBDevice
class found in Arduino/hardware/arduino/avr/cores/arduino/USBCore.cpp. This class provides the functionality necessary to communicate with a USB interface.
For many people, what these initialization functions actually do is irrelevant. However, if you want to really understand what the Arduino IDE does and how it does it, then reviewing the source code for these support functions is a worthwhile endeavor. Obtaining the source code is described in “Arduino Source Code”.
As described previously, the setup()
and loop()
functions are provided by
you in the program sketch. The setup()
function is typically used to define
specific I/O ports and starting states, initialize some parts of the AVR
peripheral functions, or perform other one-time operations. It is largely
optional and can even be an empty function, but it must exist in the sketch
or the linker will generate an error message.
The loop()
function is where the main activity occurs in a program sketch. As
can be seen from Arduino main it is called repeatedly until power to the Arduino
board is removed. Interrupts can and do occur while loop()
is executing, and
some applications may incorporate a timer interrupt or a delay to give loop()
some degree of definite periodicity (as opposed to simply free-running).