Arduino Sensor Data Serial Communication
A hands-on guide to connecting a DHT22 temperature and humidity sensor to an Arduino, transmitting sensor data to a PC via serial communication, and implementing automatic data collection and CSV storage with Python.
Problem
Required Tools
An integrated development environment for programming Arduino boards. Provides sketch writing, compilation, uploading, and serial monitor functionality.
ATmega328P-based microcontroller boards. Support digital/analog I/O pins and USB serial communication.
A digital temperature and humidity sensor. Capable of measuring temperature from -40 to 80 degrees Celsius (accuracy +/-0.5 degrees) and humidity from 0 to 100% (accuracy +/-2-5%).
A USB-B (Uno) or Mini-USB/Micro-USB (Nano) cable to connect the Arduino to a PC. Provides both power supply and serial communication simultaneously.
Solution Steps
Circuit wiring and pin layout
The DHT22 sensor comes in a 4-pin or 3-pin (module) form. Connect it to the Arduino as follows: [DHT22 Pin Layout - from left when facing front] - Pin 1 (VCC): Connect to Arduino 5V - Pin 2 (DATA): Connect to Arduino digital pin 2 + 10K ohm pull-up resistor (between VCC and DATA) - Pin 3 (NC): Not used (4-pin model only) - Pin 4 (GND): Connect to Arduino GND If using a 3-pin module-type DHT22, the pull-up resistor is built in, so no separate resistor is needed. Connect using jumper wires on a breadboard.
// === Circuit Wiring Diagram (ASCII) ===
//
// Arduino Uno DHT22 Sensor
// +-----------+ +--------+
// | | | 1(VCC) |----+---- 5V
// | 5V --+-------+--------+ |
// | | | 2(DATA)|----+---- 10K resistor ---- 5V
// | D2 --+-------+--------+
// | | | 3(NC) |
// | | +--------+
// | GND --+-------| 4(GND) |-------- GND
// +-----------+ +--------+
//
// Note: 3-pin module DHT22 has built-in pull-up resistor -> resistor can be omittedInstall DHT library in Arduino IDE
Install the Adafruit DHT sensor library for easy handling of the DHT22 sensor. In Arduino IDE: 1. Click Tools > Manage Libraries 2. Type "DHT sensor library" in the search box 3. Install "DHT sensor library by Adafruit" (also install the dependency "Adafruit Unified Sensor") 4. Alternatively, you can install via CLI.
# Install libraries via Arduino CLI
arduino-cli lib install "DHT sensor library"
arduino-cli lib install "Adafruit Unified Sensor"
# Verify installed libraries
arduino-cli lib list | grep -i dhtWrite and upload the Arduino sketch
Write a sketch that reads temperature and humidity from the DHT22 and transmits it over the serial port. Data is sent in CSV format (temperature,humidity) to make parsing easy in Python. The 2-second reading interval is because the DHT22's minimum sampling interval is 2 seconds.
#include <DHT.h>
#define DHTPIN 2 // DHT22 data pin
#define DHTTYPE DHT22 // DHT22 (AM2302) sensor type
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600); // Start serial communication (9600 baud)
dht.begin(); // Initialize DHT sensor
// Print CSV header
Serial.println("temperature,humidity");
// Wait for sensor stabilization
delay(2000);
}
void loop() {
// Read humidity (%)
float humidity = dht.readHumidity();
// Read temperature (Celsius)
float temperature = dht.readTemperature();
// Check for read failure
if (isnan(humidity) || isnan(temperature)) {
Serial.println("ERROR,ERROR");
delay(2000);
return;
}
// Serial output in CSV format
Serial.print(temperature, 1); // 1 decimal place
Serial.print(",");
Serial.println(humidity, 1);
// DHT22 minimum sampling interval: 2 seconds
delay(2000);
}Verify data with the serial monitor
After uploading the sketch, open the Arduino IDE serial monitor (Tools > Serial Monitor or Ctrl+Shift+M) to verify that data is being output correctly. The baud rate must be set to 9600, matching the value in the code. Expected output example: temperature,humidity 23.5,45.2 23.6,45.0 23.5,44.8 If you see garbled characters, the baud rate setting does not match. If "ERROR,ERROR" appears continuously, check the sensor wiring.
# Check serial monitor via Arduino CLI
arduino-cli monitor -p /dev/ttyACM0 -b arduino:avr:uno
# Or use minicom on Linux
minicom -b 9600 -D /dev/ttyACM0
# Use screen on macOS
screen /dev/cu.usbmodem14201 9600Automatic serial data collection and CSV storage with Python
Use the pyserial library to read Arduino serial data in Python and save it to a CSV file with timestamps. Data collection continues until interrupted with Ctrl+C, and warning messages are printed to the console when thresholds are exceeded.
#!/usr/bin/env python3
"""Arduino DHT22 sensor data collection script"""
import serial
import csv
import time
from datetime import datetime
# === Configuration ===
SERIAL_PORT = '/dev/ttyACM0' # Windows: 'COM3', macOS: '/dev/cu.usbmodem14201'
BAUD_RATE = 9600
OUTPUT_FILE = f'sensor_data_{datetime.now():%Y%m%d_%H%M%S}.csv'
TEMP_THRESHOLD = 30.0 # Temperature alert threshold (degrees)
HUMID_THRESHOLD = 70.0 # Humidity alert threshold (%)
def main():
# Connect to serial port
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=5)
time.sleep(2) # Wait for Arduino reset
# Skip first line (header)
header = ser.readline().decode('utf-8').strip()
print(f"Sensor header: {header}")
print(f"Data collection started... (output file: {OUTPUT_FILE})")
print(f"Temp alert: > {TEMP_THRESHOLD} degrees, Humidity alert: > {HUMID_THRESHOLD}%")
print("-" * 50)
with open(OUTPUT_FILE, 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['timestamp', 'temperature', 'humidity'])
try:
while True:
line = ser.readline().decode('utf-8').strip()
if not line or line.startswith('ERROR'):
print(f"[{datetime.now():%H:%M:%S}] Sensor read error")
continue
parts = line.split(',')
if len(parts) != 2:
continue
temp, humid = float(parts[0]), float(parts[1])
timestamp = datetime.now().isoformat()
# Write to CSV file
writer.writerow([timestamp, temp, humid])
csvfile.flush() # Write immediately
# Console output
alert = ""
if temp > TEMP_THRESHOLD:
alert += " [HIGH TEMP WARNING!]"
if humid > HUMID_THRESHOLD:
alert += " [HIGH HUMIDITY WARNING!]"
print(f"[{datetime.now():%H:%M:%S}] "
f"Temp: {temp:.1f} deg | Humidity: {humid:.1f}%{alert}")
except KeyboardInterrupt:
print(f"\nCollection stopped. Data saved to: {OUTPUT_FILE}")
finally:
ser.close()
if __name__ == '__main__':
main()Core Code
Core code for the Arduino sketch and Python serial collector. Transmits DHT22 sensor data in CSV format and saves it to a file with timestamps.
// ===== Arduino Sketch (Core Code) =====
#include <DHT.h>
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
dht.begin();
Serial.println("temperature,humidity");
delay(2000);
}
void loop() {
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println("ERROR,ERROR");
} else {
Serial.print(t, 1);
Serial.print(",");
Serial.println(h, 1);
}
delay(2000);
}
// ===== Python Collector (Core Code) =====
// pip install pyserial
//
// import serial, csv
// from datetime import datetime
//
// ser = serial.Serial('/dev/ttyACM0', 9600, timeout=5)
// ser.readline() # Skip header
//
// with open('data.csv', 'w', newline='') as f:
// w = csv.writer(f)
// w.writerow(['time', 'temp', 'humid'])
// while True:
// line = ser.readline().decode().strip()
// if line and 'ERROR' not in line:
// t, h = line.split(',')
// w.writerow([datetime.now().isoformat(), t, h])
// f.flush()Common Mistakes
Unstable sensor data due to missing pull-up resistor
You must connect a 10K ohm pull-up resistor between the DHT22 DATA pin and VCC. Without a pull-up resistor, the data line enters a floating state, causing frequent NaN values. Using a 3-pin module-type DHT22 board eliminates the need for a separate resistor since it has a built-in pull-up.
Baud rate mismatch between Arduino and Python
The Serial.begin() value in the Arduino code and the serial.Serial() baud rate value in Python must be identical (e.g., both 9600). A mismatch will display garbled characters (b'\xff\xfe...') in the serial monitor. Typically 9600 or 115200 is used.
Sensor not working properly due to insufficient USB power
The DHT22 operates at 3.3V-5V, but current may be insufficient when connected through a USB hub. Connect directly to a PC USB port, or connect an external 5V power adapter to the Arduino barrel jack. Power issues are especially common when using multiple sensors simultaneously.
Trying to open the serial port from two programs simultaneously
A serial port can only be used by one program at a time. Close the Arduino IDE serial monitor before running the Python script. If you get a "Permission denied" or "Access is denied" error, check whether another program is occupying the port.