Unit B - Inputs & Outputs

09. UART Serial & Debugging

Watch your sketch over USB Serial, print useful labels, and accept simple commands.

Estimated time 3 hours

Learning outcomes

  • Explain why baud rates must match on both ends
  • Use Serial.print and Serial.println with clear labels
  • Read characters with available and read
  • Know when parseInt helps and how it can block
  • Apply a calm debug-print strategy instead of flooding the Monitor

Parts and preparation

Arduino Uno, USB data cable and Arduino IDE 2 Serial Monitor. Onboard LED only - no breadboard required.

Before power: inspect wiring, confirm supply voltage and ensure all connected circuits share GND.

UART Serial & Debugging instructional connection diagram

Why Serial matters

When LEDs alone cannot explain a bug, Serial is your window into the sketch. You print what the board thinks - inputs, decisions, outputs - and you can send simple commands back.

On the Uno, USB Serial shares the hardware UART with pins D0 (RX) and D1 (TX). Avoid parking other devices on those pins while uploading or debugging.

Path from sketch Serial.print through USB to Serial Monitor and commands back via Serial.read
Sketch <-> USB serial <-> Serial Monitor. Observe and command.

UART and baud rate

UART sends bits asynchronously: both ends agree on bit timing (baud). Serial.begin(9600) sets the sketch side; the Monitor dropdown must show the same number.

If they differ, you get garbage characters or nothing useful. 9600 is the course default - slow enough to read, fast enough for student demos.

Sketch Serial.begin 9600, USB link, Monitor also set to 9600
Both ends must use the same baud. Mismatch looks like nonsense text.

Serial.print continues on the same line. Serial.println adds a line ending so the next message starts below.

Bare numbers are hard to read in a hurry. Prefer labels and units: Serial.print("raw="); Serial.println(raw);

Labelled print plus println versus two bare println numbers
Labels turn a stream of digits into something you can trust at a glance.
Serial.print("cmd=");
Serial.println(command);

Receiving commands

Serial.available() reports how many bytes are waiting. Serial.read() returns one byte (often stored in a char).

Compare characters carefully: '1' is the character one, not the integer 1. Monitor line endings (NL/CR) also arrive as bytes - ignore them if your sketch only cares about '0' and '1'.

parseInt() reads digit characters into an integer. Handy for brightness values, but it can wait until a non-digit or a timeout - that wait blocks other work.

Four steps: available, read, decide, act with note that quote 1 is a character
available -> read -> decide -> act. Confirm with a println.
CallRole
Serial.begin(9600)Start UART at 9600 baud
Serial.available()Bytes waiting in the buffer
Serial.read()Take one byte
Serial.print / printlnSend text to the Monitor
Serial.parseInt()Read an integer (can wait)

Debugging strategy

Print the few values that prove the story: the key input, the branch you took, the output you set. Do not print on every loop pass unless you throttle it - a flood hides the bug.

After digitalWrite, print what you intended ("LED ON"). If the Monitor says ON but the LED is dark, the fault is wiring or pinMode - not the if logic.

Three cards: what to print, how to pace messages, and what to avoid
Aim the flashlight. Print on change or at a calm rate.

What the worked sketch practises

Type 1 or 0 in the Serial Monitor to turn the onboard LED on or off. The sketch echoes confirmation so you can see command and effect together.

Set line ending to No line ending while testing single keys, or teach your if-chain to ignore '\n' and '\r'.

Wiring and safe build sequence

  1. USB data cable from PC to Uno (charge-only cables fail silently)
  2. Select the correct board and port in the IDE
  3. Open Serial Monitor at 9600 baud
  4. Do not attach extra hardware to D0/D1 during this lesson
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 ledPin = LED_BUILTIN;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("Lesson 09: type 1 for ON, 0 for OFF");
}

void loop() {
  if (Serial.available() > 0) {
    char command = Serial.read();

    if (command == '1') {
      digitalWrite(ledPin, HIGH);
      Serial.println("LED ON");
    } else if (command == '0') {
      digitalWrite(ledPin, LOW);
      Serial.println("LED OFF");
    }
    // ignore other bytes such as line endings
  }
}

How the code works

  1. '1' and '0' are character literals; 1 and 0 without quotes are numbers.
  2. Line-ending characters fall through the if/else if and are ignored.
  3. Confirmation prints prove the branch ran - useful when the LED seems dead.
  4. Match Monitor baud to Serial.begin(9600).

Test and record evidence

Expected result: Typing 1 turns the onboard LED on and prints LED ON. Typing 0 turns it off and prints LED OFF.

Practical evidence checklist

Common faults and checks
  • Match 9600 baud in the Monitor dropdown.
  • Blank Monitor: use a USB data cable, correct port, and open Monitor after upload.
  • If commands seem to fire twice, check line ending settings or print the raw byte as a number to see CR/LF.
  • Garbage text usually means a baud mismatch.
  • LED never changes but prints work: confirm LED_BUILTIN and that nothing else drives pin 13.
Extension challenge: Accept a brightness from 0 to 255 with parseInt and apply it with analogWrite on a PWM pin (for example D9 + LED + resistor). Print the parsed value so you can see timeouts and partial input.

Check your understanding

Q1. Why must baud rates match?

Show answer

The receiver needs the same bit timing as the sender.

Q2. What does Serial.available report?

Show answer

The number of bytes waiting to be read.

Q3. Why compare to '1' instead of 1?

Show answer

'1' is the character code from the keyboard; 1 is the integer one.

Q4. What is the risk of parseInt in loop?

Show answer

It can wait for more digits or a timeout, blocking other work.

Q5. Name one good debug-print habit.

Show answer

Label values, print key decisions/outputs, and avoid flooding every loop pass.