Skip to main content

Microcontrollers

Section 14.1 Datatypes

All variables in C must be declared before usage. This declaration includes the datatype that the variable takes on, which indicates how much memory the microcontroller must use to store the variable and the minimum and maximum values it can take on. The memory usage dictates how much space (defined in bytes) must be used to store that particular value. However, when stored in the actual memory of a microcontroller, the value may need to be stored in multiple addresses if the capacity of the variable is larger than the word size of the memory.
A compiler may opt to store a variable in program memory if that variable is never modified in code. In that case, the variable will be stored in increments of the word size of program memory (which is 16ย bits in the ATmega328P). Otherwise, the compiler will store the variable in data memory. In that case, the variable will be stored in increments of the word size of data memory (which is 8ย bits in the ATmega328P).
Integer datatypes are used to represent whole numbers. Integer datatypes are listed in Tableย 14.1.1. Integer datatypes can either be signed (capable of representing both positive and negative values) or unsigned (capable of representing positive values only). By default, a variable is signed. Using the keyword unsigned will modify the variable to restrict it to unsigned values only.
Table 14.1.1. Integer datatypes in C.
Datatype Memory Range
char 8 bits โˆ’128 to 127
unsigned char 8 bits 0 to 255
int 16 bits โˆ’32,768 to 32,767
unsigned int 16 bits 0 to 65,535
long 32 bits โˆ’2,147,483,648 to 2,147,483,647
unsigned long 32 bits 0 to 4,294,967,295
Floating-point datatypes are capable of representing fractional numbers as well as numbers which are too large or too small to fit into the constraints of the integer datatypes. The two floating-point datatypes defined by the Arduino IDE are float and double which (confusingly) are both single-precision floating-point numbers. These numbers have a single sign bit, 8 exponent bits, and 23 fractional bits. The number they represent is defined by (14.1.1), where \(s\) is the sign bit stored in the variable, \(f\) is the fractional component stored in the variable, and \(e\) is the exponent component stored in the variable.
\begin{equation} (-1^s) \times (1.f) \times 2^{e-127}\tag{14.1.1} \end{equation}
There are downsides to working with floating-point numbers. Floating-point arithmetic is very slow. This is because floating-point math requires custom subroutines to carry out mathematical operations using an instruction set built off of integer-based operations. This can yield strange or unexpected results (for example: 6.0/3.0 may not be exactly equal to 2.0 using a floating-point operation) and limits the amount of useful precision of each floating-point value. In addition to this, each floating-point variable requires 4 bytes of data memory, regardless of the value itโ€™s representing. Floating-point variables and operations will not be utilized in this textbook or the accompanying lab manual [16.24].