บทความ: 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. ไปที่ Data → From Text/CSV
  3. เลือกไฟล์ CSV จาก SD Card
  4. Excel จะแสดงตัวอย่างข้อมูล ให้ตรวจสอบ
  5. คลิก Load เพื่อนำเข้าข้อมูล

Google Sheets

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

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

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

  1. เลือกข้อมูลทั้งหมด (รวมหัวตาราง)
  2. ไปที่ Insert → Chart
  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 ของคุณเองได้แล้ว!

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