Code Along - Chapter 2

Variables & Types

Store values in well-named variables, calculate with them, choose the right Uno type, and see what happens when a number no longer fits.

Estimated time 75-100 minExercises passed 0 / 9

What you will practise

A variable is a named box for a value. Every variable has a type (what kind of value), a name and a value. On the Uno the type also decides how big the box is - and a value that does not fit wraps around to a strange number.

In this chapter you print values to the Serial Monitor, calculate with whole numbers and decimals, and hunt down two classic type bugs. The tests run your sketch on a simulated Arduino Uno, so int really is 16-bit, exactly like the real board.

Worked example

Declaring and printing variables

Each variable is declared above setup() with a type, a name and a starting value. Serial.print shows a value and stays on the same line; Serial.println ends the line. Press Run and watch the Serial Monitor.

int ledPin = 13;
float voltage = 4.75;
bool ready = true;
char grade = 'A';

void setup() {
  Serial.begin(9600);
  Serial.print("ledPin = ");
  Serial.println(ledPin);
  Serial.print("voltage = ");
  Serial.println(voltage);
  Serial.print("ready = ");
  Serial.println(ready);
  Serial.print("grade = ");
  Serial.println(grade);
}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Expected output
ledPin = 13
voltage = 4.75
ready = 1
grade = A
  • A bool prints as 1 (true) or 0 (false).
  • A char prints as the character itself, not a number.
  • A float prints with two decimal places unless you ask for more: Serial.println(voltage, 3);
Exercise 2.1

One variable, one label

Not started

Declare an int called ledPin holding 13, then print it after the label LED pin: .

Use Serial.print for the label and Serial.println for the value.

Sample output
LED pin: 13
// Declare ledPin here


void setup() {
  Serial.begin(9600);
  // Print: LED pin: 13

}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 2.2

Board passport

Not started

Now four variables. Declare them above setup():

  • boardName, a String holding "Uno"
  • pinCount, an int holding 20
  • clockMHz, a byte holding 16
  • supplyVoltage, a float holding 5.0

Then print them so the Serial Monitor shows exactly the sample output.

Sample output
Board: Uno
Pins: 20
Clock MHz: 16
Voltage: 5.00
// 1. Declare the four variables here


void setup() {
  Serial.begin(9600);
  // 2. Print the four lines here

}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Choosing a type on the Uno

The Uno's ATmega328P is an 8-bit chip, so its types are smaller than on a PC. Pick the smallest type that always fits the value:

TypeSizeRangeTypical use
byte1 byte0 to 255pin numbers, small counts
int2 bytes-32768 to 32767everyday whole numbers
unsigned int2 bytes0 to 65535counts that are never negative
long4 bytesabout -2.1 to 2.1 billionbig whole numbers
unsigned long4 bytes0 to 4294967295millis() times, long counters
float4 bytesabout 7 significant digitsvolts, temperatures, averages
bool1 bytetrue / falseflags such as ledOn
char1 byteone characterletters, 'A'
Cards for byte int unsigned long float bool and char with typical uses
Match the type to the range. millis timestamps belong in unsigned long.
Worked example

Counting with the right type

This is the Lesson 04 sketch. flashCount is an unsigned long because it keeps growing for as long as the board runs. Run it and watch the virtual LED and the count together.

const byte ledPin = LED_BUILTIN;  // onboard LED pin
unsigned long flashCount = 0;     // grows each toggle - needs a wide type
bool ledOn = false;               // remembers current LED state

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  ledOn = !ledOn;                 // flip true/false
  digitalWrite(ledPin, ledOn);
  flashCount++;
  Serial.print("flashCount = ");
  Serial.println(flashCount);
  delay(500);
}

Turn on JavaScript to edit, run and test this code in the browser.

Expected output
flashCount = 1
flashCount = 2
flashCount = 3
Exercise 2.3

Calculate with variables

Not started

red and blue hold two counts of parts. Print their total, their difference (red minus blue) and their product, each after its label.

Calculate with the variables - the tests try other numbers.

Sample output
Total: 17
Difference: 7
Product: 60
int red = 12;
int blue = 5;

void setup() {
  Serial.begin(9600);
  // Print the three lines here

}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Whole numbers and decimals

When both sides of / are whole numbers, C++ does integer division: the answer is a whole number and the remainder is thrown away. 7 / 2 is 3, not 3.5.

If either side is a decimal, the calculation is done with decimals: 7 / 2.0 is 3.5. Storing the result in a float afterwards is too late - the decimals were already lost.

Worked example

Integer division in action

Run this and compare each line with the code that printed it.

void setup() {
  Serial.begin(9600);
  Serial.println(7 / 2);        // both whole numbers
  Serial.println(7 / 2.0);      // one decimal
  Serial.println(7 % 2);        // remainder
  int celsius = 21;
  Serial.println(celsius * 9 / 5 + 32);    // whole-number maths
  Serial.println(celsius * 9.0 / 5 + 32);  // decimal maths
}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Expected output
3
3.50
1
69
69.80
Exercise 2.4

Celsius to Fahrenheit

Not started

celsius holds a temperature. Declare a float called fahrenheit, calculate it with F = C × 9 / 5 + 32, and print one line like the sample. The tests try other temperatures, including negative ones.

Sample output
21.50 C = 70.70 F
float celsius = 21.5;

void setup() {
  Serial.begin(9600);
  // Declare fahrenheit and calculate it here


  // Print: 21.50 C = 70.70 F
}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 2.5

Fix the average

Not started

This sketch should print the average of a, b and c with two decimals, but it prints Average: 7.00 instead of Average: 7.67. Find out why and fix it. Keep the three variables.

Sample output
Average: 7.67
int a = 7;
int b = 8;
int c = 8;

void setup() {
  Serial.begin(9600);
  int total = a + b + c;
  float average = total / 3;
  Serial.print("Average: ");
  Serial.println(average);
}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Dividing with a remainder

Two operators work together on whole numbers:

  • / says how many whole times one number fits into another: 17 / 5 is 3.
  • % says what is left over: 17 % 5 is 2.

Together they split a number into parts - 17 sweets shared between 5 children is 3 each with 2 left over. The same pair turns seconds into minutes, or milliseconds into seconds.

Exercise 2.6

Share out the sweets

Not started

sweets are shared equally between children. Print how many each child gets, and how many are left over.

Sample output
Each gets: 3
Left over: 2
int sweets = 17;
int children = 5;

void setup() {
  Serial.begin(9600);
  // Print: Each gets: 3   and   Left over: 2

}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 2.7

Seconds to hours, minutes and seconds

Not started

totalSeconds holds a time. Work out the whole hours, minutes and seconds, and print one line like the sample.

There are 3600 seconds in an hour and 60 in a minute. Use / and % as in the last exercise.

Sample output
3725 s = 1 h 2 min 5 s
unsigned long totalSeconds = 3725;

void setup() {
  Serial.begin(9600);
  // Work out hours, minutes and seconds here


  // Print: 3725 s = 1 h 2 min 5 s
}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Deeper When a number no longer fits

An int on the Uno has 16 bits, so its largest value is 32767. Add 1 and it wraps around to -32768, like a car odometer rolling over. Unsigned types wrap the other way: a byte at 0 minus 1 becomes 255.

The compiler does the same with numbers you type: 60 * 1000 is calculated as an int (both numbers are ints) and overflows before it is stored - even if you store it in an unsigned long. Adding L or UL to a number makes it a 32-bit long or unsigned long.

Worked example

Watching an int overflow

Run this and look at what happens after 32767.

int counter = 32765;

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println(counter);
  counter++;
  delay(300);
}

Turn on JavaScript to edit, run and test this code in the browser.

Expected output
32765
32766
32767
-32768
-32767
Exercise 2.8

The 60 * 1000 bug

DeeperNot started

This sketch should say that one minute is 60000 ms and one hour is 3600000 ms, but the numbers are wildly wrong. Fix the two calculations so they are done in a 32-bit type. Keep them as calculations - do not type 60000 or 3600000.

Sample output
One minute is 60000 ms
One hour is 3600000 ms
unsigned long oneMinute = 60 * 1000;
unsigned long oneHour = 60 * 60 * 1000;

void setup() {
  Serial.begin(9600);
  Serial.print("One minute is ");
  Serial.print(oneMinute);
  Serial.println(" ms");
  Serial.print("One hour is ");
  Serial.print(oneHour);
  Serial.println(" ms");
}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 2.9

From analogRead to volts

DeeperNot started

reading holds what analogRead() gives on an Uno: a whole number from 0 to 1023, where 1023 means 5 V. Declare a float called volts, work out the voltage, and print the line in the sample with three decimals.

Two of the obvious ways give 0.000. The hints explain why.

Sample output
Reading 512 = 2.502 V
int reading = 512;   // what analogRead() would give

void setup() {
  Serial.begin(9600);
  // Work out volts and print: Reading 512 = 2.502 V

}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Try it on a real Uno

Download your solution to Seconds to hours, minutes and seconds with the Download .ino button, open it in the Arduino IDE and upload it. Set the Serial Monitor to 9600 baud: the output should match the simulator exactly.

Then change totalSeconds to 100000 and predict the output before you upload.