2016/Sep/18

Workshop 4 . NodeMCU/ESP8266 + DHT11+16x2 LCD Display I2C+NTP

วัตถุประสงค์

เพื่อให้สามารถทำการเขียนชุดคำสั่งให้ NodeMCU สามารถทำการเชื่อมต่อกับ Internet ผ่าน WIFI และให้ไปรับค่าวันที่/เวลา จาก NTP:Network Time Protocols ซึ่งเป็น Protocol ที่ใช้สำหรับปรับเทียบเวลา ( Time Synchronization) ของ Computer โดยอาศัยเครือข่าย Internet เป็นสื่อกลางในการส่งข้อมูลเวลามาตรฐานไปยังเครื่องลูกข่าย โดยมีเครื่องแม่ข่าย ( NTP Server) เป็นตัวให้บริการส่งเวลามาตรฐาน เพื่อใช้ในการปรับเทียบเวลาให้ตรงกลับเวลามาตรฐาน ( Time Standard) ซึ่งเป็นค่าเวลาที่ทาง Time & Frequency Lab. ได้ทำการเก็บรักษาไว้โดยวิธีการเปรียบเทียบกับเวลามาตรฐานของประเทศอื่นๆ ซึ่งเป็นที่ยอมรับในระดับนานาชาติ โดยมีความถูกต้องอยู่ที่ ประมาณ 1 millisecond ในระบบ LAN และประมาณ 10 millisecond ในระบบ WAN นับว่าเป็นความคลาดเคลื่อนที่อยู่ในระดับต่ำ อีกทั้งยังง่ายต่อการเข้าถึงของผู้ใช้ทั่วไป แค่เพียงมี PC หรืออุปกรณ์ที่สามารถเชื่อมต่อ เข้าระบบ Internet ได้ผู้ใช้ก็สามารถที่จะ Synchronize เวลามาตรฐานผ่านระบบ NTP ได้ทันที

เมื่อได้ค่าเวลาจาก NTP มาแล้วเราก็จะนำค่า วันที่ เวลา อุณหภูมิ (Temperature) และ ความชื้น (Humidity) จาก DHT11 Sensor DHT11 sensor มาแสดงผลทางหน้าจอ 16x2 LCD Display I2C พร้อมๆ กัน

เครื่องมือที่ใช้

  1. NodeMCU/ESP8266 พร้อม สาย USB สำหรับ Upload ไฟล์
  2. ชุดโปรแกรม Arduino studio (ดาวน์โหลดได้จาก https://www.arduino.cc/en/Main/Software)
  3. DHT11 sensor (Digital Humidity and Temperature Sensor)
  4. ESP8266 – 16x2 LCD Display I2C

หมายเหตุรายละเอียดของการดึงเวลาจาก NTP ทำสามารถดูเพิ่มเติมได้จาก
ขอขอบคุณ  Mr.Comdet Phudphut
      ESP8266 Tutorial ดึงเวลาสากลมาใช้งาน => https://www.youtube.com/watch?v=c8MpndNKOTs
      Time.ino at => https://github.com/esp8266/Arduino/blob/4cf72e7ef4fcabde230de44ba1d1ab5d57cdeee0/tests/Time/Time.ino
      Time.c at => https://github.com/esp8266/Arduino/blob/4b8fb2093fa9dcabe19e4d836c9fb5fc7becf250/cores/esp8266/time.c
      Time.h at => https://github.com/metalheart/esp8266/blob/master/include/time.h

ลงมือซิครับรออะไรอยู่  ** ไม่ต้องคุยเรื่องการติดตั้งนะครับ หาอ่านได้ตาม Internet

  1. เปิดโปรแกรม Arduino ต่อสาย USB จากบอร์ด NodeMCU เข้ากับเครื่อง Notebook เลือกบอร์ด กำหนด Port ให้ถูกต้อง
  2. ต่อสายสัญญาณจาก DHT11 เข้ากับบอร์ด NodeMCU จาก Workshop 2
  3. ต่อสายสัญญาณจาก 16x2 LCD Display I2C
  1. ทำการเปิดไฟล์ ino โดยไปโหลดมาจาก https://github.com/esp8266/Arduino/blob/4cf72e7ef4fcabde230de44ba1d1ab5d57cdeee0/tests/Time/Time.ino

 

  1. เปิดไฟล์เปล่าขึ้นมา แล้ววางข้อความทั้งหมดที่คัดลอกมาลงไป เปลี่ยน SSID และ Password
     
  1. ทดลองสั่ง Run ดู จะเห็นว่ามีค่าวันที่ และเวลา ที่ดึงมาจาก NTP Server ปรากฏใน Serial Monitor แสดงว่าถึงขั้นนี้ก็คือเชื่อมต่อ Internet ผ่าน WIFI ได้ เรียก Time มาจาก NTP Server ได้แล้ว
  2. ปัญหาคือในการแสดงผล มันเรียกใช้คำสั่ง ctime ไปเอาค่าเวลาปัจจุบันมาแสดง (&now) โดยมีรูปแบบที่กำหนดไว้แล้ว เราอยากจะเปลี่ยนตำแหน่งการแสดงผล เนื่องจากพื้นที่บนจอ LCD มีจำกัด คุณคมเดช ได้ให้คำแนะนำใน YouTube ไว้
  1. สิ่งที่จะปรับให้ถูกต้องอันดับแรกคือการกำหนด timezone จากเดิมเป็น 3 ซึ่งประเทศไทยเป็น GMT+7 จึงเปลี่ยนเป็น 7 * 3600 แทน จากนั้นไปทำการกำหนดค่า ConfigTime ให้ไปใช้ค่าตัวแปรที่กำหนดไว้
  2. ทดลอง Run ดูใหม่ ค่าเวลา จะเป็นค่าที่ถูกต้อง
  1. จากนั้นมาดูที่ คุณคมเดช แนะนำไว้ คือการเรียกใช้งาน p_tm โดยจะไปเรียกค่าปัจจุบันจาก localtime ที่ได้มาจาก NTP แล้ว
  2. ทดลอง Run ดู พบว่า ค่าที่มีปัญหาคือ ค่า tm_mon , tm_year ที่ไม่ตรง จากการที่หาข้อมูลค่า tm_mon คือค่าเดือนที่เริ่มนับจาก เดือน 0 คือ Jan ... ดังนั้น ค่าที่อ่านได้จาก tm_mon จึงต้องเพิ่มค่า + 1 , ส่วนค่า tm_year ที่ได้เป็นค่าที่ต้องมีการบวกเพิ่มขึ้นจากปี ค.ศ.1900 ดังนั้นเราจะเอา tm_year+1900+543 เพื่อให้ได้เป็น พ.ศ. 2559
  3. เมื่อเข้าใจถึงค่าที่ได้แล้วเราก็มาจัดการรูปแบบของ วัน/เดือน/ปี ชั่วโมง:นาที ให้พร้อมสำหรับการนำไปใช้แสดงผลบนจอ LCD กัน
  4. เมื่อได้ค่าที่ต้องการมาแล้วก็ถึงเวลารวมร่าง (ชุดคำสั่ง) เข้ากับ Workshop ที่ 3


  1. ชุดคำสั่งทั้งหมด ที่ทำให้เชื่อมต่อ WIFI ได้ สามารถดึงเวลาจาก NTP Server ได้ สามารถอ่านค่าอุณหภูมิและความชื้นจาก DHT11 Sensor ได้ สามารถนำค่าที่อ่านได้แสดงผลบนจอ 16x2 LCD ได้

** โค้ดในชุดคำสั่งอาจจะ ไม่ค่อยเป็นไปตามหลักมากนักนะครับ ผมเป็นพวกตัด-แปะ (Copy – Paste)

// Start Code

// ขอขอบคุณนักพัฒนา ทุกๆ ท่าน

// ขอขอบคุณ อาจารย์อานนท์ หม้อสุวรรณ จาก TESR : Thai Embeded System and Robotic

//    https://www.facebook.com/ThaiEmbedded/?fref=ts

// ขอขอบคุณ Mr.Comdet Phudphut

//    https://www.facebook.com/comdet?fref=ts

//    ESP8266 Tutorial ดึงเวลาสากลมาใช้งาน

//    https://www.youtube.com/watch?v=c8MpndNKOTs

//    Time.ino at => https://github.com/esp8266/Arduino/blob/4cf72e7ef4fcabde230de44ba1d1ab5d57cdeee0/tests/Time/Time.ino

//    Time.c at => https://github.com/esp8266/Arduino/blob/4b8fb2093fa9dcabe19e4d836c9fb5fc7becf250/cores/esp8266/time.c

//    Time.h at => https://github.com/metalheart/esp8266/blob/master/include/time.h

//  ขอขอบคุณ

//    Khon Kaen Maker Club => https://www.facebook.com/KhonKaenMakerClub/?fref=ts

//    Chiang Mai Maker Club => https://www.facebook.com/ChiangMaiMakerClub/?fref=ts

//    Lampang Maker Club => https://www.facebook.com/groups/907239239368989/

// ขอขอบคุณนักพัฒนา Maker ของ การไฟฟ้าฝ่ายผลิตห่งประเทศไทย (กฟผ.) ทุกท่าน

// last update 17 Jan 2016 04:30PM By Mr.Sridetch Pancharkan EGAT Maemoh Mine Lampang Thailand 52220

// ปรับปรุงครั้งสุดท้าย  17 กันยายน 2559 16.30 น. โดย นายศรีเดช  ปัญจขันธ์  กฟผ. เหมืองแม่เมาะ อ.แม่เมาะ จ.ลำปาง 52220

// ผิดพลาดประการใด แจ้งกลับมาได้ครับที่ sridetch.p@egat.co.th

 

#include <ESP8266WiFi.h>

#include <time.h>

#include "DHT.h"

#include <Wire.h>

#include <LiquidCrystal_I2C.h>

 

LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display

 

#define DHTPIN D5     // what digital pin we're connected to

#define DHTTYPE DHT11   // DHT 11

 

const char* ssid = "YourSSID";

const char* password = "YourPassword";

int timezone = 7*3600;

int dst = 0;

DHT dht(DHTPIN, DHTTYPE);

 

void setup() {

  // Welcome message to the LCD.

  lcd.init();                      // initialize the lcd

  lcd.backlight();

  lcd.setCursor(0,0);

  lcd.print("EGAT Expert Pool");

  lcd.setCursor(0,1);

  lcd.print("BigTUI at Maemoh");

 

  Serial.begin(115200);

  Serial.setDebugOutput(true);

  dht.begin();

 

  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);

  Serial.println("\nConnecting to WiFi");

  while (WiFi.status() != WL_CONNECTED) {

    Serial.print(".");

    delay(3000);

  }

  configTime(timezone, dst, 0, "pool.ntp.org", "time.nist.gov");

  Serial.println("\nWaiting for time");

  while (!time(nullptr)) {

    Serial.print(".");

    delay(1000);

  }

  Serial.println("");

}

 

void loop() {

  time_t now = time(nullptr);

  Serial.println(ctime(&now));

  struct tm* p_tm = localtime(&now);

  Serial.print("Time=");Serial.print(p_tm->tm_hour);Serial.print(":");Serial.println(p_tm->tm_min);

  Serial.print("Date(d/m/yyyy)=");Serial.print(p_tm->tm_mday);

  Serial.print("/");Serial.print(p_tm->tm_mon+1);Serial.print("/");Serial.println(p_tm->tm_year+1900+543);

 

  // Reading temperature or humidity takes about 250 milliseconds!

  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)

  float h = dht.readHumidity();

  // Read temperature as Celsius (the default)

  float t = dht.readTemperature();

  // Read temperature as Fahrenheit (isFahrenheit = true)

  float f = dht.readTemperature(true);

 

  // Check if any reads failed and exit early (to try again).

  if (isnan(h) || isnan(t) || isnan(f)) {

    Serial.println("Failed to read from DHT sensor!");

    return;

  }

 

  // Compute heat index in Fahrenheit (the default)

  float hif = dht.computeHeatIndex(f, h);

  // Compute heat index in Celsius (isFahreheit = false)

  float hic = dht.computeHeatIndex(t, h, false);

 

  Serial.print("Humidity: ");Serial.print(h);Serial.print(" %\t");

  Serial.print("Temperature: ");Serial.print(t);Serial.print(" *C ");Serial.print(f);Serial.println(" *F\t");

 

  lcd.init();                      // initialize the lcd

  // Print a message to the LCD.

  lcd.backlight();

  lcd.setCursor(0,0);

  lcd.print("T=");lcd.print(t,0);lcd.print((char)223);lcd.print("C,");

  lcd.print(f,0);lcd.print((char)223);lcd.print("F,");

  lcd.print("H=");lcd.print(h,0);lcd.print("%");

  lcd.setCursor(0,1);

  lcd.print(p_tm->tm_mday);lcd.print("/");lcd.print(p_tm->tm_mon+1);lcd.print("/");lcd.print(p_tm->tm_year+1900+543);lcd.print("  ");

  lcd.print(p_tm->tm_hour);lcd.print(":");lcd.print(p_tm->tm_min);

 

  delay(1000);

}

//END Code by BigTUI.

 

  1. หน้าตาสุดท้ายที่ได้ครับ

   

 

 

จบ Work shop 4 แล้วครับ
หากท่านไม่ได้สร้างสรร สิ่งแรกในโลกนี้
ไม่ต้องห่วงครับโลกนี้มีคนที่เจอปัญหาแบบท่านมาก่อน
และมีคนอีกหลายคนที่สามารถช่วยเหลือท่านได้จากโลกอินเตอร์เน็ต Google ช่วยเราได้

Comment

Comment:

Tweet


ศรีเดช ปัญจขันธ์
View full profile