Hello! Welcome to the next lesson in our Arduino journey.
In our last session, we explored how to create pseudo-analog outputs using Pulse Width Modulation (PWM) and analogWrite(). You learned to control the brightness of an LED and the speed of a motor, giving your projects a new level of nuance.
So far, our Arduino sketches have been self-contained. But what if you want to see the value from a sensor in real-time on your computer? Or what if you want to send a command from your keyboard to change how your circuit behaves? Today, we'll bridge that gap. This lesson covers how to communicate between the Arduino and a host computer using the Serial library.
This is arguably one of the most important skills in embedded development. It's your primary tool for debugging, for sending data to your computer for analysis (which should resonate with your work in data analysis and BI), and for creating interactive projects that respond to user input from a PC.
1. The "Under the Hood" of Serial Communication
Before we write any code, let's understand what's happening at a lower level, as you appreciate knowing the "why" behind the "how". When an Arduino talks to your computer via USB, it's using a form of asynchronous serial communication.
- Serial: Data is sent one single bit at a time over one wire.
- Asynchronous: Unlike some protocols that use a shared clock signal to keep the sender and receiver in sync, this method doesn't. Instead, the sender and receiver must agree on a communication speed beforehand.
This agreed-upon speed is called the baud rate, measured in bits per second. If the Arduino is "speaking" at 9600 bps, the computer must be "listening" at 9600 bps, or the message will be garbled.
The following video provides an excellent deep dive into how a single byte of data is framed and transmitted.
Serial Communication with Arduino - The details!
To understand the fundamentals of how serial communication works, watch this segment from Programming Electronics Academy.
Watch the video from 01:57 to 06:54 and from 12:38 to 14:48. Focus on these key concepts: The roles of the Transmit (TX) and Receive (RX) pins. The structure of a data packet: a start bit (to signal the start of a message), the data frame (your actual data), and a stop bit (to signal the end). The importance of the baud rate for keeping the two devices synchronized.
This underlying protocol is managed for us by a dedicated chip on the Arduino board and the Serial library in our code, making it easy to use.
2. Sending Data from Arduino to PC (print, println)
The most common use of serial communication is for the Arduino to send information to the computer. This is invaluable for debugging, as you can print variable values, status messages, or sensor readings to see what your code is doing in real-time.

The Arduino IDE includes a tool called the Serial Monitor which acts as the computer's terminal for this conversation.
Let's look at the three core functions for sending data:
Serial.begin(speed): This function starts the serial communication and sets the baud rate. It's almost always placed in thevoid setup()function. The most common speed is9600, but other standard rates like115200are also used.Serial.print(data): This sends data to the serial port as human-readable text. You can print strings, integers, floats, etc. The cursor remains on the same line after the data is printed.Serial.println(data): This does the same thing asSerial.print(), but adds a carriage return and a newline character at the end, moving the cursor to the next line. This is great for printing distinct pieces of information.
The following video is a great practical walkthrough of these commands.
Arduino Tutorial 11: Understanding the Arduino Serial Port and Print Commands
This tutorial by Paul McWhorter clearly demonstrates how to set up the Serial Monitor and use the print commands. Pay close attention to how he troubleshoots a common baud rate mismatch issue.
Watch from 02:16 to 09:44. This will cover: Initializing the serial port with Serial.begin(9600). Using Serial.print() vs. Serial.println(). The critical importance of matching the baud rate in your code with the setting in the Serial Monitor window. Combining string literals and variables to create well-formatted output messages.
Your Turn: "Hello, World!" and Sensor Data
Let's write a simple sketch.
- Open the Arduino IDE.
- Enter the code below.
- Connect your Arduino board.
- Upload the code.
- Open the Serial Monitor by clicking the magnifying glass icon in the top-right corner of the IDE (or Tools -> Serial Monitor).
- Crucially, make sure the dropdown menu in the bottom-right of the Serial Monitor is set to 9600 baud.
void setup() {
// Initialize serial communication at 9600 bits per second
Serial.begin(9600);
// Wait for the serial port to connect. Needed for native USB port only
while (!Serial) {
;
}
Serial.println("Arduino is ready!");
}
void loop() {
// Print a static message
Serial.print("Uptime in seconds: ");
Serial.println(millis() / 1000); // millis() returns milliseconds since start
// Read an analog pin (leave it unconnected to see floating values)
int sensorValue = analogRead(A0);
Serial.print("Analog Pin A0 Value: ");
Serial.println(sensorValue);
delay(1000); // Wait for a second
}
You should see the uptime and a fluctuating analog value printed to the monitor every second. This simple feedback loop is the foundation of debugging in the Arduino world.
3. Receiving Data from PC to Arduino (available, read)
Now for the other direction: sending commands from the PC to the Arduino. This allows you to create interactive projects. For example, you could type 'H' to turn an LED on and 'L' to turn it off.
The process involves two main functions:
Serial.available(): This returns the number of bytes (characters) that have arrived from the PC and are waiting in the serial input buffer. It's essential to check if this is greater than zero before trying to read anything.Serial.read(): This reads one single byte/character from the input buffer.
This check-then-read pattern is fundamental. It's a non-blocking approach: your loop() function can continue running thousands of times per second, and it only acts on serial data when it's actually there.
Example: Two-Way Communication
Let's implement a classic example: controlling the built-in LED by sending commands from the Serial Monitor.
Arduino UART Example & Tutorial | Serial Communication
The following article provides a clear reference for the Serial library's functions and a perfect example of two-way communication. We will implement the example shown.
First, read the section 'Arduino UART Serial Library' to get a quick overview of the key functions. Then, carefully study the 'Arduino UART Example (Arduino – PC)' section. Pay close attention to the code and the explanation of how Serial.available() and Serial.read() are used in the loop() to check for and process incoming commands.
Now, try it yourself. Wire up an external LED or just use the built-in one (LED_BUILTIN). Upload the code from the example in the article.
- Open the Serial Monitor.
- Type
1and press Enter. The LED should turn on, and the Arduino should send back "LED is ON". - Type
0and press Enter. The LED should turn off, and the Arduino should reply with "LED is OFF".
You've just created a complete communication loop!
4. Robust Serial Input: Reading Full Commands
Reading single characters is useful, but often you'll want to send more complex commands, like "set_speed=200". This requires reading a whole string of text.
A common mistake is to assume all the characters arrive at once. As we learned, serial data is slow. A robust program reads characters one by one as they arrive and assembles them into a string, waiting for a special end-marker character (like the 'newline' character, \n, which the Serial Monitor sends when you press Enter) to know the message is complete.
The "Serial Input Basics" tutorial on the Arduino Forum is the gold standard for learning this technique.
This forum post explains a non-blocking technique for reading entire strings from the serial port. This is a much more robust and flexible method than reading single characters.
Read 'Example 2 - Receiving several characters from the Serial Monitor'. Focus on understanding the recvWithEndMarker() function. Notice how it uses a static index to fill a character array one byte at a time, and only sets the newData flag when it sees the newline \n character.
This pattern of buffering incoming characters until a delimiter is found is extremely powerful and is a common paradigm in many communication protocols. The same resource also shows how to parse this received string to extract numbers (atoi, atof) or multiple values (strtok), which are techniques you'll be familiar with from other programming languages.
Conclusion
You now have the tools to make your Arduino projects communicate with the outside world. This is a huge step forward, enabling debugging, data logging, and interactive control.
Key Takeaways:
- Serial communication is a method of sending data one bit at a time, governed by a pre-agreed baud rate.
- Use
Serial.begin(baud_rate)insetup()to initialize communication. - Use
Serial.print()andSerial.println()to send human-readable data from the Arduino to the PC's Serial Monitor. - Use the
if (Serial.available() > 0)andSerial.read()pattern to receive data from the PC in a non-blocking way. - For robustly receiving full commands or sentences, read characters into a buffer until you receive an end-marker like a newline (
\n).
Next Up
In the final lesson of this module, we'll put everything together. Now that you can read sensors, control outputs, and use the Serial Monitor for debugging, you are ready to integrate an external library to control a more complex component, like an LCD screen or a servo motor. Your new serial communication skills will be essential for troubleshooting as we add this new layer of complexity.