Learning Goals 5 min
By the end of this lesson you will be able to:
- Use Arduino's three boolean operators —
&&(AND),||(OR),!(NOT) — and explain what each one returns for every combination of true/false inputs. - Write a truth table for any expression involving these operators, and use the table as a debugging tool when an expression behaves unexpectedly.
- Recognise that the same three operations exist physically as logic gates inside every chip on earth — so the AND in your sketch is the conceptual same thing as the AND in the Arduino's silicon.
Warm-Up 10 min
You've already used && and || for two-button combos since L01-21. Today they get their proper name — boolean operators — and a third sibling, ! (NOT), joins the team. Together these three are the entire vocabulary of digital logic, and they show up everywhere from your code to the silicon inside the chip running it.
Quick-fire puzzle
Read these everyday sentences carefully — they hide a famous trap of how the word "and" is used in English vs in code.
- "You can have dessert if you eat your vegetables and your fish." — When can you have dessert?
- "This drink is suitable for vegetarians and vegans." — Who can drink it?
- "Please bring your passport and your boarding pass." — What two items do you need?
Reveal the answer
- Only if both vegetables and fish are eaten. This is the code sense of AND: both conditions must be true.
- Both vegetarians AND vegans — meaning each of them, separately, can drink it. This is the everyday English sense, which sounds like AND but really means "any member of either group" — which in code would be OR.
- Both items. Same as #1 — strict AND.
Sentence 2 is the trap: English uses "and" loosely; code does not. In Arduino, && means strict-both — every operand must be true for the whole expression to be true. If you ever find yourself writing if (a == 1 && a == 2), you've fallen into the trap: in code that's "a equals both 1 and 2 at the same time", which is never true. Today's lesson nails this down with a tool — the truth table — that takes the guessing out.
New Concept — three operators, three tables 20 min
The big idea — boolean values are bits
A boolean value has exactly two possibilities: true or false. In Arduino code, all of the following are interchangeable ways of writing the same two values:
true/false— the keyword forms; clearest in conditions.HIGH/LOW— whatdigitalReadreturns; same numeric values.1/0— the raw integer; what's actually stored in memory.
The Arduino has a dedicated type for them: bool. You've been using bool-shaped values implicitly since L01-08 — every if condition is one. Today they become first-class citizens with their own operators.
Operator 1 — AND (&&)
a && b is true only when both a and b are true. Truth table:
a | b | a && b |
|---|---|---|
| false | false | false |
| false | true | false |
| true | false | false |
| true | true | true |
Three falses, one true — only the bottom row qualifies. Real-world reading: "the alarm fires only if the door is open AND the system is armed."
Operator 2 — OR (||)
a || b is true when at least one of a or b is true. Truth table:
a | b | a || b |
|---|---|---|
| false | false | false |
| false | true | true |
| true | false | true |
| true | true | true |
Three trues, one false — only "both false" fails. Real-world reading: "the light turns on if the motion sensor fires OR the button is pressed."
Operator 3 — NOT (!)
!a is true when a is false, and false when a is true. It flips the value. Truth table (only one input — there are only two rows):
a | !a |
|---|---|
| false | true |
| true | false |
Real-world reading: "the LED turns on when the button is NOT pressed" — useful with INPUT_PULLUP where a pressed button reads LOW.
Combining them — compound expressions
You can chain operators freely. Use parentheses to make the order explicit and the meaning unambiguous:
if (armed && (doorOpen || windowOpen)) {
// fire alarm if armed AND (door OR window is open)
}
if (!buttonPressed) {
// runs when button is NOT being held
}
if (a && !b) {
// "a but not b" — fires only when a is true AND b is false
}The trick to reading a long boolean expression is to build its truth table in your head, row by row. If the expression has three inputs (a, b, c), there are eight rows (2 × 2 × 2). Four inputs — sixteen. The number of rows doubles per input, which is exactly why too many inputs in one condition becomes unreadable.
Gates inside the chip
Every chip you've touched contains millions of physical implementations of these three operators. They're called logic gates:
- AND gate — two input wires, one output wire. Output is HIGH only when both inputs are HIGH. The
&&in your code, in transistors. - OR gate — output HIGH when at least one input is HIGH. The
||in your code, in transistors. - NOT gate (also called an "inverter") — one input, one output. Output is the opposite. The
!in your code, in transistors.
Each gate is roughly four transistors (about a billionth of a square millimetre). Your Uno's chip has roughly 100,000 of them; a modern phone CPU has tens of billions. They have schematic symbols you'll see on circuit diagrams:
Short-circuit evaluation — a useful detail
When the chip evaluates a && b, it checks a first. If a is false, the whole expression is automatically false — there's no need to check b, so the chip doesn't bother. Same for a || b: if a is true, the chip skips b.
This is called short-circuit evaluation. Two reasons it matters:
- Speed — skipping unnecessary work, especially when the second operand is an expensive function call.
- Safety — you can put a guard first:
if (n > 0 && arr[n - 1] == 5)safely handlesn = 0because the array access is never evaluated.
Why it matters
Every conditional you'll ever write — in Arduino, in Python, in JavaScript, in spreadsheet formulas, in database queries — is built from these three operators. Every logic chip ever fabricated implements them in silicon. The truth-table tool you learn today is the universal language for reasoning about digital logic: ten minutes of practice with truth tables saves hours of "why doesn't my condition do what I expect" debugging.
Worked Example — three LEDs, three operators 20 min
One sketch that visibly shows each operator's truth table in real time. Two buttons drive three LEDs — one per operator. Press the buttons in all four combinations; each LED's behaviour proves the operator's truth table.
The wiring
Reuse parts from earlier lessons — nothing new:
- Two buttons on D6 (A) and D7 (B) with
INPUT_PULLUP(L01-21 wiring). - Three LEDs on D9, D10, D11 with 220 Ω resistors (L01-15 wiring), sharing GND through the − rail.
The sketch
// Visual truth table — three LEDs prove three operators
const int BTN_A = 6;
const int BTN_B = 7;
const int LED_AND = 9;
const int LED_OR = 10;
const int LED_NOT = 11;
void setup() {
Serial.begin(9600);
pinMode(BTN_A, INPUT_PULLUP);
pinMode(BTN_B, INPUT_PULLUP);
pinMode(LED_AND, OUTPUT);
pinMode(LED_OR, OUTPUT);
pinMode(LED_NOT, OUTPUT);
}
void loop() {
// Read raw button state; LOW = pressed because of INPUT_PULLUP
bool a = (digitalRead(BTN_A) == LOW);
bool b = (digitalRead(BTN_B) == LOW);
// Each LED demonstrates one operator
digitalWrite(LED_AND, a && b); // on only when both pressed
digitalWrite(LED_OR, a || b); // on when at least one pressed
digitalWrite(LED_NOT, !a); // on when A is NOT pressed
Serial.print("a="); Serial.print(a);
Serial.print(" b="); Serial.print(b);
Serial.print(" AND="); Serial.print(a && b);
Serial.print(" OR="); Serial.print(a || b);
Serial.print(" NOT(a)="); Serial.println(!a);
delay(100);
}Try every row of the truth table
- Upload at 9600 baud. Open the Monitor.
- Press neither button. Monitor:
a=0 b=0 AND=0 OR=0 NOT(a)=1. LED 9 off, LED 10 off, LED 11 on. (NOT-A is true because A isn't pressed.) - Press just A.
a=1 b=0 AND=0 OR=1 NOT(a)=0. LED 9 off, LED 10 on, LED 11 off. - Press just B.
a=0 b=1 AND=0 OR=1 NOT(a)=1. LED 9 off, LED 10 on, LED 11 on (A still isn't pressed). - Press both.
a=1 b=1 AND=1 OR=1 NOT(a)=0. All three light up except NOT-A.
The Monitor's rows match the truth tables in the New Concept exactly. You've just used three buttons and three LEDs to physically demonstrate the truth tables of every logic gate in computing.
Trace a compound expression on paper
For the expression a && !b (read: "A is pressed but B is not"), fill in the truth table for all four combinations of A and B.
a | b | !b | a && !b |
|---|---|---|---|
| false | false | true | false (a is false) |
| false | true | ____ | ____ |
| true | false | ____ | ____ (only this row should be true) |
| true | true | ____ | ____ |
Adding the intermediate !b column makes the final column easy: just AND the first column with the third. This is exactly how computer scientists work through any unfamiliar boolean expression — one operator at a time, intermediate columns first.
Try It Yourself — three boolean drills 15 min
Goal: Build the four-row truth table for each expression below, on paper. No Arduino needed.
- (a)
a || b - (b)
!(a && b)(this gate has a name — NAND) - (c)
!a || !b(should turn out identical to (b) — that's De Morgan's Law) - (d)
(a || b) && !(a && b)(this is XOR — exclusive OR)
Questions:
- (b) and (c) should produce the exact same four output values. Verify that — what does this tell you about NOT and AND/OR being interchangeable in pairs? ____
- What single row of (d)'s table is the only one that's different from a plain OR? ____ (Hint: when both are true.)
- If you had to remember just one of (a)–(d) as the "exclusive or" gate, which is the shortest expression for XOR? ____
Goal: Rewire and code the worked example so that LED 9 now lights up for NAND (NOT-AND) and LED 10 lights up for NOR (NOT-OR). LED 11 keeps doing NOT-A.
The wiring is identical to the worked example. Only the three middle lines of loop() change.
digitalWrite(LED_AND, !(a && b)); // NAND now
digitalWrite(LED_OR, !(a || b)); // NOR now
digitalWrite(LED_NOT, !a); // unchangedPress all four button combinations. Confirm: NAND LED is on for everything except "both pressed"; NOR LED is on only for "neither pressed".
Questions:
- NAND is special — every other gate can be built from NANDs alone. Why is that a useful fact for chip manufacturers? ____ (Hint: one circuit pattern, used many times.)
- The NAND row table you built is identical to which one from the easy task? ____
- If you wanted a fourth LED for XOR (exclusive OR — on when exactly one of A or B is pressed), what wiring would you add and what one-liner expression would drive it? ____
Goal: Two-rule alarm system. Three inputs — a "door" button on D6, a "window" button on D7, and an "armed" switch on D5. One LED alarm on D9 and one buzzer on D8.
Logic: alarm fires if (the system is armed) AND (door OR window is open). Express the whole rule in one boolean expression and drive both the LED and the buzzer from it.
const int ARMED = 5;
const int DOOR = 6;
const int WINDOW = 7;
const int ALARM_LED = 9;
const int BUZZER = 8;
void setup() {
pinMode(ARMED, INPUT_PULLUP);
pinMode(DOOR, INPUT_PULLUP);
pinMode(WINDOW, INPUT_PULLUP);
pinMode(ALARM_LED, OUTPUT);
pinMode(BUZZER, OUTPUT);
}
void loop() {
bool armed = (digitalRead(ARMED) == LOW);
bool door = (digitalRead(DOOR) == LOW);
bool window = (digitalRead(WINDOW) == LOW);
bool fire = armed && (door || window);
digitalWrite(ALARM_LED, fire);
if (fire) tone(BUZZER, 1000);
else noTone(BUZZER);
}Questions:
- Build the eight-row truth table for the alarm rule (three inputs = 2³ = 8 rows). How many of the rows fire the alarm? ____
- What's the only row where door is held but the alarm doesn't fire? Explain. ____ (Hint: the missing ingredient.)
- You want to add a "panic button" on D4 that fires the alarm regardless of armed state. What's the new one-line expression? ____ (Hint: another OR at the top.)
Mini-Challenge — build XOR from AND/OR/NOT 10 min
"Exclusive OR — on when one but not both"
XOR ("exclusive or") is a fourth gate that's not built into C++ as a boolean operator. It's true when exactly one of its two inputs is true — but not when both are. Your challenge: implement XOR using only &&, ||, and !, then wire it to a fourth LED to verify it works.
Two valid one-liner expressions both produce XOR (there are others):
- Form 1:
(a || b) && !(a && b)— "at least one AND not both" - Form 2:
(a && !b) || (!a && b)— "A and not B, or not A and B"
Your task:
- Pick one of the two forms. Don't peek at the other yet.
- Write a sketch that reuses the worked example's wiring (two buttons on D6/D7, three LEDs you can repurpose). Drive any one of the LEDs with your XOR expression.
- Test all four button combinations and confirm: LED is on for "just A" and "just B", off for "neither" and "both".
- On paper, build the truth table for your chosen form and confirm it matches XOR.
- Now look at the other form. Build its truth table. Same output for every row? (It should be — both forms compute XOR.)
It works if:
- Your XOR LED is on for exactly two of the four button combinations.
- The two on-rows are "A only" and "B only" — not "neither" and not "both".
- Your paper truth table matches the LED's behaviour exactly.
Reveal one valid sketch + the truth table
// XOR using AND / OR / NOT — built from L01-42's primitives
const int BTN_A = 6;
const int BTN_B = 7;
const int LED_XOR = 9;
void setup() {
pinMode(BTN_A, INPUT_PULLUP);
pinMode(BTN_B, INPUT_PULLUP);
pinMode(LED_XOR, OUTPUT);
}
void loop() {
bool a = (digitalRead(BTN_A) == LOW);
bool b = (digitalRead(BTN_B) == LOW);
bool xor_result = (a || b) && !(a && b);
digitalWrite(LED_XOR, xor_result);
}Truth table for both XOR forms:
a | b | (a||b) && !(a&&b) | (a&&!b) || (!a&&b) |
|---|---|---|---|
| false | false | false | false |
| false | true | true | true |
| true | false | true | true |
| true | true | false | false |
Both columns are identical — they're the same function written two different ways. This is the entire job of digital logic design: take a desired truth table and find the shortest combination of AND, OR and NOT gates that produces it. Real CPUs include dedicated XOR circuitry because XOR turns out to be incredibly useful (it's at the heart of addition, encryption and error detection). You've just built one from scratch.
Recap 5 min
Three operators, three truth tables, three physical gates: && (AND, both true), || (OR, at least one true), ! (NOT, flip). They live in your code as conditionals and in the chip as billions of tiny transistor circuits. Combine them with parentheses and build any logic you need — and when an expression confuses you, write its truth table. NAND, NOR and XOR are useful derived gates built from the three primitives. Short-circuit evaluation makes && and || safe to use as guard clauses. From here on, every boolean expression you write is a tiny computer-science exercise — and you have the tools to read any of them.
- Boolean
- A value that is either
trueorfalse— equivalently HIGH/LOW or 1/0. Named after George Boole, the 19th-century mathematician who invented this algebra. Arduino's type isbool. - AND (
&&) - Boolean operator that returns true only when both operands are true. The strict English-style "and".
- OR (
||) - Boolean operator that returns true when at least one operand is true. Inclusive — also true when both are true.
- NOT (
!) - Boolean operator that takes one operand and returns the opposite. Applies only to the immediately following value or parenthesised group.
- Truth table
- A small table listing every combination of input values and the resulting output of a boolean expression. The standard tool for reasoning about and debugging logic — exhaustive, never ambiguous.
- Logic gate
- A physical circuit (typically four transistors) inside a chip that implements one of the boolean operators. Every microprocessor is built from billions of them wired together.
- NAND / NOR / XOR
- Derived gates: NAND = NOT(AND), NOR = NOT(OR), XOR = "exactly one". All three can be built from the basic AND / OR / NOT primitives. NAND is so universal that entire chips are built from NAND alone.
- Short-circuit evaluation
- The behaviour that
&&stops at the first false operand and||stops at the first true one. Useful for speed and for "guard then access" patterns likeif (n > 0 && arr[n - 1] == 5). - De Morgan's Law
- The identity
!(a && b) == (!a || !b)and its dual!(a || b) == (!a && !b). Lets you push NOT inside a parenthesised group by flipping the operator. Useful when you're trying to simplify or reverse a condition. - Bitwise (
&,|) vs boolean (&&,||) - The single-character versions operate on every bit of a number independently (Level 2 topic). The doubled versions operate on whole true/false values. Use the doubled forms in
ifconditions.
Homework 5 min
The three-input puzzle. No Arduino needed for the maths part. On paper, build the eight-row truth table (three inputs A, B, C = 2³ = 8 rows) for each expression below:
a && b && ca || b || ca && (b || c)(a && b) || (b && c) || (a && c)(this is "majority vote" — true when at least two of three are true)
Then build it as a sketch. Wire three buttons on D5, D6, D7 with INPUT_PULLUP and one LED on D9. The LED should light up only when the majority vote expression is true — at least two of three buttons pressed.
Also: a design reflection on paper.
- The "majority vote" pattern is used in real systems for fault tolerance — three redundant sensors voting on a reading. Why might that be safer than just one sensor? ____
- How many rows are in the truth table for an expression with five boolean inputs? Six? Ten? Why does this make "really long conditions" hard to reason about? ____
- Of the three primitive gates (AND, OR, NOT), which one do you think is used most often in everyday code? Which gets used least? Justify briefly. ____
- The early electronic computer ENIAC (1945) had 17,468 vacuum-tube gates. A modern phone has about 50 billion. Roughly how many times more? ____ (Hint: a calculator is fine.)
Bring back next class:
- The saved
.inofile (call itmajority-vote). - A photo of your four hand-drawn truth tables in your notebook.
- Your four written reflection answers, in your notebook.
Heads up for next class: L01-43 "Auto Night Light" is the Cluster F project. It combines the LDR (L01-36) with a threshold decision (boolean logic from today) to build your first real sensor product — a light that knows when to turn itself on. After three lessons of building blocks, you finally combine them.