1. Introduction
Now that we have a basic understanding of serial communication, it's time to explore the different library functions the ESP32 (Arduino core) provides for performing serial communication between the microcontroller and a host computer or another device.
Serial library is extensive, but only a handful of functions are used
in most day-to-day projects. This guide focuses on the most commonly used functions, explains
what they do, and demonstrates them with real code you can upload to your ESP32.
For a complete reference of every function available in the Serial library, you can always check the official Arduino documentation, which lists all supported methods, overloads, and parameters in detail.
2. Commonly Used Serial Library Functions
Below is a summary table of the core functions you will use constantly when working with serial communication on the ESP32.
| Function | Purpose | Typical Use |
|---|---|---|
Serial.begin(baud) |
Initializes the serial port and starts communication at a specified baud rate. | Called once, inside setup() |
Serial.write(byte) |
Sends a single raw byte of data over the serial connection. | Sending binary data, not human-readable text |
Serial.print(data) |
Converts data (number, character, string, variable) to ASCII text and sends it. | Displaying readable text/values on Serial Monitor |
Serial.println(data) |
Same as print(), but also sends a newline character afterward. |
Printing lines of output, one per line |
Serial.available() |
Checks whether there is incoming data waiting to be read in the serial buffer. | Before attempting to read incoming data |
Serial.read() |
Reads a single byte of incoming serial data from the buffer. | Reading data sent from the computer to ESP32 |
2.1 Serial.begin() — Starting the Communication
Serial is the class name and begin() is the function used to
start the communication. You need to specify the baud rate — the speed at which
data will be transmitted. A very common value used is 9600.
Serial.begin(9600);
Serial.begin()
to allow the serial module to fully initialize before sending any data.
2.2 Serial.write() — Sending a Single Byte
Serial.write() is used to send a single raw byte from the microcontroller to
another connected device. Unlike print(), it does not convert the
value to readable text — it sends the exact numeric byte value.
2.3 Serial.print() / Serial.println() — Sending Readable Data
Serial.print() is a very flexible function — you can pass it a single byte,
a character, a string, or even a variable. It automatically converts whatever you pass into
ASCII text before sending it to the other device, making it human-readable.
Serial.println() works exactly the same way, but it additionally sends a
newline character at the end, so the next output appears on a fresh line.
2.4 Serial.available() and Serial.read() — Receiving Data
Serial.available() is used to check whether there is data waiting on the
serial line to be received. Serial.read() is then used to actually read that
incoming data, one byte at a time.
3. Building the Program Step by Step
Let's write a simple program that demonstrates Serial.begin() and Serial.println() in action.
3.1 Step-by-Step Construction
Serial.begin(9600) inside setup() to initialize communication.Serial.println() to print a welcome message.delay() function.3.2 Complete Code
// Basic Serial Communication Example - ESP32 void setup() { Serial.begin(9600); // Start serial communication at 9600 baud delay(100); // Small delay to let Serial module initialize } void loop() { Serial.println("Welcome to ESP32 Serial Communication"); delay(2000); // Wait 2 seconds before repeating }
3.3 Printing a Variable
Let's extend the example by declaring a global variable and printing its value alongside our welcome message, incrementing it each time through the loop.
// Serial Communication with a Counter Variable int i = 0; // Global variable void setup() { Serial.begin(9600); delay(100); } void loop() { Serial.print("Welcome to Serial Communication, i = "); Serial.println(i); // print value and move to new line i++; // increment the counter delay(2000); }
i starts again from 0,
then increases as 1, 2, 3, 4... and so on, printed once every 2 seconds.
4. Uploading the Code & Using the Serial Monitor
4.1 Upload Procedure
Follow these commands one at a time in the Arduino IDE:
Tools → Board → (Select your ESP32 board) Tools → Port → (Select the correct COM port) Sketch → Upload (or press Ctrl+U)Write Code→ Compile→ Connect Board→ Upload→ Run on ESP32
4.2 Opening the Serial Monitor
To view the output being sent from the ESP32, we need a terminal-like tool capable of reading serial ports — either physical UART ports or the virtual USB-serial ports created by boards like the ESP32. The Arduino IDE has this built in.
Tools → Serial Monitor (or click the Serial Monitor icon, top-right corner)4.3 Matching the Baud Rate
The Serial Monitor has its own baud rate setting, usually found at the bottom-right of the
monitor window. This value must match the baud rate you set in
Serial.begin() in your code.
Wrong Baud Rate → Garbage Characters
Correct Baud Rate (9600) → Readable Text Output
Serial.begin(), the computer will not be able to correctly interpret the
incoming bits, resulting in garbled/garbage characters on screen. Selecting the same rate
(e.g., 9600) in both places fixes this immediately.
5. Understanding ASCII: print() vs write()
This is one of the most important — and most commonly misunderstood — concepts for beginners working with serial communication.
5.1 The Core Difference
| Function | What It Sends | Example: value 0 |
|---|---|---|
Serial.print(0) / println(0) |
Converts the number to its text (ASCII) representation | Sends the character '0' (ASCII decimal 48) |
Serial.write(0) |
Sends the raw byte value as-is, no conversion | Sends the raw byte 0 (ASCII NULL character) |
0 is not ASCII "zero" by default — it's the ASCII
NULL character. Serial.print()/println() will
correctly convert a numeric 0 into the printable character '0'. But
Serial.write() sends the raw byte, which for value 0 is a non-printable NULL
character, not the digit zero.
5.2 A Quick Look at the ASCII Table
Characters below decimal value 32 are non-printable control characters. Printable characters begin around decimal 33 ('!') and continue through numbers, letters, and symbols. Digits '0'–'9' correspond to decimal values 48–57.
5.3 Demonstration: write() vs println()
// Demonstrating raw byte write() vs ASCII println() int i = 0; void setup() { Serial.begin(9600); delay(100); } void loop() { Serial.write(i); // sends RAW byte value of i (not text) i++; delay(500); }
When this code runs, the Serial Monitor will show mostly blank/garbage output for values
below 33, since those are non-printable control characters. Once i reaches
33 ('!'), printable characters begin appearing. By the time it reaches
48–57, you will see the actual digit characters '0' through '9' appear as
raw bytes coincidentally match their ASCII digit codes.
Serial.print() / Serial.println()
whenever you want to display human-readable values (numbers, text, variables) on the Serial
Monitor. Only use Serial.write() when you specifically need to send raw binary
byte values, such as for custom communication protocols.
6. Summary & Key Takeaways
Serial.begin(baud)initializes serial communication at a chosen speed — commonly 9600.Serial.write()sends raw bytes with no text conversion.Serial.print()andSerial.println()convert values into readable ASCII text;println()adds a newline.Serial.available()andSerial.read()are used together to receive incoming data.- The Serial Monitor's baud rate must match the code's baud rate, or output will appear as garbage.
- Numeric values sent with
write()are interpreted as raw ASCII codes, not decimal digits — always preferprint()/println()for readable variable output.