เก็บข้อมูล เรื่องการบันทึกค่าอุณหภูมิ ตามเวลาผ่าน SD Card+ESP8266

สำหรับในโพสต์นี้ผมศึกษาเกี่ยวกับเรื่องของการเก็บข้อมูลบันทึกเข้าไปใน SD Card module โดยได้ประยุกต์โค้ดต่างๆที่ได้ศึกษามาให้ได้ตามความต้องการดังนี้

  1. ชื่อไฟล์ .txt เราสามารถตั้งชื่อไว้ใน SD Card ก่อนหรือไม่ต้องสร้างเลยก็ได้เพราะ เพราะระบบจะสร้างชื่อไฟล์และนามสกุลตามโค้ดที่เรากำหนดลงไป
  2. ช่วงที่ esp 8266 เริ่มทำงาน ถ้าไม่ได้ใส่ SD Card เข้าไป ตั้งแต่แรก ระบบจะไม่สามารถเขียนหรืออ่านข้อมูลจาก SD Card ได้ หลังจากใส่ SD Card เข้าไปแล้วให้กดปุ่ม Reset esp 8266 1 ครั้ง ระบบก็จะทำงานปกติ
  3. ในขณะที่ระบบทำงานปกติหากเราต้องการที่จะนำ SD Card ออกมาเพื่อที่จะนำไปดูข้อมูลในเครื่องคอมพิวเตอร์ ระบบจะทำการหยุดอ่านและเขียนข้อมูลใน SD Card ทันที
  4. หลังจากที่เราดูข้อมูลจาก SD Card ด้วยคอมพิวเตอร์เสร็จเรียบร้อยแล้ว ถ้าเราลบไฟล์นั้นออก เมื่อเสียบกลับเข้าไปใน SD Card module ระบบก็จะทำการ สร้างชื่อไฟล์และนามสกุลตามที่กำหนดลงในโค้ดใหม่และทำการเขียนข้อมูลลงไปใหม่ได้ หรือถ้าเราไม่ลบไฟล์นั้น ระบบจะทำการเขียนค่าต่อจากของเดิมอย่างต่อเนื่อง โดยไม่ต้องมากด Reset esp 8266 ทุกครั้ง
  5. ระบบตอนนี้ยังไม่ได้เชื่อมต่อ wi-fi Internet สาเหตุที่ใช้ esp 8266 ผมจะเผื่อเอาไว้สำหรับการเชื่อมต่อ WiFi Internet ไว้ก่อนเท่านั้นเอง
  6. Code ที่ใช้อยู่สามารถดูตัวอย่างได้จาก Library SD ของ esp 8266 ได้ ประกอบกับศึกษาจากเว็บไซต์ต่างๆซึ่งมีสิ่งที่เราต้องการอยู่แล้ว โปรเจคนี้เลยไม่มีอะไรที่หวือหวา เพียงแต่นำมาประยุกต์ให้ได้ตามสิ่งที่เราต้องการเท่านั้นเองครับ
#include <SPI.h>
#include <SD.h>
File myFile; // สร้างออฟเจก File สำหรับจัดการข้อมูล
const int chipSelect = D4;


//RTC Library
#include "Arduino.h"
#include "Wire.h"
#include "uRTCLib.h"
// uRTCLib rtc;
uRTCLib rtc(0x68);





int year_;


#include <DHT.h>
#define DHTTYPE DHT21
#define DHTPIN  D3
DHT dht(DHTPIN, DHTTYPE);


int faild = 0;
int done = 0;



Sd2Card card;

void setup()
{
  Serial.begin(115200);

  dht.begin();

#ifdef ARDUINO_ARCH_ESP8266
  Wire.begin(4, 5); // GPIO4 = D2 and GPIO5 = D1 on ESP8266
#else
  Wire.begin();
#endif

  //rtc.set(0, 17, 15, 3, 5, 3, 20);//ใช้เฉพาะตั้งเวลา ถ้าจะตั้งก็ เอา // ออก เมื่อตั้งได้ตรงแล้วก็เอา // ใส่กลับไปเหมือนเดิม
  //  RTCLib::set(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year)



  Serial.println();
  Serial.println("Initializing SD card...");
  delay(300);
  pinMode(SS, OUTPUT);//หรือขา CS จะกำหนดเป็นขาใดก็ได้ ในที่นี้กำหนดเป็นขา D4


  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");// ถ้าเริ่มทำงาน ถ้าไม่เสียบ SD Card ได้ แสดงข้อความ initialization failed
    return;
  }


  Serial.println("initialization done."); // ถ้าเริ่มทำงาน SD Card ได้ แสดงข้อความ initialization done

  // ปักหมุดชื่อว่า createNew ไว้หากสร้างไฟล์ไม่เสร็จ จะให้กลับมาที่จุดนี้ใหม่
createNew:

  // เปิดไฟล์ ชื่อ test.txt ขึ้นมา เราจะสามารถเปิดได้ครั้งละ 1 ไฟล์เท่านั้น
  // หากต้องการใช้งานหลายไฟล์ ทำได้โดยการปิดไฟล์หนึ่งไปก่อน แล้วเปิดอีกไฟล์ขึ้นมาทำงาน
  // หากไม่มีไฟล์ที่ชื่อตามต้องการ จะเป็นการสร้างไฟล์ขึ้นมาใหม่
  myFile = SD.open("PM_check.txt", FILE_WRITE);
  // ปิดไฟล์ลงไปก่อน
  myFile.close();

  // ลองตรวจสอบดูว่ามีไฟล์อยู่หรือไม่ ถ้ามี Serial monitor บอกว่ามีไฟล์อยู่ ถ้าไม่มีให้แสดงว่าไม่มี
  // เราเพิ่งสร้างไฟล์ใหม่ขึ้นมา ปกติต้องมีไฟล์ แต่หากไม่มีก็เขียนดค้ด goto กลับไฟสร้างไฟล์ใหม่อีกครั้ง
  if (SD.exists("PM_check.txt")) {
    Serial.println("File exists.");
  } else {
    Serial.println("File doesn't exists.");
    goto createNew;
  }

  delay(3000);

  // ปักหมุดชื่อ newWrite ไว้กรณีเขียนไฟล์ไม่สำเร็จ ให้กลับมาจุดนี้ใหม่
newWrite:

  // ทำการเปิดไฟล์อีกครั้งแล้วทำการเขียนข้อความว่า testing SD Card..... ลงไปในไฟล์
  myFile = SD.open("PM_check.txt", FILE_WRITE);
  if (myFile) {
    Serial.print("Writing to PM_check.txt...");
    //myFile.println("รายงานการเก็บข้อมูล.....");
    // ปิดไฟล์แล้วแสดงผล done
    myFile.close();
    Serial.println("done.");
  } else {
    // หากเปิดไฟล์ขึ้นมาไม่สำเร็จ แสดง error แล้วกลับไปที่ newWrite เพื่อลองทำใหม่
    Serial.println("error opening file");
    goto newWrite;
  }

  delay(3000);


}//void setup





void loop()
{

  float h = dht.readHumidity();
  float t = dht.readTemperature();



  rtc.refresh();
  year_ = rtc.year() + 2543; //+43 เพื่อให้ได้ปี พ.ศ. 63

if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    //Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card inserted?");
    //Serial.println("* is your wiring correct?");
    //Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;
  } else {

  myFile = SD.open("PM_check.txt", FILE_WRITE);
  // ถ้าเปิดไฟล์สำเร็จ ให้เขียนข้อมูลเพิ่มลงไป
  if (myFile) {
    Serial.println("Writing to PM_check.txt...");
    myFile.print(" Date: ");
    myFile.print("\t");     // \t = เว้น 1 tab มีผลตอนวางลงใน Excel

    if (rtc.day() < 10)
    {
      myFile.print("0");
      myFile.print(rtc.day());
    }
    else myFile.print(rtc.day());
    myFile.print('-');


    if (rtc.month() < 10)
    {
      myFile.print("0");
      myFile.print(rtc.month());
    }
    else myFile.print(rtc.month());
    myFile.print('-');

    myFile.print(year_);
    myFile.print("\t");     // \t = เว้น 1 tab มีผลตอนวางลงใน Excel

    myFile.print(" Time: ");
    myFile.print("\t");     // \t = เว้น 1 tab มีผลตอนวางลงใน Excel
    if (rtc.hour() < 10)
    {
      myFile.print("0");
      myFile.print(rtc.hour());
    }
    else myFile.print(rtc.hour());

    myFile.print(':');



    if (rtc.minute() < 10)
    {
      myFile.print("0");
      myFile.print(rtc.minute());
    }
    else myFile.print(rtc.minute());

    myFile.print(':');



    if (rtc.second() < 10)
    {
      myFile.print("0");
      myFile.print(rtc.second());
    }
    else myFile.print(rtc.second());


    myFile.print("\t");     // \t = เว้น 1 tab มีผลตอนวางลงใน Excel
    myFile.print(" = ");
    myFile.print("\t");     // \t = เว้น 1 tab มีผลตอนวางลงใน Excel

    // บันทึกที่ต้องการ

    myFile.print("Temp.= ");
    myFile.print(t, 2);
    myFile.print(" °C");
    myFile.print("\t");       // \t = เว้น 1 tab
    myFile.print("Humid.= ");
    myFile.print(h, 2);
    myFile.println(" %");

    // ปิดไฟล์
    myFile.close();
    Serial.println("done.");
    //Serial.println();

  }

  }

 // หน่วงเวลา 2  วินาที
  delay(2000);
}//void loop










1 Likes

ต่อไป จะแก้ไขข้อที่ 1 ให้สามารถเขียนข้อมูลได้เลยเมื่อระบบเริ่มทำงานแต่ลืมเสียบ SD card เข้าไป แต่หลังจากเสียบแล้ว ก็ เริ่มทำการเขียนข้อมูลต่อได้เลย
(1. ช่วงที่ esp 8266 เริ่มทำงาน ถ้าไม่ได้ใส่ SD Card เข้าไป ตั้งแต่แรก ระบบจะไม่สามารถเขียนหรืออ่านข้อมูลจาก SD Card ได้ หลังจากใส่ SD Card เข้าไปแล้วให้กดปุ่ม Reset esp 8266 1 ครั้ง ระบบก็จะทำงานปกติ)

เอา Code ส่วนนี้ ไปแทนที่ ในส่วนของ void setup{ }

void setup()
{
  Serial.begin(115200);

  dht.begin();

#ifdef ARDUINO_ARCH_ESP8266
  Wire.begin(4, 5); // GPIO4 = D2 and GPIO5 = D1 on ESP8266
#else
  Wire.begin();
#endif

  //rtc.set(0, 17, 15, 3, 5, 3, 20);//ใช้เฉพาะตั้งเวลา ถ้าจะตั้งก็ เอา // ออก เมื่อตั้งได้ตรงแล้วก็เอา // ใส่กลับไปเหมือนเดิม
  //  RTCLib::set(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year)



  Serial.println();
  Serial.println("Initializing SD card...");
  delay(300);
  pinMode(SS, OUTPUT);//หรือขา CS จะกำหนดเป็นขาใดก็ได้ ในที่นี้กำหนดเป็นขา D4
  
insert_card://กรณีเริ่มระบบใหม่ แต่ SD card ยังไม่ได้เสียบ
if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    //Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card inserted?");
    //Serial.println("* is your wiring correct?");
    //Serial.println("* did you change the chipSelect pin to match your shield or module?");
    //return;
    goto insert_card;
  } else {

  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");// ถ้าเริ่มทำงาน ถ้าไม่เสียบ SD Card ได้ แสดงข้อความ initialization failed
    return;
    
  }


  Serial.println("initialization done."); // ถ้าเริ่มทำงาน SD Card ได้ แสดงข้อความ initialization done

  // ปักหมุดชื่อว่า createNew ไว้หากสร้างไฟล์ไม่เสร็จ จะให้กลับมาที่จุดนี้ใหม่
createNew:

  // เปิดไฟล์ ชื่อ test.txt ขึ้นมา เราจะสามารถเปิดได้ครั้งละ 1 ไฟล์เท่านั้น
  // หากต้องการใช้งานหลายไฟล์ ทำได้โดยการปิดไฟล์หนึ่งไปก่อน แล้วเปิดอีกไฟล์ขึ้นมาทำงาน
  // หากไม่มีไฟล์ที่ชื่อตามต้องการ จะเป็นการสร้างไฟล์ขึ้นมาใหม่
  myFile = SD.open("PM_check.txt", FILE_WRITE);
  // ปิดไฟล์ลงไปก่อน
  myFile.close();

  // ลองตรวจสอบดูว่ามีไฟล์อยู่หรือไม่ ถ้ามี Serial monitor บอกว่ามีไฟล์อยู่ ถ้าไม่มีให้แสดงว่าไม่มี
  // เราเพิ่งสร้างไฟล์ใหม่ขึ้นมา ปกติต้องมีไฟล์ แต่หากไม่มีก็เขียนดค้ด goto กลับไฟสร้างไฟล์ใหม่อีกครั้ง
  if (SD.exists("PM_check.txt")) {
    Serial.println("File exists.");
  } else {
    Serial.println("File doesn't exists.");
    goto createNew;
  }

  delay(3000);

  // ปักหมุดชื่อ newWrite ไว้กรณีเขียนไฟล์ไม่สำเร็จ ให้กลับมาจุดนี้ใหม่
newWrite:

  // ทำการเปิดไฟล์อีกครั้งแล้วทำการเขียนข้อความว่า testing SD Card..... ลงไปในไฟล์
  myFile = SD.open("PM_check.txt", FILE_WRITE);
  if (myFile) {
    Serial.print("Writing to PM_check.txt...");
    //myFile.println("รายงานการเก็บข้อมูล.....");
    // ปิดไฟล์แล้วแสดงผล done
    myFile.close();
    Serial.println("done.");
  } else {
    // หากเปิดไฟล์ขึ้นมาไม่สำเร็จ แสดง error แล้วกลับไปที่ newWrite เพื่อลองทำใหม่
    Serial.println("error opening file");
    goto newWrite;
  }

  delay(3000);
  }
2 Likes

แล้วถ้าผมไม่มี RTC จะต้องแก้โค้ดตรงไหนบ้างครับ
ขอบคุณครับ

ง่ายๆ ครับเปิด basic code RTC ขึ้นมาเทียบแล้วก็ลบออกไปจบ