Learning Goals 5 min
By the end of this lesson you will be able to:
- Use
Serial.available()at the top ofloop()to check whether the user has typed anything into the Serial Monitor. - Use
Serial.read()to fetch one typed character at a time into acharvariable. - Compare the character with single-quote literals like
'r'or'g'and run different code for different commands — turning the laptop keyboard into a remote control for the Arduino.
Warm-Up 10 min
For two lessons now the conversation has been one-way: the Arduino talks, you read. Today the cable becomes a proper conversation — you type, the Arduino reacts. The same Serial Monitor window you've been reading from has had an input box at the top all along; today you finally use it.
Quick-fire puzzle
Imagine the Arduino as a tiny friend sitting on your desk, deaf and blind, listening only down the USB cable. You type a single letter into the Monitor and hit Send. Three things must happen before the Arduino can react:
- Your laptop has to send the keystroke down the cable.
- The Arduino has to notice something arrived.
- The Arduino has to look at what it was and decide what to do.
Which step do you think is the trickiest for a beginner — and why?
Reveal the answer
Step 2 — noticing — is the tricky one. The Arduino's loop() is running at thousands of cycles per second, mostly doing nothing. A character could arrive at any moment. So before reading anything, the sketch must check "is there anything waiting for me?" That check is what Serial.available() does. Skip the check and your sketch will try to read empty air — and what it reads back will be garbage.
Steps 1 and 3 are easy: the laptop already knows how to send (when you click Send), and matching a single character against 'r' is just an if statement (L01-20). The whole lesson is really about that one "is anything waiting?" check.
New Concept — the receive buffer and the three lines that read it 15 min
The big idea — a tiny mailbox
The Arduino doesn't sit and wait for you to type — it would never get anything else done. Instead, the hardware has a small receive buffer: a little mailbox that quietly fills with characters as they arrive down the cable, even while your loop() is busy with other work. Your job, every loop pass, is to peek in the mailbox and ask "is there any post?" If yes, fetch one item. If no, move on.
That mailbox holds up to 64 characters on a Uno before it starts dropping the oldest ones. Tiny — but for a person typing one letter at a time, more than enough.
The two lines you need to memorise
Add these to the two from L01-24 and you can have a full conversation.
Serial.available(); // returns how many bytes are waiting (0 = nothing typed)
Serial.read(); // returns the oldest byte and removes it from the mailboxThe standard input pattern
Almost every input sketch in this lesson — and the next two — has the same shape inside loop():
void loop() {
if (Serial.available() > 0) {
char c = Serial.read();
// decide what to do with c
}
}Three details to notice:
- The
ifguard.Serial.available() > 0means "there's at least one character waiting". Without this check,Serial.read()would return-1(the "nothing here" value) and your logic would behave randomly. - The
chartype.charis a one-character variable type — exactly the right shape for a single typed letter. (It's actually an 8-bit integer with a letter painted on it, but L01-27 is when we lift the hood.) - One character per
loop()pass. Each pass reads one character. If the user types"abc"and hits Send, the buffer gets three letters and they're read on three consecutive loop passes. The pattern handles this naturally — you don't need to do anything special.
Comparing with single-quote literals
Once you have a char in a variable, comparing it is exactly like comparing numbers — only the values use single quotes:
if (c == 'r') { // note: SINGLE quotes, one character only
digitalWrite(RED_PIN, HIGH);
}
else if (c == 'g') {
digitalWrite(GREEN_PIN, HIGH);
}Single quotes for one character, double quotes for strings (text of any length). 'r' and "r" look identical to a human but mean different things to the compiler — single is a number, double is a sequence of numbers ending in a hidden zero. Today, always use single.
The "Newline" setting matters
Look at the bottom-left of the Serial Monitor — there's a dropdown that says "No line ending", "Newline", "Carriage return", or "Both". This controls what the Monitor secretly tacks onto the end of every message you Send.
If it's set to "Newline", typing r and hitting Send actually delivers two characters to the Arduino: r followed by a hidden newline character. Your sketch then reads r, runs the red branch, and immediately reads the newline — which doesn't match any of your 'r'/'g'/'y' commands, so nothing happens. Confusing if you don't know it.
For today's single-letter commands, set the dropdown to "No line ending". We'll deal with newlines properly in L01-28.
Why it matters
Reading from Serial turns your sketch into a remote-controlled device. The patterns are tiny — five lines of code — but they unlock an entire family of projects: typing commands to drive LEDs, sliders to dial in motor speed, text triggers to play tunes, even simple chat bots. Every IoT device in your home accepts commands over a wire or radio; this is the simplest form of that pattern.
Worked Example — the typed traffic light 20 min
You're going to type r, y, or g into the Monitor and watch the corresponding LED light up on your breadboard — like operating a tiny traffic light by keyboard. Same wiring as L01-15 (three LEDs on D9, D10, D11, sharing GND through the − rail). No new components.
Step 1 — Refresh the wiring
If you've already broken down the L01-15 circuit, rebuild it. Three LEDs, each with a 220 Ω resistor, anodes to D9 (red), D10 (yellow), D11 (green), cathodes back to GND through the − rail. Same picture as L01-15.
Step 2 — The sketch
Open a new sketch and type this in:
// Typed traffic light — r/y/g key controls LEDs
const int RED_PIN = 9;
const int YELLOW_PIN = 10;
const int GREEN_PIN = 11;
void setLeds(int r, int y, int g) {
digitalWrite(RED_PIN, r);
digitalWrite(YELLOW_PIN, y);
digitalWrite(GREEN_PIN, g);
}
void setup() {
Serial.begin(9600);
pinMode(RED_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
Serial.println("Type r, y, or g and press Send.");
}
void loop() {
if (Serial.available() > 0) {
char c = Serial.read();
if (c == 'r') {
setLeds(HIGH, LOW, LOW);
Serial.println("RED");
}
else if (c == 'y') {
setLeds(LOW, HIGH, LOW);
Serial.println("YELLOW");
}
else if (c == 'g') {
setLeds(LOW, LOW, HIGH);
Serial.println("GREEN");
}
}
}Step 3 — Upload, set the line-ending, type
- Upload the sketch.
- Open the Serial Monitor at 9600 baud.
- At the bottom-left of the Monitor, set the line-ending dropdown to "No line ending". This is the step everyone forgets.
- In the text box at the top, type
rand click Send. The red LED lights up; the Monitor echoesRED. - Type
ySend → yellow.gSend → green.ragain → red. - Now try typing
x. Nothing happens — none of theifbranches match, so the sketch just goes back to waiting. That's the right behaviour: unknown commands are silently ignored.
r typed in the top box, RED echoed in the output below. Both dropdowns set correctly — line-ending off, baud rate 9600. Get these two wrong and the sketch behaves strangely.Step 4 — Try a multi-character send
Now type rygr (no spaces) and hit Send. Four characters arrive at once. Watch the LEDs and Monitor:
RED
YELLOW
GREEN
REDEach loop pass reads one character, runs the matching branch, and moves on. With four characters in the buffer and a loop that runs thousands of times per second, all four are processed in well under a millisecond. The LEDs flash through red → yellow → green → red so fast you only see the final one (red). The Monitor, though, captures every step. This is the standard input pattern doing exactly what it should.
Trace it on paper
For the input "rg", fill in what happens on each loop pass.
| Pass | Buffer before | Serial.available() | c after read | Branch taken | Buffer after |
|---|---|---|---|---|---|
| 1 | r g | 2 | 'r' | ____ | ____ |
| 2 | ____ | ____ | ____ | ____ | (empty) |
| 3 | (empty) | 0 | — | none (the if is false) | (empty) |
If you can fill in pass 1 and pass 2 without uploading, you've understood the buffer.
Try It Yourself — three remote controls 20 min
Goal: An echo sketch. Whatever character you type, the Arduino prints You sent: X back at you, where X is the character. No wiring at all — just the USB cable.
Plan: read one character with the standard input pattern, then build the reply line with print + println (the L01-24 trick).
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
char c = Serial.read();
Serial.print("You sent: ");
Serial.println(c);
}
}Questions:
- Type
helloand hit Send. How many lines appear in the Monitor and why? ____ - Change the line-ending dropdown from "No line ending" to "Newline". Re-send
hello. How many lines now, and what's the extra one? ____ - Type a space, then Send. Does anything appear? What's on the line after
You sent:? ____
Goal: A toggle sketch. Wire one LED on D9 (L01-07 circuit). Type t to toggle the LED — each t Send flips its state from off → on or on → off. No delay; the LED stays in whatever state you last set it to.
Plan: keep a mutable global int ledState = 0;. When you receive 't', flip the state and apply it.
const int LED_PIN = 9;
int ledState = 0;
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
if (Serial.available() > 0) {
char c = Serial.read();
if (c == 't') {
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
Serial.print("toggled, now ");
Serial.println(ledState);
}
}
}Questions:
- The operator
!means "not". WhenledStateis 0, what does!ledStatebecome? When it's 1? ____ - Type
tttt(four t's) and hit Send once. The Monitor prints four lines instantly. What state does the LED end up in — on or off — and why? ____ - Add a
qcommand that quits by forcing the LED off regardless of state. Where in yourloop()does the newelse ifgo? ____
Goal: A tone keyboard. Wire a piezo buzzer on D8 (L01-14 circuit). Each of the keys a, s, d, f, g, h, j plays a different note of the C-major scale (C, D, E, F, G, A, B). One key per Send.
Plan: chain seven if/else if branches inside the standard input pattern. Each one calls tone(8, freq, 300) with that note's frequency.
const int BUZZER_PIN = 8;
void setup() {
Serial.begin(9600);
pinMode(BUZZER_PIN, OUTPUT);
Serial.println("Keys a s d f g h j play C D E F G A B");
}
void loop() {
if (Serial.available() > 0) {
char c = Serial.read();
if (c == 'a') tone(BUZZER_PIN, 262, 300); // C
else if (c == 's') tone(BUZZER_PIN, 294, 300); // D
else if (c == 'd') tone(BUZZER_PIN, 330, 300); // E
else if (c == 'f') tone(BUZZER_PIN, 349, 300); // F
else if (c == 'g') tone(BUZZER_PIN, 392, 300); // G
else if (c == 'h') tone(BUZZER_PIN, 440, 300); // A
else if (c == 'j') tone(BUZZER_PIN, 494, 300); // B
}
}Questions:
- Type
adgjand Send. Do you hear all four notes, or just one? Why? ____ (Hint: eachtone(…, 300)overrides the previous one almost immediately.) - If you wanted to actually hear all four notes as a quick arpeggio, what one call from L01-14 would you add inside each branch after the
tone? ____ - Add an eighth key —
k— that plays high C (523 Hz). One newelse if. ____
Mini-Challenge — the four-key remote 10 min
"One Arduino, four commands"
Combine all of Cluster B and C in one tiny command shell. Wire three LEDs on D9/D10/D11 and a piezo buzzer on D8 (the L01-15 circuit). Now build a sketch that responds to four typed commands:
| Key | Effect |
|---|---|
r | Red LED on, others off, buzzer silent. |
g | Green LED on, others off, buzzer silent. |
b | Beep the buzzer at 440 Hz for 200 ms. LEDs unchanged. |
q | Quit: all LEDs off, buzzer silent. |
Your task:
- Reuse the
setLeds(r, y, g)helper from L01-23. - Use the standard input pattern with a four-way
if/else ifchain. - After every command, print a short confirmation to the Monitor (e.g.
RED,GREEN,BEEP,QUIT). - Print a helpful
"Commands: r g b q"banner insetup()so a fresh user knows what to type.
It works if:
- Typing
rSend turns only the red LED on. Typinggswaps it for green. Typingbbeeps without changing the LED. Typingqturns everything off. - Typing
rbgbqas one Send runs all five commands in sequence: red, beep, green, beep, off.
Reveal one valid sketch
// Four-key remote — r/g/b/q
const int RED_PIN = 9;
const int YELLOW_PIN = 10;
const int GREEN_PIN = 11;
const int BUZZER_PIN = 8;
void setLeds(int r, int y, int g) {
digitalWrite(RED_PIN, r);
digitalWrite(YELLOW_PIN, y);
digitalWrite(GREEN_PIN, g);
}
void setup() {
Serial.begin(9600);
pinMode(RED_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
Serial.println("Commands: r g b q");
}
void loop() {
if (Serial.available() > 0) {
char c = Serial.read();
if (c == 'r') {
setLeds(HIGH, LOW, LOW);
Serial.println("RED");
}
else if (c == 'g') {
setLeds(LOW, LOW, HIGH);
Serial.println("GREEN");
}
else if (c == 'b') {
tone(BUZZER_PIN, 440, 200);
Serial.println("BEEP");
}
else if (c == 'q') {
setLeds(LOW, LOW, LOW);
noTone(BUZZER_PIN);
Serial.println("QUIT");
}
}
}Same standard input pattern as the worked example, just with one extra command and the buzzer helper from L01-14. Unknown letters (like x) fall through every branch and are silently ignored — exactly the polite behaviour you want from a command interface. This four-key remote is the seed of every "command-line" tool ever built.
Recap 5 min
The Arduino has a tiny receive mailbox that fills with characters as they arrive down the USB cable. Every loop pass, the standard input pattern asks "is anything in there?" with Serial.available(); if yes, it grabs one with Serial.read() into a char and runs whichever if/else if branch matches. Compare with single-quote literals. Set the Monitor's line-ending to "No line ending" while you're working with one-letter commands. Five lines of code turn the laptop keyboard into a remote control for your sketch.
- Receive buffer
- A small piece of memory (about 64 bytes on a Uno) that automatically stores incoming characters from the USB cable until your sketch is ready to read them.
Serial.available()- Returns the number of bytes waiting in the receive buffer right now. Returns 0 when nothing is waiting. Use as the
ifguard before every read. Serial.read()- Returns the oldest byte from the buffer and removes it. Returns
-1if the buffer is empty — which is why you always guard it withSerial.available()first. char- The data type for exactly one character. Stores it as a small integer (its character code), but you can compare and assign it like a letter.
- Single-quote literal
- A character written between single quotes —
'r','?','1'. One character, never more. Different from a double-quoted string like"r", which is a sequence of characters. - Line-ending dropdown
- The Monitor setting that adds an invisible newline (and/or carriage return) to the end of every Send. Set to "No line ending" for single-character commands; we'll need other settings in L01-28.
Homework 5 min
The five-key remote. Take today's four-key remote and add a fifth command of your own design. It must:
- Use a single letter that isn't already taken (so not r, g, b, or q).
- Do something the existing four don't — e.g. flash all three LEDs five times, play a two-note jingle, or run a sweep across the LEDs from red to green over one second.
- Print a confirmation line in the Monitor when triggered.
- Be listed in the
"Commands: …"banner insidesetup().
Also: a design reflection on paper.
- Imagine you wanted a sixth command that needs two letters to specify it (e.g.
r5means "flash red five times"). Why is that hard with today's pattern? ____ (Hint: each loop pass reads only one character.) - The Arduino's receive buffer is 64 bytes. If you pasted a 100-character sentence into the Monitor and hit Send, what would happen to the last 36 characters? ____
- List two everyday devices you own (or have used) that accept typed commands. The line between "command-line program" and "tiny embedded device" is thinner than you'd think. ____
Bring back next class:
- The saved
.inofile (call itfive-key-remote). - A short phone video (15–20 seconds) showing you typing four or five commands into the Monitor and the LEDs/buzzer reacting to each.
- Your three reflection answers in your notebook.
Heads up for next class: L01-27 "ASCII Basics" answers the question we kept ducking today — what is a character actually, under the hood? You'll discover that the letter A is the number 65, and that you can do arithmetic on letters as easily as on numbers. That unlocks several powerful tricks in L01-28's switch/case lesson.