mrBov (Kritskon) November 28, 2020, 12:42pm #1
ใครเคยมีปัญหาการดึงเวลาจาก NTP ผ่าน wifi ที่ปล่อยจากแหล่งที่ไม่ค่อยเสถียรและหลุดบ่อย จนทำให้ interrupt ลองใช้วิธีนี้ดูครับ
หลักการคือการกำหนดให้มีการต่อ wifi และดึงค่าเวลาจาก ntp server ในครั้งแรกที่เริ่มต้นโปรแกรมเพื่อเป็นการเทียบเวลาในปัจจุบันและนำไปนับต่อด้วยโค๊ดจาก TimeKeeping No RTC หลังจาก nodemcu รันเวลาได้แล้ว เราสามารถตัดการเชื่อมต่อ wifi ได้ โดยที่ระบบยังทำงานตามรอบเวลาต่อไปอยู่ แต่อาจจะมีความคลาดเคลื่อนของเวลาบ้างเล็กน้อยในหลักวินาที
#include <ESP8266WiFi.h>
#include <time.h>
#define nodeMCU_LED D4 // Nodemcu v2 ใช้ D0 , Nodemcu v3 ใช้ D4
const char* ssid = "xxxxxxxxxxx"; // SSID is set
const char* password = "xxxxxxxxxx"; // Password is set
char ntp_server1[20] = "1.asia.pool.ntp.org";
char ntp_server2[20] = "1.th.pool.ntp.org";
char ntp_server3[20] = "time.navy.mi.th";
int timezone = 7 * 3600; //timezone for Thailand is +7
int dst = 0;
//Written by Ruben Marc Speybrouck
unsigned long timeNow = 0;
unsigned long timeLast = 0;
//Time start Settings:
int startingHour = 14; // set your starting hour here, not below at int hour. This ensures accurate daily correction of time
int seconds = 0;
int minutes = 14;
int hours = startingHour;
int days = 0;
//Accuracy settings
int dailyErrorFast = 0; // set the average number of milliseconds your microcontroller's time is fast on a daily basis
int dailyErrorBehind = 0; // set the average number of milliseconds your microcontroller's time is behind on a daily basis
int correctedToday = 1; // do not change this variable, one means that the time has already been corrected today for the error in your boards crystal. This is true for the first day because you just set the time when you uploaded the sketch.
void setup() { // put your setup code here, to run once:
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println(WiFi.localIP());
Serial.println("");
pinMode(nodeMCU_LED,OUTPUT);
for (int i=0; i <= 20; i++){
configTime(timezone, dst, ntp_server1, ntp_server2, ntp_server3);
Serial.println("\nWaiting for time");
while (!time(nullptr)) {
Serial.print(".");
delay(30000);
}
time_t now = time(nullptr);
struct tm* p_tm = localtime(&now);
//Serial.print(".");
delay(1000);
if(i==20){
Serial.println("");
Serial.print(p_tm->tm_hour); Serial.print(":");
Serial.print(p_tm->tm_min); Serial.print(":");
Serial.println(p_tm->tm_sec);
Serial.println(ctime(&now));
hours = p_tm->tm_hour;
minutes = p_tm->tm_min;
seconds = p_tm->tm_sec;
}
}
}
void loop() { // put your main code here, to run repeatedly:
timeNow = millis()/1000; // the number of milliseconds that have passed since boot
seconds = timeNow - timeLast;
//the number of seconds that have passed since the last time 60 seconds was reached.
if (seconds >= 60) {
timeLast = timeNow;
minutes = minutes + 1; }
//if one minute has passed, start counting milliseconds from zero again and add one minute to the clock.
if (minutes >= 60){
minutes = 0;
hours = hours + 1; }
// if one hour has passed, start counting minutes from zero and add one hour to the clock
if (hours == 24){
hours = 0;
days = days + 1;
}
//if 24 hours have passed, add one day
if (hours ==(24 - startingHour) && correctedToday == 0){
delay(dailyErrorFast*1000);
seconds = seconds + dailyErrorBehind;
correctedToday = 1; }
//every time 24 hours have passed since the initial starting time and it has not been reset this day before, add milliseconds or delay the program with some milliseconds.
//Change these varialbes according to the error of your board.
// The only way to find out how far off your boards internal clock is, is by uploading this sketch at exactly the same time as the real time, letting it run for a few days
// and then determining how many seconds slow/fast your boards internal clock is on a daily average. (24 hours).
if (hours == 24 - startingHour + 2) {
correctedToday = 0; }
//let the sketch know that a new day has started for what concerns correction, if this line was not here the arduiono // would continue to correct for an entire hour that is 24 - startingHour.
Serial.print("The time is: ");
Serial.print(days);
Serial.print(":");
Serial.print(hours);
Serial.print(":");
Serial.print(minutes);
Serial.print(":");
Serial.println(seconds);
digitalWrite(nodeMCU_LED,HIGH);
delay(500);
digitalWrite(nodeMCU_LED,LOW);
delay(500);
}