Unit A - Foundations

05. Operators & Decisions

Calculate, compare and branch: arithmetic, = vs ==, Boolean logic, and if/else chains.

Estimated time 3 hours

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
  • 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.

Operators & Decisions instructional connection diagram

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.

Flow from reading buttons A and B through both and either checks to selecting the output
Read inputs, test both, then either, then choose steady / flash / 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.

Cards for plus minus multiply divide and modulo with integer division trap
Five arithmetic operators. Integer division drops the remainder unless you use a float.
OperatorMeaningExample
+Add3 + 2 -> 5
-Subtract3 - 2 -> 1
*Multiply3 * 2 -> 6
/Divide5 / 2 -> 2 (ints)
%Remainder5 % 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 >=.

One equals for assignment versus two equals for comparison
= stores. == compares. Memorise this before hunting wiring faults.
bool aPressed = digitalRead(buttonA) == LOW;  // compare
ledOn = true;                                 // assign

Boolean 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).

Three cards for AND OR and NOT with course examples
AND both, OR either, NOT reverse. Prefer && and || over bitwise & and | here.

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.

Truth table of A and B for AND and OR results
Both true only for AND. OR lights up whenever at least one is true.

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).

Stacked if, else if and else branches for the two-button LED behaviour
One chain, one winner. Order matters: test both before either.
if (aPressed && bPressed) {
  // steady
} else if (aPressed || bPressed) {
  // flash
} else {
  // off
}

INPUT_PULLUP: pressed is LOW

Course buttons wire from the pin to GND with pinMode(..., INPUT_PULLUP). Open reads HIGH; pressed reads LOW.

That is why the sketch uses digitalRead(pin) == LOW for pressed - not == HIGH. If your LED behaviour feels inverted, check this first.

Open button reads HIGH, pressed button reads LOW with INPUT_PULLUP
Active-low press: compare to LOW when using INPUT_PULLUP.

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

  1. Button A: one side to D2, other side to GND
  2. Button B: one side to D3, other side to GND
  3. pinMode INPUT_PULLUP for both (no external resistor required)
  4. Output: onboard LED (LED_BUILTIN)
Power rule: switch off before moving wires. Arduino I/O pins are control signals; high-current loads require a driver and suitable external supply.
const 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

  1. Pressed is LOW because INPUT_PULLUP holds an open input HIGH.
  2. Test both (&&) before either (||) so two presses are not treated as one.
  3. millis() / 250 % 2 flips 0/1 about four times per second without delay().
  4. = would be wrong inside the if tests - those need == for comparison.

Test and record evidence

Expected result: No button: LED off. Exactly one button: LED flashes. Both buttons: LED steady on.

Practical evidence checklist

Common faults and checks
  • If behaviour feels inverted, remember pressed reads LOW with INPUT_PULLUP.
  • Check && versus || and == versus =.
  • Four-leg buttons connect opposite corners; rotate 90 degrees if a button always looks pressed.
  • 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.
Extension challenge: Give button A priority: if A is pressed, ignore B and hold the LED steady on. Only when A is released should B control flashing. Explain how your if order enforces that.

Check your understanding

Q1. What is the difference between = and ==?

Show answer

= assigns a value; == compares for equality.

Q2. When does A || B evaluate true?

Show answer

When A is true, B is true, or both are true.

Q3. What is 5 / 2 as integers on Arduino?

Show answer

2 - integer division discards the remainder.

Q4. Why compare digitalRead to LOW for a course button?

Show answer

INPUT_PULLUP wiring is active-low: pressed connects the pin to GND.

Q5. 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.