Guide no. 31
Log temperatures, voltages or any other measurement on a microSD card, in a file that opens in Excel. Which card and module to use, how to connect them, and a sketch that works on both the UNO and the ESP32.
By Ada Intelisano · informaticait.it technical team
- A microSD card runs at 3.3 V and draws up to 100 mA while writing: with the UNO you need a module with a regulator and a level shifter.
- The Arduino SD library reads only FAT16 and FAT32: use a microSD card up to 32 GB (SDHC). SDXC cards come formatted as exFAT.
- Warning:
FILE_WRITEon the UNO writes at the end of the file, on the ESP32 it erases it. On the ESP32 you useFILE_APPEND. - The data really reaches the card only with
close()orflush(). For Excel with Italian settings: semicolon and decimal comma.
The card
| Type | Capacity | File system | With the SD library |
|---|---|---|---|
| SD | up to 2 GB | FAT12/16 | yes (not FAT12 on very small cards) |
| SDHC | from 2 to 32 GB | FAT32 | yes: the right choice |
| SDXC | from 32 GB to 2 TB | exFAT | no: you need SdFat, or reformat |
Classes and file systems from the SD Association. Format with its program, SD Memory Card Formatter, rather than with the operating system tools: the SD Association recommends it and so does Adafruit. The SD library uses short names (8 characters plus a 3-character extension): MISURE.CSV is fine, daily_measurements.csv is not. On the ESP32 long names work, exFAT does not.
Voltages and modules
A microSD card is powered from 2.7 to 3.6 V and its lines cannot take more than 0.3 V above its supply: the 5 V of the UNO pins must be brought down. While writing it draws up to 100 mA (Transcend, default speed mode, the one used in SPI). Adafruit recommends a sturdy 3.3 V regulator and a chip-based level shifter, not resistor dividers: recent cards want clean, sharp edges. The Adafruit 254 module does exactly that (LP2985 regulator and 74HC4050 level shifter); the DFRobot DFR0229 uses resistor dividers instead and puts CS on pin 4. For outdoor use there are industrial microSD cards rated from −40 to 85 °C.
The wiring
| Module | Arduino UNO | ESP32-DevKitC |
|---|---|---|
| CLK (SCK) | 13 | GPIO 18 |
| DO (MISO) | 12 | GPIO 19 |
| DI (MOSI) | 11 | GPIO 23 |
| CS | 10 | GPIO 5 |
| 5V / GND | 5V / GND | 5V / GND |
On the UNO, even if you use another pin for CS, pin 10 must stay an output, otherwise the library does not work. On the ESP32 there is also the fast SD_MMC connection, but it uses pins 2 and 12, which affect boot (see guide no. 26): Espressif flags it as incompatible with the DevKitC without modifications. With an SPI module there are no problems.
The sketch
// Data logger on microSD: every 10 seconds it adds a line to the file MISURE.CSV with the time and the voltage read. // The file uses a semicolon and a decimal comma, as Excel expects with Italian settings. // Same sketch for Arduino UNO (CS on pin 10) and ESP32 (CS on GPIO 5). #include <SPI.h> #include <SD.h> #ifdef ARDUINO_ARCH_ESP32 const int PIN_CS = 5; const int PIN_INPUT = 34; const char *FILE_NAME = "/MISURE.CSV"; #define APPEND_MODE FILE_APPEND // on the ESP32 FILE_WRITE would erase the file #else const int PIN_CS = 10; const int PIN_INPUT = A0; const char *FILE_NAME = "MISURE.CSV"; // the UNO SD library wants 8.3 names #define APPEND_MODE FILE_WRITE // on the UNO FILE_WRITE writes at the end of the file #endif const unsigned long EVERY_MS = 10000; unsigned long last = 0; float readVolts() { #ifdef ARDUINO_ARCH_ESP32 return analogReadMilliVolts(PIN_INPUT) / 1000.0; #else return analogRead(PIN_INPUT) * 5.0 / 1023.0; #endif } void setup() { Serial.begin(115200); if (!SD.begin(PIN_CS)) { Serial.println("Card not found: check wires, CS and formatting (FAT32)"); while (true) delay(1000); } if (!SD.exists(FILE_NAME)) { // new file: the header line first File f = SD.open(FILE_NAME, APPEND_MODE); f.println("secondi;volt"); // column titles: seconds; volts f.close(); } Serial.println("Logging started"); } void loop() { if (millis() - last < EVERY_MS) return; last = millis(); String value = String(readVolts(), 3); value.replace('.', ','); // decimal comma for Excel with Italian settings File f = SD.open(FILE_NAME, APPEND_MODE); if (f) { f.print(millis() / 1000); f.print(';'); f.println(value); f.close(); // close() really saves the data on the card Serial.println(value); } else { Serial.println("Write error"); } }
Every 10 seconds the sketch opens the file, adds a line and closes it: if power fails you lose at most the last measurement. Compiled for the UNO it uses 941 bytes of RAM out of 2048 (the library always keeps a 512-byte block). The time comes from millis(), which rolls back to zero after about 50 days: for a real date and time add a DS3231 (guide no. 16) or, with the ESP32, the time from the Internet (guide no. 30).
CSV and Excel
The CSV format (RFC 4180) uses a comma between fields and a point for decimals. But Excel set to Italian, which uses the comma for decimals, expects a semicolon: an “international” CSV opened with a double click ends up all in one column. That is why the sketch writes 10;1,652. If the file goes to a program, a script or Excel with English settings, use the comma and the point. Otherwise, in Excel: Data › From Text/CSV and choose the delimiter.
Common mistakes
| What happens | Why | Fix |
|---|---|---|
| “Card not found” | wires, wrong CS, exFAT or unformatted card | check the wires, format FAT32 with SD Memory Card Formatter |
| On the ESP32 the file always has just one line | FILE_WRITE erases the file every time it is opened | FILE_APPEND |
| Empty file after unplugging the power | data left in memory | close() or flush() after every write |
| The file is not created | name longer than 8+3 characters or folder that does not exist | short name; create the folder first |
| Writing sometimes fails | weak power supply during the 100 mA peaks | suitable regulator, short wires |
| In Excel everything is in one column | delimiter different from the one Excel expects | semicolon, or Data › From Text/CSV |
| ESP32 does not start with the SD_MMC reader | pull-ups on pins 2 and 12 at boot | use the SPI connection |
Useful products
Other guides
- Resistor colour code and tolerances
- N-channel and P-channel MOSFETs
- Bipolar transistor (BJT) or MOSFET?
- Relays: how to drive them and how much current they draw
- THT and SMD/SMT components
- XIAO board pinouts
- LEDs: forward voltage and series resistor
- The multimeter: measuring voltage and current
- Wemos D1 mini: first steps
- MOSFET module with Arduino and ESP32
- Relay module with Arduino and ESP32
- 3D printing filaments: PLA, PETG and fibre-filled versions
- Analog and digital: the differences
- ADS1115: 16-bit converter with Arduino and ESP32
- From bits to real values: converting sensor readings
- DS3231 RTC clock with Arduino and ESP32
- Linear or switching regulator: which one to choose
- Step-down, step-up and buck-boost: choosing the right module
- Voltage divider: reading voltages higher than 5 V or 3.3 V
- Pull-up, pull-down and bounce: wiring a button properly
- 3.3 V and 5 V logic levels: getting an ESP32 and an Arduino to talk
- The I²C bus: addresses, pull-ups and the scanner
- Lithium batteries: voltages, charging and protection
- ESP32 power consumption and deep sleep: how long the battery lasts
- Temperature sensors compared
- ESP32: which pins to use and which to avoid
- Getting started with the ESP32 in Arduino IDE 2 and PlatformIO
- SSD1306 OLED display and 16×2 I²C LCD with Arduino and ESP32
- PIR motion sensor and HC-SR04 ultrasonic sensor
- Date and time from the Internet with the ESP32: NTP, Italian time zone and daylight saving time
- Solar-powered ESP32: panel, charger and the numbers for Italy
- Web server on the ESP32: control a relay from your phone
- Your first LED: wire it up and make it blink
- The button: let Arduino decide
- The potentiometer: turn a knob and read its value
- Soft light: adjusting the brightness of an LED
- The buzzer: playing notes and melodies
- The traffic light: three LEDs in sequence
- The thermometer: reading the temperature with the TMP36
- The servo motor: moving an arm with Arduino
- The night light: the photoresistor and your first decision
- The relay: switching on a light bulb with Arduino
- The LCD display: making Arduino write
- The electronic dice: your first complete project
- The RGB LED: every color from three lights
- The joystick: two-axis control with a shield
- The LED ring: twelve colors from a single pin
- The DC motor: driving it with a MOSFET
- Soil moisture: the plant that asks for water
- The stepper motor: turn exactly as far as you want
- The parking sensor: faster and faster beeps
- The 7-segment display: big, bright numbers
- Automatic watering: the plant that waters itself
- The keypad: a lock with a secret code
- Networked weather station: values and chart on your phone
- A Telegram bot on the ESP32: your home from your phone
- MQTT with the ESP32: the language of connected devices
- Updating the ESP32 over Wi-Fi (OTA)
- ESP-NOW: two ESP32 boards talking without a router
- WebSocket with the ESP32: the LED that follows the slider
- Readings on a Google sheet, with deep sleep
- WiFiManager: choose the Wi-Fi from your phone
- Bluetooth LE with the ESP32: the phone without a network
- The camera in your browser with the ESP32-S3
- A portable Bluetooth speaker you build yourself
- Bluetooth desktop speakers, 2 × 20 W
- Stereo MP3 player with two buttons
- The shelf that plays music: a Visaton exciter
- How to solder well
- How much does it draw? Current and power with the INA219
- Load-cell scale with the HX711
- CO2 traffic light: when to open the windows
- RFID card door opener
- GPS: track logger on microSD
- LoRa: how far does it go? A range test with two boards
- Battery weather sign with an e-paper display
- Web radio with an ESP32 and an I2S amplifier
- Getting started with the Raspberry Pi Pico 2 in MicroPython
- Your first amplifier: the LM386 and a speaker
- Talking Arduino: the DFR0760 speech synthesis module
- The spectrum of your music on an LED matrix
- Drawing with 64 LEDs: the 8×8 matrix with the MAX7219
- A real voltage: the 12-bit MCP4725 DAC
- The heartbeat on Arduino: an ECG with the AD8232