05. Operators & Decisions
Calculate, compare and branch: arithmetic, = vs ==, Boolean logic, if/else chains and switch.
Learning outcomes
- Use +, -, *, / and % and explain integer division
- Distinguish assignment (=) from equality (==) and other comparisons
- Combine conditions with &&, || and !
- Write an if / else if / else chain that selects one action
- Use switch to choose between fixed values of one variable
- Read INPUT_PULLUP buttons as pressed-when-LOW
Parts and preparation
Arduino Uno, two push buttons, jumper wires. Onboard LED is the output - no extra LED required.
Before power: inspect wiring, confirm supply voltage and ensure all connected circuits share GND.
Decide from inputs
Sketches spend most of their life reading the world, then choosing what to do. Operators calculate and compare. if / else if / else picks a branch.
This lesson drives the onboard LED from two buttons: both pressed = steady on, exactly one = flash, neither = off.
Arithmetic operators
Use + - * / and % to calculate. % (modulo) is the remainder after division - handy for wrapping and for simple blink patterns.
Integer trap: when both operands are integers, / discards the fraction. 5 / 2 is 2. Write 5.0 / 2 (or cast) when you need 2.5.
| Operator | Meaning | Example |
|---|---|---|
| + | Add | 3 + 2 -> 5 |
| - | Subtract | 3 - 2 -> 1 |
| * | Multiply | 3 * 2 -> 6 |
| / | Divide | 5 / 2 -> 2 (ints) |
| % | Remainder | 5 % 2 -> 1 |
Assignment vs comparison
= stores a value into a variable. == asks whether two values are equal and produces true or false.
Writing if (x = 1) by mistake assigns 1 to x and often looks always true - a classic bug. In comparisons you also use !=, <, <=, > and >=.
bool aPressed = digitalRead(buttonA) == LOW; // compare
ledOn = true; // assignBoolean operators
&& (AND) is true only when both sides are true. || (OR) is true when either side is true (or both). ! (NOT) flips true to false and false to true.
Parentheses keep complex tests readable: if ((a && b) || alarm).
Truth table for two buttons
Name the pressed flags clearly: aPressed and bPressed are true when that button is down. Then the logic matches everyday English: both, either, neither.
if / else if / else
An if chain tests conditions in order. Only the first true branch runs; the rest are skipped. else covers whatever is left when no earlier test matched.
Separate if statements are different: each is tested on its own, so more than one body can run. Use a chain when the outcomes should be mutually exclusive (steady vs flash vs off).
if (aPressed && bPressed) {
// steady
} else if (aPressed || bPressed) {
// flash
} else {
// off
}switch: one variable, several fixed values
When one variable selects between several fixed values - a mode number, a menu choice, a character typed in Serial - a switch reads more clearly than a long if chain.
switch compares the variable with each case label. Execution starts at the matching case and runs until break. Forget the break and the next case runs too (fall-through). default runs when no case matches, like a final else.
switch only works with whole-number types (byte, int, char) and constant case labels. Use if for ranges and combined conditions, such as temperature > 30 && fanAllowed.
| Use | When |
|---|---|
| if / else if / else | Ranges, && / || combinations, float comparisons |
| switch | One whole-number variable compared with fixed values (modes, menu keys) |
switch (mode) {
case 0:
digitalWrite(ledPin, LOW); // off
break;
case 1:
digitalWrite(ledPin, HIGH); // steady
break;
case 2:
digitalWrite(ledPin, millis() / 250 % 2); // flash
break;
default:
Serial.println("Unknown mode");
break;
}INPUT_PULLUP: pressed is LOW
Course buttons wire from the pin to GND with pinMode(..., INPUT_PULLUP). INPUT_PULLUP switches on a resistor inside the chip that pulls the pin up to 5 V, so an open button reads HIGH. Pressing the button connects the pin straight to GND, so it reads LOW.
Wiring the 4-leg button: push it into the breadboard so it straddles the centre gap. Connect one leg to the Uno pin (D2 for button A, D3 for button B) and the diagonally opposite leg to GND. Diagonal legs are always on opposite sides of the switch, so this works whichever way round the button sits.
That is why the sketch uses digitalRead(pin) == LOW for pressed - not == HIGH. If your LED behaviour feels inverted, check this first.
What the worked sketch practises
Two buttons on D2 and D3. Both pressed: LED steady HIGH. Exactly one pressed: LED flashes using millis() / 250 % 2 so loop stays responsive (no delay). Neither: LED LOW.
Order in the chain is important: the both test must come before the either test, or both-pressed would be treated as a single-button flash.
Wiring and safe build sequence
- Place each 4-leg button straddling the breadboard's centre gap
- Button A: one leg to D2, the diagonally opposite leg to GND
- Button B: one leg to D3, the diagonally opposite leg to GND
- pinMode INPUT_PULLUP for both (no external resistor required)
- Output: onboard LED (LED_BUILTIN)
Worked sketch
Download .inoconst byte buttonA = 2;
const byte buttonB = 3;
const byte ledPin = LED_BUILTIN;
void setup() {
pinMode(buttonA, INPUT_PULLUP);
pinMode(buttonB, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop() {
// INPUT_PULLUP: pressed connects pin to GND -> reads LOW
bool aPressed = digitalRead(buttonA) == LOW;
bool bPressed = digitalRead(buttonB) == LOW;
if (aPressed && bPressed) {
digitalWrite(ledPin, HIGH); // both: steady on
} else if (aPressed || bPressed) {
digitalWrite(ledPin, millis() / 250 % 2); // one: flash
} else {
digitalWrite(ledPin, LOW); // none: off
}
}How the code works
- Pressed is LOW because INPUT_PULLUP holds an open input HIGH.
- Test both (&&) before either (||) so two presses are not treated as one.
- millis() / 250 % 2 flips 0/1 about four times per second without delay(): millis() counts milliseconds since reset, / 250 turns that into quarter-seconds, and % 2 keeps only 0 or 1 - off, on, off, on. You meet millis() properly in Lesson 11.
- = would be wrong inside the if tests - those need == for comparison.
Test and record evidence
Practical evidence checklist
Common faults and checks
- If behaviour feels inverted, remember pressed reads LOW with INPUT_PULLUP.
- Check && versus || and == versus =.
- Button always looks pressed (or never): use diagonally opposite legs, or rotate the button 90 degrees across the centre gap.
- If both buttons flash instead of going steady, your both-branch may be missing or ordered after either.
- Floating feel with no pull-up: confirm INPUT_PULLUP, not plain INPUT.
Check your understanding
Q1. What happens in a switch if a case has no break?
Show answer
Execution falls through and runs the next case as well.
Q2. What is the difference between = and ==?
Show answer
= assigns a value; == compares for equality.
Q3. When does A || B evaluate true?
Show answer
When A is true, B is true, or both are true.
Q4. What is 5 / 2 as integers on Arduino?
Show answer
2 - integer division discards the remainder.
Q5. Why compare digitalRead to LOW for a course button?
Show answer
INPUT_PULLUP wiring is active-low: pressed connects the pin to GND.
Q6. Why put the both-pressed test before the either-pressed test?
Show answer
Otherwise both pressed would match the either branch and flash instead of staying steady.
Practise in your browser
Write and test this lesson's code on a virtual Uno. Work through the 7 exercises in order. Press Test and each one checks itself.
Comparing values
A comparison is either true or false. C++ has six comparison operators: == (equal), != (not equal), <, <=, > and >=.
An if statement runs its block only when the condition is true. else gives the other path. For more than two paths, add else if in between: if (t > 30) { ... } else if (t > 25) { ... } else { ... } - the tests are checked in order and only the first true one runs. Watch out: a single = stores a value, a double == compares two values.
Deciding with if and else
Change temperature to 20 and press Run again to see the other branch.
Fan ON
Above the threshold?
reading is a value from analogRead(), between 0 and 1023. The start of the line is printed for you. Add an if / else that finishes it with : HIGH if the reading is 512 or more, and : LOW if it is below 512 - exactly as in the sample.
Reading 700: HIGH
Fix the = bug
This sketch always reports five presses - and it even changes the count! Find the bug and fix it. Read the compiler warning: it points straight at the problem.
The real Arduino IDE hides warnings by default. Turn them on in File > Preferences > Compiler warnings.
Not five presses buttonPresses = 3
Even or odd pulse count
A counter has recorded pulses pulses. Print whether that count is even or odd, as in the sample. A number is even when dividing by 2 leaves no remainder - use %.
7 pulses: odd
Battery level bands
Turn a battery voltage into a status word:
- 4.00 V or more:
Full - 3.60 to 3.99 V:
Good - 3.30 to 3.59 V:
Low - below 3.30 V:
Critical
Print it like the sample, using an if / else if / else chain.
3.70 V: Good
Combining conditions
&&(AND) is true only when both sides are true.||(OR) is true when at least one side is true.!(NOT) flips true and false.
Brackets make mixed conditions clear: (a && b) || c.
AND, OR and NOT
Predict the output before you press Run. Then change alarmArmed to true.
Check the room Alarm is not armed
Pump interlock
A pump may only run when its switch is on and the tank is not yet full. Print Pump running when both are true, and Pump stopped otherwise.
Pump running
Thermostat with a dead band
A heater should not click on and off every time the temperature wobbles. Use these rules:
- below 18 °C: switch the heater on
- above 22 °C: switch the heater off
- from 18 to 22 °C: leave
heaterOnas it is
Update heaterOn, then print the temperature and the heater state like the sample.
17.50 C: heater ON
Choosing with switch
switch compares one whole number or character with several fixed values. break ends each case; default catches everything else.
Green
Mode selector
A rotary switch sets mode: 1 is Manual, 2 is Auto, 3 is Test. Anything else is Unknown. Print the mode with a switch, exactly as in the sample.
Mode 2: Auto
Try it on a real Uno
Download Above the threshold?, replace the fixed reading with int reading = analogRead(A0); inside loop(), add delay(500); and upload it with a potentiometer on A0. Turn the knob and watch HIGH and LOW swap over as you pass the middle.
Want more? Code Along chapter 3 has a Deeper exercise that goes further than this lesson. It is optional.