Build a weather station that logs to an SD card

Measure temperature, humidity and light, show them on the LCD and save a reading every ten seconds to an SD card that you can open as a spreadsheet.
  • Level:Intermediate
  • Duration: 1 h 30 min
  • Ages 12+
  • Platform: Arduino

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Build a weather station that logs to an SD card – EEMENTOR STEM™ lesson

Scientists don't just look at a measurement once. They record it over hours or days and then look for patterns. In this capstone you build a small weather station that does exactly that. A DHT11 measures temperature and humidity, a photoresistor measures light, the LCD shows the live values, and every ten seconds the UNO adds a line to a file on an SD card. Afterwards you put the card in a computer and turn the file into a chart.

What you'll learn

  • How to combine three libraries (LCD, DHT and SD) in one sketch
  • How the SPI bus connects the SD card module
  • How to write a CSV file that any spreadsheet program can open
  • How to time two different jobs with millis() instead of delay()

What you need

  • UNO R3 board and USB cable (UNO R3 Starter Kit)
  • 1602 LCD display, 10 kΩ potentiometer and 1 resistor, 220 Ω (UNO R3 Starter Kit)
  • DHT11 temperature and humidity sensor (UNO R3 Starter Kit)
  • Photoresistor module (45-in-1 Sensor Kit)
  • SD card module (45-in-1 Sensor Kit)
  • An SD or microSD card that fits your module, 32 GB or smaller, formatted as FAT32 (not included)
  • Breadboard and jumper wires (UNO R3 Starter Kit)

Before you start

The LCD has 16 connections in a row. If yours has no pins, solder 16 pins from the 40-pin male header in the kit first, so it plugs into the breadboard. Ask an adult to help if you're new to soldering.

This is a bigger build than the earlier lessons, so don't wire everything at once. Add one part, test it, then add the next. When something stops working, you know it's the part you just added.

Wiring

Breadboard wiring diagram: Build a weather station that logs to an SD card
Breadboard view. Check each connection against the wiring table below.
From To
LCD VSS, RW and K GND
LCD VDD 5V
LCD V0 Middle pin (W) of the potentiometer
LCD RS UNO pin 9
LCD E UNO pin 8
LCD D4, D5, D6, D7 UNO pins 5, 4, 3, 2
LCD A (backlight +) 220 Ω resistor, then 5V
Potentiometer outer pins 5V and GND
DHT11 S (signal) UNO pin 7
DHT11 + and − 5V and GND
Photoresistor module S UNO pin A0
Photoresistor module + and − 5V and GND
SD module CS UNO pin 10
SD module MOSI UNO pin 11
SD module MISO UNO pin 12
SD module SCK UNO pin 13
SD module VCC (or +5) 5V
SD module GND GND

Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.

In the earlier LCD project, RS and E were on pins 12 and 11. Here they move to pins 9 and 8, because the SD card needs pins 11, 12 and 13. If your SD module has both a +5 and a +3.3 pin, use only the +5 pin. If it has only a 3.3 V pin, connect that to the UNO's 3V3 pin instead of 5V.

Build it in stages

  1. The screen. Wire the LCD and the potentiometer and upload the sketch. Even with nothing else connected you should see "Weather logger" and then "Sensor error". Turn the potentiometer until the text is sharp.
  2. The sensors. Add the DHT11 and the photoresistor module. The top line now shows temperature and humidity, and the bottom line shows the light level.
  3. The SD card. Unplug the USB cable, add the SD module and push in the card. Plug the cable back in. The screen shows "SD card ready", and the counter n= on the bottom line goes up by one every ten seconds.

The sketch

Install the DHT sensor library by Adafruit (and Adafruit Unified Sensor when asked). The LiquidCrystal, SPI and SD libraries are already built in.

#include <LiquidCrystal.h>
#include <DHT.h>
#include <SPI.h>
#include <SD.h>

// LCD pins: RS, E, D4, D5, D6, D7
LiquidCrystal lcd(9, 8, 5, 4, 3, 2);
DHT dht(7, DHT11);

const int LIGHT_PIN = A0;
const int SD_CS = 10;
const unsigned long SCREEN_EVERY = 2000;   // update the screen every 2 s
const unsigned long LOG_EVERY = 10000;     // save a line every 10 s

bool cardOk = false;
unsigned long lastScreen = 0;
unsigned long lastLog = 0;
unsigned int records = 0;

void setup() {
  lcd.begin(16, 2);
  dht.begin();
  lcd.print(F("Weather logger"));

  cardOk = SD.begin(SD_CS);
  lcd.setCursor(0, 1);
  if (cardOk) lcd.print(F("SD card ready"));
  else lcd.print(F("No SD card!"));

  // A new file starts with a line of column names
  if (cardOk && !SD.exists("LOG.CSV")) {
    File file = SD.open("LOG.CSV", FILE_WRITE);
    if (file) {
      file.println(F("seconds,temperature_C,humidity_pct,light_pct"));
      file.close();
    }
  }
  delay(2000);
}

void loop() {
  unsigned long now = millis();
  if (now - lastScreen < SCREEN_EVERY) return;   // nothing to do yet
  lastScreen = now;

  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  int light = map(analogRead(LIGHT_PIN), 0, 1023, 100, 0);   // bright = high %

  lcd.clear();
  if (isnan(temperature) || isnan(humidity)) {
    lcd.print(F("Sensor error"));
    return;
  }

  lcd.print(temperature, 1);
  lcd.print(F("C  "));
  lcd.print(humidity, 0);
  lcd.print(F("%"));
  lcd.setCursor(0, 1);
  lcd.print(F("L:"));
  lcd.print(light);
  lcd.print(F("% "));
  if (cardOk) {
    lcd.print(F("n="));
    lcd.print(records);
  } else {
    lcd.print(F("no card"));
  }

  if (cardOk && now - lastLog >= LOG_EVERY) {
    lastLog = now;
    File file = SD.open("LOG.CSV", FILE_WRITE);   // opens at the end of the file
    if (file) {
      file.print(now / 1000);
      file.print(',');
      file.print(temperature, 1);
      file.print(',');
      file.print(humidity, 0);
      file.print(',');
      file.println(light);
      file.close();                               // close = safely saved
      records++;
    } else {
      cardOk = false;                             // card removed or full
    }
  }
}

Look at your data

  1. Let the station run for at least ten minutes. For a more interesting result, leave it overnight on a USB charger or power bank.
  2. Wait until the counter has just gone up, then unplug the power and take out the card.
  3. Put the card in a computer and open LOG.CSV with Excel, Google Sheets or LibreOffice Calc.
  4. Select the columns and insert a line chart. Can you see when the sun came up, or when someone opened a window?

How it works

The SD card module talks to the UNO over SPI, a fast bus with four wires: MOSI carries data to the card, MISO carries data back, SCK is the clock that keeps both sides in step, and CS (chip select) tells the card that the message is for it. On the UNO, SPI always uses pins 11, 12 and 13.

The file is a CSV file: plain text with one reading per line and commas between the values. Almost every spreadsheet program can open it. SD.open("LOG.CSV", FILE_WRITE) opens the file at its end, so new lines are added after the old ones, and close() makes sure the line is really written to the card. Because each line is saved and closed straight away, you lose at most one reading if the power is cut.

The first column is the number of seconds since the UNO started, taken from millis(). Two timers run side by side: the screen is refreshed every two seconds and the card is written every ten. Text inside F("…") is kept in the UNO's larger program memory. That matters here, because the SD library needs a big part of the UNO's small working memory.

Try this next

  • Change LOG_EVERY to 60000 to save one line per minute for a whole day.
  • Add a column for the highest temperature seen so far.
  • Add the DS18B20 from the Sensor Kit as an outdoor probe (see Precise temperature with the DS18B20).
  • Start a new file each time the UNO starts: look for the first name from LOG01.CSV to LOG99.CSV that doesn't exist yet.

Troubleshooting

  • The screen lights up but shows only blocks or nothing: turn the potentiometer slowly from one end to the other.
  • "No SD card!": check the four SPI wires and the power pin, and make sure the card is pushed in fully. Format the card as FAT32 on a computer. Cards larger than 32 GB don't work with this library.
  • "Sensor error": check the DHT11 signal wire on pin 7 and its power pins.
  • The light value goes down when you shine a light on the sensor: swap 100, 0 to 0, 100 in the map() line.
  • The file is empty or the last lines are missing: the power was cut while the UNO was writing. Unplug it just after the counter goes up.
  • The UNO restarts or shows strange characters after adding the SD module: some SD modules draw a lot of current. Try another USB port or a powered USB hub.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

UNO R3 Starter Kit | Arduino IDE Compatible | Free Tutorials $56.00

Shop the kit