บทความ: ESP32 SD Card CSV Data Logging และการวิเคราะห์ข้อมูลด้วย Excel

เรียนรู้วิธีบันทึกข้อมูลเซ็นเซอร์ลง SD card ในรูปแบบ CSV และนำเข้าข้อมูลไปวิเคราะห์ด้วย Excel หรือ Google Sheets พร้อมตัวอย่างโค้ดและคำอธิบายภาษาไทย

📅 16 มีนาคม 2026⏱️ 15 นาที🎯 ระดับเริ่มต้น - กลาง

📖 บทนำ

การบันทึกข้อมูล (Data Logging) เป็นส่วนสำคัญของโปรเจกต์ IoT ไม่ว่าจะเป็นสถานีตรวจสอบสภาพอากาศ ระบบตรวจสอบอุณหภูมิ หรือการติดตามการใช้พลังงาน SD Card เป็นทางเลือกที่ยอดเยี่ยมสำหรับการบันทึกข้อมูลเนื่องจาก:

  • 💾 ความจุขนาดใหญ่ (GB ถึง TB)
  • 💵 ราคาถูก
  • 🔌 ถอดปลั๊กได้ง่าย
  • 💻 เข้ากันได้กับคอมพิวเตอร์ทุกเครื่อง
  • 📊 ข้อมูลสามารถนำไปใช้ใน Excel ได้ทันที

ในบทความนี้คุณจะได้เรียนรู้วิธีการบันทึกข้อมูลเซ็นเซอร์ลง SD Card ในรูปแบบ CSV (Comma-Separated Values) ซึ่งเป็นรูปแบบมาตรฐานที่ Excel และ Google Sheets รองรับ ทำให้คุณสามารถวิเคราะห์ข้อมูล สร้างกราฟ และสร้างรายงานได้อย่างง่ายดาย

🤔 CSV คืออะไร?

CSV (Comma-Separated Values) เป็นรูปแบบไฟล์ข้อความที่เก็บข้อมูลตาราง โดยแต่ละค่าจะคั่นด้วยจุลภาค (comma) แต่ละบรรทัดแทนหนึ่งแถวของข้อมูล

Timestamp,Temperature,Humidity
2026-03-16 14:00:00,28.5,65.2
2026-03-16 14:01:00,28.7,64.8
2026-03-16 14:02:00,28.6,65.0

ข้อดีของ CSV:

  • ✅ เปิดได้กับ Excel, Google Sheets, Numbers
  • ✅ ไฟล์มีขนาดเล็ก
  • ✅ แก้ไขได้ง่ายด้วย Text Editor
  • ✅ เข้ากันได้กับภาษาโปรแกรมทุกภาษา

🔧 อุปกรณ์ที่ต้องใช้

Hardware

  • ESP32 Development Board - ฿80-150
  • MicroSD Card Module - ฿20-40
  • MicroSD Card (4GB ขึ้นไป) - ฿50-150
  • DHT22 Temperature & Humidity Sensor - ฿40-60
  • Breadboard & Jumper Wires - ฿30-50

Software

  • Arduino IDE หรือ PlatformIO
  • Excel, Google Sheets หรือ Numbers
  • Library: SD, FS, DHT sensor library

💡 เคล็ดลับ: SD Card Module ส่วนใหญ่ใช้ SPI protocol ซึ่ง ESP32 รองรับในตัว ตรวจสอบให้แน่ใจว่า SD Card ได้รับการจัดรูปแบบ (format) เป็น FAT32 หรือ exFAT

🔌 การต่อสาย

SD Card Module ต่อกับ ESP32

SD Card ModuleESP32
CS (Chip Select)GPIO 5
SCK (Clock)GPIO 18
MOSI (Master Out Slave In)GPIO 23
MISO (Master In Slave Out)GPIO 19
VCC3.3V
GNDGND

DHT22 Sensor ต่อกับ ESP32

DHT22ESP32
VCC3.3V
DataGPIO 4
GNDGND

⚠️ ข้อควรระวัง: ต่อตัวต้านทาน 10kΩ ระหว่าง VCC และ Data pin ของ DHT22 เพื่อดึงสัญญาณขึ้น (pull-up resistor)

💻 บันทึกข้อมูลเซ็นเซอร์เดียว

นี่คือโค้ดพื้นฐานสำหรับบันทึกข้อมูลอุณหภูมิจาก DHT22 ลง SD Card ในรูปแบบ CSV:

/**
 * ESP32 SD Card CSV Data Logging - Single Sensor
 * บันทึกข้อมูลอุณหภูมิและความชื้นลง SD Card
 */

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

// กำหนดขา GPIO
#define SD_CS 5
#define DHTPIN 4
#define DHTTYPE DHT22

// สร้างออบเจกต์ DHT
DHT dht(DHTPIN, DHTTYPE);

// ชื่อไฟล์ CSV
const char* filename = "/sensor_data.csv";

// ช่วงเวลาในการบันทึก (มิลลิวินาที)
const unsigned long LOG_INTERVAL = 60000; // 1 นาที

unsigned long lastLogTime = 0;

void setup() {
  Serial.begin(115200);
  
  // เริ่มต้นใช้งาน DHT
  dht.begin();
  
  // เริ่มต้นใช้งาน SD Card
  Serial.println("กำลังเริ่มต้น SD Card...");
  if (!SD.begin(SD_CS)) {
    Serial.println("ไม่สามารถเริ่มต้น SD Card ได้!");
    Serial.println("ตรวจสอบการต่อสายและ SD Card");
    while (1) {
      delay(1000);
    }
  }
  Serial.println("SD Card เริ่มต้นสำเร็จ!");
  
  // ตรวจสอบว่ามีไฟล์อยู่แล้วหรือไม่
  if (!SD.exists(filename)) {
    // สร้างไฟล์ใหม่และเขียนหัวตาราง
    File file = SD.open(filename, FILE_WRITE);
    if (file) {
      file.println("Timestamp,Temperature,Humidity");
      file.close();
      Serial.println("สร้างไฟล์ CSV ใหม่และเขียนหัวตารางแล้ว");
    } else {
      Serial.println("ไม่สามารถสร้างไฟล์ได้!");
    }
  } else {
    Serial.println("ไฟล์ CSV มีอยู่แล้ว กำลังเพิ่มข้อมูล...");
  }
  
  Serial.println("เริ่มต้นการบันทึกข้อมูล...");
  Serial.println("Timestamp,Temperature,Humidity");
}

void loop() {
  // ตรวจสอบเวลาที่จะบันทึกข้อมูล
  unsigned long currentTime = millis();
  
  if (currentTime - lastLogTime >= LOG_INTERVAL) {
    lastLogTime = currentTime;
    
    // อ่านค่าจาก DHT22
    float temperature = dht.readTemperature();
    float humidity = dht.readHumidity();
    
    // ตรวจสอบว่าอ่านค่าสำเร็จหรือไม่
    if (isnan(temperature) || isnan(humidity)) {
      Serial.println("ไม่สามารถอ่านค่าจาก DHT22 ได้!");
      return;
    }
    
    // สร้าง timestamp
    String timestamp = getTimestamp();
    
    // สร้างข้อมูล CSV
    String csvData = timestamp + "," + 
                     String(temperature, 1) + "," + 
                     String(humidity, 1);
    
    // เขียนข้อมูลลง SD Card
    File file = SD.open(filename, FILE_APPEND);
    if (file) {
      file.println(csvData);
      file.close();
      Serial.print("บันทึกข้อมูล: ");
      Serial.println(csvData);
    } else {
      Serial.println("ไม่สามารถเปิดไฟล์เพื่อเขียนข้อมูลได้!");
    }
  }
}

// ฟังก์ชันสร้าง timestamp
String getTimestamp() {
  // หมายเหตุ: ESP32 มี RTC ภายใน แต่ต้องตั้งค่าเวลาครั้งแรก
  // ในตัวอย่างนี้ใช้ millis() แทน
  unsigned long seconds = millis() / 1000;
  unsigned long minutes = seconds / 60;
  unsigned long hours = minutes / 60;
  unsigned long days = hours / 24;
  
  return String(days) + "d " + 
         String(hours % 24) + "h " + 
         String(minutes % 60) + "m " + 
         String(seconds % 60) + "s";
}

ผลลัพธ์: ข้อมูลจะถูกบันทึกในไฟล์ sensor_data.csv ทุกๆ 1 นาที ไฟล์สามารถนำไปเปิดใน Excel ได้ทันที

📊 บันทึกข้อมูลหลายเซ็นเซอร์

สำหรับโปรเจกต์ที่ซับซ้อนขึ้น เราสามารถบันทึกข้อมูลจากหลายเซ็นเซอร์พร้อมกันได้:

/**
 * ESP32 SD Card CSV Data Logging - Multiple Sensors
 * บันทึกข้อมูลหลายเซ็นเซอร์พร้อมกัน
 */

#include <FS.h>
#include <SD.h>
#include <SPI.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_BMP280.h>

// กำหนดขา GPIO
#define SD_CS 5
#define DHTPIN 4
#define DHTTYPE DHT22
#define LDR_PIN 34

// สร้างออบเจกต์เซ็นเซอร์
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP280 bmp;

// ชื่อไฟล์ CSV
const char* filename = "/multi_sensor_data.csv";

const unsigned long LOG_INTERVAL = 30000; // 30 วินาที
unsigned long lastLogTime = 0;

void setup() {
  Serial.begin(115200);
  
  // เริ่มต้นใช้งานเซ็นเซอร์
  dht.begin();
  
  // เริ่มต้นใช้งาน BMP280 (Pressure Sensor)
  if (!bmp.begin(0x76)) {
    Serial.println("ไม่พบ BMP280!");
  }
  
  // ตั้งค่า LDR pin
  pinMode(LDR_PIN, INPUT);
  
  // เริ่มต้นใช้งาน SD Card
  if (!SD.begin(SD_CS)) {
    Serial.println("ไม่สามารถเริ่มต้น SD Card ได้!");
    while (1) delay(1000);
  }
  
  // สร้างไฟล์ใหม่พร้อมหัวตาราง
  if (!SD.exists(filename)) {
    File file = SD.open(filename, FILE_WRITE);
    if (file) {
      // หัวตาราง CSV
      file.println("Timestamp,Temperature,DHT_Humidity,BMP_Pressure,BMP_Altitude,Light_Level");
      file.close();
      Serial.println("สร้างไฟล์ CSV ใหม่แล้ว");
    }
  }
  
  Serial.println("เริ่มต้นการบันทึกข้อมูลหลายเซ็นเซอร์...");
}

void loop() {
  unsigned long currentTime = millis();
  
  if (currentTime - lastLogTime >= LOG_INTERVAL) {
    lastLogTime = currentTime;
    
    // อ่านค่าจาก DHT22
    float tempDHT = dht.readTemperature();
    float humidity = dht.readHumidity();
    
    // อ่านค่าจาก BMP280
    float pressure = bmp.readPressure() / 100.0F; // hPa
    float altitude = bmp.readAltitude(1013.25); // มิลลิเมตร
    
    // อ่านค่าจาก LDR (Light Sensor)
    int lightLevel = analogRead(LDR_PIN);
    
    // ตรวจสอบความถูกต้องของข้อมูล
    if (isnan(tempDHT) || isnan(humidity)) {
      Serial.println("ข้อผิดพลาดในการอ่านค่าจาก DHT22!");
      return;
    }
    
    // สร้างข้อมูล CSV
    String csvData = getTimestamp() + "," +
                     String(tempDHT, 1) + "," +
                     String(humidity, 1) + "," +
                     String(pressure, 1) + "," +
                     String(altitude, 1) + "," +
                     String(lightLevel);
    
    // เขียนข้อมูลลง SD Card
    File file = SD.open(filename, FILE_APPEND);
    if (file) {
      file.println(csvData);
      file.close();
      Serial.print("บันทึกข้อมูล: ");
      Serial.println(csvData);
    }
  }
}

String getTimestamp() {
  unsigned long seconds = millis() / 1000;
  return String(seconds) + "s";
}

💡 เคล็ดลับ: คุณสามารถเพิ่มเซ็นเซอร์เพิ่มเติมได้ เช่น MQ Gas Sensor, Soil Moisture Sensor, หรือ Current Sensor โดยเพิ่มคอลัมน์ใน CSV

📂 อ่านข้อมูลใน Excel

วิธีที่ 1: เปิดไฟล์โดยตรง

  1. ถอด SD Card จาก ESP32
  2. ใส่ SD Card ลงในคอมพิวเตอร์ (ใช้ Card Reader)
  3. เปิด Windows Explorer หรือ Finder
  4. ดับเบิลคลิกไฟล์ sensor_data.csv
  5. Excel จะเปิดไฟล์โดยอัตโนมัติ

วิธีที่ 2: นำเข้าข้อมูล (Import)

  1. เปิด Excel และสร้าง Workbook ใหม่
  2. ไปที่ DataFrom Text/CSV
  3. เลือกไฟล์ CSV จาก SD Card
  4. Excel จะแสดงตัวอย่างข้อมูล ให้ตรวจสอบ
  5. คลิก Load เพื่อนำเข้าข้อมูล

Google Sheets

  1. ไปที่ Google Sheets
  2. คลิก FileImport
  3. ลากไฟล์ CSV มาวาง หรือคลิก Browse
  4. เลือก Replace spreadsheet หรือ Insert new sheet
  5. คลิก Import data

📈 การวิเคราะห์ข้อมูล

สร้างกราฟ (Charts)

  1. เลือกข้อมูลทั้งหมด (รวมหัวตาราง)
  2. ไปที่ InsertChart
  3. เลือกประเภทกราฟ:
    • Line Chart: เหมาะกับการดูแนวโน้มตามเวลา
    • Scatter Plot: เหมาะกับการดูความสัมพันธ์ระหว่างตัวแปร
    • Bar Chart: เหมาะกับการเปรียบเทียบ

ฟังก์ชัน Excel ที่มีประโยชน์

ฟังก์ชันคำอธิบายตัวอย่าง
=AVERAGE(B2:B1000)ค่าเฉลี่ยอุณหภูมิเฉลี่ย
=MAX(B2:B1000)ค่าสูงสุดอุณหภูมิสูงสุด
=MIN(B2:B1000)ค่าต่ำสุดอุณหภูมิต่ำสุด
=STDEV(B2:B1000)ส่วนเบี่ยงเบนมาตรฐานความผันผวน
=CORREL(B2:B1000, C2:C1000)สหสัมพันธ์ความสัมพันธ์ระหว่างอุณหภูมิและความชื้น

ตัวอย่างการวิเคราะห์

💡 ตัวอย่าง: หากคุณมีข้อมูลอุณหภูมิและความชื้น คุณสามารถวิเคราะห์ได้ว่า:
- อุณหภูมิเฉลี่ยต่อวันคือเท่าไร
- ช่วงเวลาไหนที่อุณหภูมิสูงสุด
- อุณหภูมิและความชื้นมีความสัมพันธ์กันหรือไม่

🏠 โปรเจกต์ตัวอย่าง: สถานีตรวจสอบสภาพอากาศ

นี่คือโปรเจกต์สมบูรณ์ที่รวมทุกอย่างเข้าด้วยกัน:

ฟีเจอร์

  • บันทึกข้อมูลทุก 5 นาที
  • บันทึกข้อมูล 6 พารามิเตอร์: อุณหภูมิ, ความชื้น, ความดัน, ความสูง, แสง, ดัชนี UV
  • สร้างไฟล์ใหม่ทุกวัน (เพื่อป้องกันไฟล์ใหญ่เกินไป)
  • แสดงสถานะบน Serial Monitor
  • ตรวจสอบพื้นที่ว่าง SD Card
/**
 * ESP32 Weather Station with SD Card Logging
 * สถานีตรวจสอบสภาพอากาศพร้อมบันทึกข้อมูล SD Card
 */

#include <FS.h>
#include <SD.h>
#include <SPI.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_BMP280.h>
#include <WiFi.h>

// กำหนดขา GPIO
#define SD_CS 5
#define DHTPIN 4
#define DHTTYPE DHT22
#define LDR_PIN 34
#define UV_PIN 35

DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP280 bmp;

const unsigned long LOG_INTERVAL = 300000; // 5 นาที
unsigned long lastLogTime = 0;

String getCurrentFilename() {
  // สร้างชื่อไฟล์ตามวันที่: data_YYYYMMDD.csv
  time_t now;
  struct tm timeinfo;
  
  // ใช้ NTP หรือ RTC ในการรับเวลาจริง
  // ในตัวอย่างนี้ใช้เวลาจาก millis()
  unsigned long days = millis() / (1000 * 60 * 60 * 24);
  
  return "/data_day" + String(days) + ".csv";
}

void createNewFile(String filename) {
  File file = SD.open(filename, FILE_WRITE);
  if (file) {
    file.println("Timestamp,Temperature,Humidity,Pressure,Altitude,Light,UV_Index");
    file.close();
    Serial.println("สร้างไฟล์ใหม่: " + filename);
  }
}

void checkSDCardSpace() {
  unsigned long totalBytes = SD.totalBytes();
  unsigned long usedBytes = SD.usedBytes();
  float usedPercent = (usedBytes * 100.0) / totalBytes;
  
  Serial.print("พื้นที่ใช้: ");
  Serial.print(usedPercent);
  Serial.println("%");
  
  if (usedPercent > 90) {
    Serial.println("⚠️ แจ้งเตือน: SD Card เกือบเต็ม!");
  }
}

void setup() {
  Serial.begin(115200);
  
  dht.begin();
  
  if (!bmp.begin(0x76)) {
    Serial.println("ไม่พบ BMP280!");
  }
  
  pinMode(LDR_PIN, INPUT);
  pinMode(UV_PIN, INPUT);
  
  if (!SD.begin(SD_CS)) {
    Serial.println("ไม่สามารถเริ่มต้น SD Card ได้!");
    while (1) delay(1000);
  }
  
  Serial.println("สถานีตรวจสอบสภาพอากาศเริ่มทำงาน!");
  Serial.println("บันทึกข้อมูลทุก 5 นาที");
  Serial.println("--------------------------------");
}

void loop() {
  unsigned long currentTime = millis();
  
  if (currentTime - lastLogTime >= LOG_INTERVAL) {
    lastLogTime = currentTime;
    
    // อ่านค่าจากเซ็นเซอร์ทั้งหมด
    float temp = dht.readTemperature();
    float humidity = dht.readHumidity();
    float pressure = bmp.readPressure() / 100.0F;
    float altitude = bmp.readAltitude(1013.25);
    int light = analogRead(LDR_PIN);
    int uv = analogRead(UV_PIN);
    
    if (isnan(temp) || isnan(humidity)) {
      Serial.println("ข้อผิดพลาดในการอ่านค่าจาก DHT22!");
      return;
    }
    
    // สร้างชื่อไฟล์และตรวจสอบว่ามีไฟล์อยู่หรือไม่
    String filename = getCurrentFilename();
    if (!SD.exists(filename)) {
      createNewFile(filename);
    }
    
    // สร้างข้อมูล CSV
    String csvData = getTimestamp() + "," +
                     String(temp, 1) + "," +
                     String(humidity, 1) + "," +
                     String(pressure, 1) + "," +
                     String(altitude, 1) + "," +
                     String(light) + "," +
                     String(uv);
    
    // เขียนข้อมูลลง SD Card
    File file = SD.open(filename, FILE_APPEND);
    if (file) {
      file.println(csvData);
      file.close();
      
      // แสดงผลบน Serial Monitor
      Serial.println("บันทึกข้อมูลสำเร็จ!");
      Serial.print("อุณหภูมิ: ");
      Serial.print(temp);
      Serial.println("°C");
      Serial.print("ความชื้น: ");
      Serial.print(humidity);
      Serial.println("%");
      Serial.print("ความดัน: ");
      Serial.print(pressure);
      Serial.println(" hPa");
      Serial.println("--------------------------------");
      
      // ตรวจสอบพื้นที่ว่าง SD Card ทุกๆ 1 ชั่วโมง
      static unsigned long lastCheck = 0;
      if (currentTime - lastCheck > 3600000) {
        checkSDCardSpace();
        lastCheck = currentTime;
      }
    }
  }
}

String getTimestamp() {
  unsigned long seconds = millis() / 1000;
  unsigned long minutes = seconds / 60;
  unsigned long hours = minutes / 60;
  
  return String(hours % 24) + ":" + 
         String(minutes % 60) + ":" + 
         String(seconds % 60);
}

การวิเคราะห์ข้อมูล

เมื่อคุณมีข้อมูลหลายวัน คุณสามารถ:

  • เปรียบเทียบสภาพอากาศระหว่างวัน
  • ดูแนวโน้มระยะยาว
  • หาช่วงเวลาที่ร้อน/เย็นที่สุด
  • วิเคราะห์ความสัมพันธ์ระหว่างพารามิเตอร์ต่างๆ

🔧 ปัญหาที่พบบ่อยและวิธีแก้ไข

ปัญหา: SD Card initialization failed

อาการ: ESP32 แจ้งว่าไม่สามารถเริ่มต้น SD Card ได้

สาเหตุ: การต่อสายไม่ถูกต้อง, SD Card เสีย, หรือรูปแบบไฟล์ไม่รองรับ

วิธีแก้ไข:

  • ตรวจสอบการต่อสาย (CS, SCK, MOSI, MISO, VCC, GND)
  • ลองเปลี่ยน SD Card อื่น
  • จัดรูปแบบ (format) SD Card เป็น FAT32
  • ลองเปลี่ยนค่าความต้านทาน pull-up (ถ้ามี)

ปัญหา: ไม่สามารถเขียนข้อมูลลงไฟล์ได้

อาการ: ไฟล์เปิดได้แต่ไม่สามารถเขียนข้อมูลได้

สาเหตุ: SD Card เต็ม, ไฟล์เสีย, หรือ SD Card ถูกป้องกันไม่ให้เขียน (write-protected)

วิธีแก้ไข:

  • ตรวจสอบพื้นที่ว่าง SD Card
  • ตรวจสอบสวิตช์ lock บน SD Card
  • ลบไฟล์เก่าๆ หรือใช้ SD Card ขนาดใหญ่ขึ้น
  • ลองจัดรูปแบบ SD Card ใหม่

ปัญหา: ข้อมูลใน Excel ไม่เรียงอย่างถูกต้อง

อาการ: ข้อมูลทั้งหมดอยู่ในคอลัมน์เดียว

สาเหตุ: Excel ไม่รู้จักตัวคั่น (delimiter) หรือรูปแบบไฟล์

วิธีแก้ไข:

  • ใช้ Data → From Text/CSV และเลือก delimiter เป็น Comma
  • ตรวจสอบว่าข้อมูลมี comma เพียงพรรษ์และถูกต้อง
  • ตรวจสอบว่าไม่มีอักขระพิเศษในข้อมูล

ปัญหา: Timestamp ไม่ถูกต้อง

อาการ: เวลาที่แสดงไม่ตรงกับเวลาจริง

สาเหตุ: ESP32 ไม่ได้รับเวลาจาก NTP หรือ RTC

วิธีแก้ไข:

  • ใช้ NTP (Network Time Protocol) ในการรับเวลาจากอินเทอร์เน็ต
  • ใช้ RTC (Real-Time Clock) module ภายใน/ภายนอก
  • ตั้งค่าเวลาด้วยตนเองในโค้ด

🎉 สรุป

ในบทความนี้คุณได้เรียนรู้:

  • วิธีการต่อ SD Card Module กับ ESP32
  • การบันทึกข้อมูลเซ็นเซอร์ในรูปแบบ CSV
  • การบันทึกข้อมูลหลายเซ็นเซอร์พร้อมกัน
  • การนำเข้าและวิเคราะห์ข้อมูลใน Excel หรือ Google Sheets
  • การสร้างกราฟและรายงานจากข้อมูล
  • การแก้ปัญหาที่พบบ่อย

ตอนนี้คุณสามารถสร้างระบบบันทึกข้อมูลสำหรับโปรเจกต์ IoT ของคุณเองได้แล้ว!

🚀 บทความที่เกี่ยวข้อง