Whether you're just starting out or have some experience with microcontrollers, understanding Arduino variable types is essential for effectively programming your Arduino projects.
Data types define how information is stored in variables
and manipulated in memory. This tutorial will provide an overview of the
main Arduino data types and demonstrate how you can declare them with
simple code snippets.
You can use Arduino Data types to define the type of data
that a variable can hold. Processors work on defined boundaries and for
the 8-bit Arduino Uno this is a byte boundary. it is an 8-bit processor.
The processor has to know how many bytes that each type of information
is using.
If types did not exist then you would be limited to using 8
bits and only able to store values from -128 to 127 ! By using the
integer type you can use and manipulate values from -32,768 to 32,767.
(the type 'long', allows even larger whole numbers).
Even though the processor is only capable of working with 8
bit entities, it uses a carry flag to allow information to be "carried
over" to the next byte for calculation. It means you can have arithmetic
operations on large numbers that occupy more than a single byte of
memory.
As a programmer you need to be aware of the "type" of a variable so that is capable of holding the values you expect to use.
Types allow the compiler to allocate the right amount of
memory for the variable and to perform the correct arithmetic operations
on it.
As well as whole number arithmetic, another type is 'float', that while still operating using 8bits, treats those bits in an entirely different way allowing floating-point-number calculation. In addition you can use character types (type 'char') that code the 8 bit data into numbers that represent characters.
In the Arduino programming environment, variables allow you
to store and work with different pieces of data within your sketches.
Before declaring a variable, you need to specify its data
type which tells the microcontroller how much memory space to allocate
and what type of data can be stored there.
Common Arduino variable types are:
int:
Stores integer (whole number) values. Uses 2 bytes of memory.
Example declaration: int sensorReading;
float:
Stores floating point numbers, useful for measurements with
decimals. Uses 4 bytes of memory.
Example declaration: float temperature;
boolean:
Can only hold true or false values. Uses 1 byte of memory. Common
for digital outputs.
Example declaration: boolean buttonPressed;
char:
Stores a single character such as letters, numbers, or symbols. Uses
1 byte of memory.
Example declaration: char initial;
String:
Special class used to store and manipulate strings (sequences of
characters). Takes up dynamic memory as needed.
[ Warning - there can be problems using dynamic strings.]
[ An alternative is to use vanilla C strings. ]
[ Find out the issues in this link "Arduino String". ]
Example declaration: String
message = "Hello";
byte:
Alias for unsigned 8-bit integer, same as int but uses less memory.
Example declaration: byte ledPin = 13;
long:
Alias for unsigned 32-bit integer. Uses 4 bytes.
Example declaration: long bigInteger;
The basic unit of memory in any processor is a byte but in fact in C/C++ programming the byte type is not usually defined.
The 'char' type is the usual way of writing (In non-Arduino code) that you want to use a single byte of data for your variable:
char myByte;
In Arduino code you can write:
byte myByte;
Note: if you want to use the word byte in code other than Arduino, you can define your own type as follows:
typedef char byte;
Now you can write (in any C/C++ programming environment):
byte myByte;
There are three fundamental whole number (or integer types):
In the Arduino Environment these are of length:
Now the next thing to know about them is that they all come in two flavours!
Using a method called two's complement
you can easily do addition and subtraction (by only adding!). [the
method is to invert all the bits in the bytes and then add 1 - this will
make the number negative. Try it and see i.e. choose a number say
11 then perform 2's complement on another number (3 say). Add them
together and you will get a result of 8].
Now, the only reason for saying the above is that it is quite easy to allow integer types to hold negative or positive numbers (the left most bit - if set - indicates a negative number). Here are the range of values for the three integer types:
char: -128 to 127
int -32,768 to 32,767
long: -2,147,483,648 to 2,147,483,647
int 0 to 65,535
long: 0 to 4,294,967,295
So, you can choose to tell the compiler that you only want positive numbers...
unsigned char myUnsignedByte;
unsigned int myUnsignedInt;
unsigned long myUnsignedLong;
...or both negative and positive numbers (the default where you don't need to write the word signed - it is implied):
signed char myUnsignedByte;
signed int myUnsignedInt;
signed long myUnsignedLong;
It all depends on your application.
For instance if you needed to process numbers above 32768 but below 65535 you would use an unsigned int.
You could ask the question why not use a 'long' type variable?
The answer is you could but it would be less efficient (slower and would use more memory).
Oddly enough the C/C++ language does not specify how many
bits are to be used in an integer type. This makes the language more
flexible because it can cope with different processor architectures.
For instance if you use a 32 bit processor, it is more work
to split the 32 bits into blocks of 16 so an integer will probably be
represented by 32 bits; so a bit of memory is wasted but it will be far
faster, and the 32bit microcontroller probably has lots of SRAM memory
anyway.
This sounds fine, but when you come to moving a program from
one processor to a different one, it may or may not work. This sounds
counter intuitive but here's an example.
Lets say you have made a counter using a unsigned int and
you know that the range of values that the counter can adopt are 0 ~
65535. Your program relies on this operation i.e. that increasing the
value when you get to 65535, resets the counter to zero (the 16 bit int
cannot
hold a number bigger than this).
Now, moving to a 32 bit processor may allow the range of
values from 0 ~ 4,294,967,295 i.e. entirely different operation. Note, I
say may because it depends on how the compiler implements type int.
You have to know about the number ranges represented using
each specific Arduino variable type so that your program will work. For instance
assigning a
number greater than the maximum allowed positive value for a signed int
will result in a
negative number (because of how the number is interpreted).
When moving to different processor architectures, the bit size
of the fundamental types may be different, as the C/C++ standard does not
specify them!
Written by John Main who has a degree in Electronic Engineering.
Note: Parts of this page were written using chatgpt as a research assistant.
Comments
Have your say about what you just read! Leave me a comment in the box below.
Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.