Skip to main content
Engineering LibreTexts

18.2: Universal Stuff, Common to All Controllers

  • Page ID
  • Let’s start with the biggie: arduino.h. Here are the first few lines (some parts omitted):

    #ifndef Arduino_h
    #define Arduino_h
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <avr/pgmspace.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "binary.h"
    #define HIGH 0x1
    #define LOW   0x0
    #define true  0x1
    #define false 0x0
    #define INPUT        0x0
    #define OUTPUT       0x1
    #define INPUT_PULLUP 0x2
    #define PI          3.1415926535897932384626433832795
    #define HALF_PI     1.5707963267948966192313216916398
    #define TWO_PI      6.283185307179586476925286766559
    #define DEG_TO_RAD  0.017453292519943295769236907684886
    #define RAD_TO_DEG 57.295779513082320876798154814105 

    The first two lines prevent accidental re-entry. That is, if the file has already been included it won’t be included again (if it was, you’d get a whole bunch of redefinition errors). After this we see a selection of other commonly used library header files and then a series of constant definitions. There’s nothing too crazy yet. Following this are a series of what look like functions but which are inline expansions. That is, the preprocessor replaces your “function call” with a different bit of code. This is done because inline expansions do not incur the overhead of function calls and thus run faster and use less memory. Notice how some of these make use of the ternary if/else construct, such as min(), while others make use of recently defined constants (radians()). Some, such as noInterrupts(), perform a substitution which itself will perform a further substitution (in this case, the cli() “function” will turn into a single assembly language instruction that turns off interrupts globally).

    #define min(a,b) ((a)<(b)?(a):(b))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define abs(x) ((x)>0?(x):-(x))
    #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
    #define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
    #define radians(deg) ((deg)*DEG_TO_RAD)
    #define degrees(rad) ((rad)*RAD_TO_DEG)
    #define sq(x)        ((x)*(x))
    #define interrupts()   sei()
    #define noInterrupts() cli()
    #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )

    Further down we find some typedefs, namely uint8_t, which is shorthand for an unsigned 8 bit integer, i.e., an unsigned char. This typedef was written in another header file but notice that we now have new typedefs based on that original typedef in the third and fourth lines! Thus, an unsigned char may now be declared merely as boolean or byte, and finally, an unsigned int may be declared as a word.

    #define lowByte(w)  ((uint8_t) ((w) & 0xff))
    #define highByte(w) ((uint8_t) ((w) >> 8))
    typedef uint8_t boolean;
    typedef uint8_t byte;
    typedef unsigned int word;

    Common procedures in IO programming include checking, setting and clearing specific bits in special registers. Typically this is done through bitwise math operators. For example, if you want to set the 0th bit of a register called DDRB while leaving all other bits intact, you’d bitwise OR it with 0x01 as in:

    DDRB = DDRB | 0x01;

    You could also define specific bit positions like so:

    #define LEDBIT   0
    #define MOTORBIT 1
    #define ALARMBIT 2

    So if you want to set the bit for the motor, you would write:

    DDRB = DDRB | (0x01<<MOTORBIT);

    In other words, left shift a one in the zero bit location one place (resulting in the 1st vs. 0th bit being high) and OR the register contents with it. This is a little cumbersome unless you turn it into a function call:

    bitSet( DDRB, MOTORBIT );

    Now that’s pretty easy and obvious, so check out the lines below:

    #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
    #define bitSet(value, bit) ((value) |= (1UL << (bit)))
    #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
    #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
    #define bit(b) (1UL << (b))

    Further along in the file we come across a bunch of function prototypes for items we will be using:

    void pinMode(uint8_t, uint8_t);
    void digitalWrite(uint8_t, uint8_t);
    int  digitalRead(uint8_t);
    int  analogRead(uint8_t);
    void analogReference(uint8_t mode);
    void analogWrite(uint8_t, int);
    unsigned long millis(void);
    unsigned long micros(void);
    void delay(unsigned long);
    void setup(void);
    void loop(void);

    The last two are particularly important. The Arduino development system has a pre-written main() function. It makes calls to setup() and loop(), so we’ll be writing these as our primary entry points.