โดยปกติทั่วไปเวลาเราใช้ microcontroller ไม่ว่าจะเป็น Arduino หรือ ESP8266 หรืออะไรก็ตาม ในการทำ project ต่างๆที่เกี่ยวข้องกับเวลา ไม่ว่าจะเป็น Smart farm, ที่รดน้ำต้นไม้ เราจำเป็นต้องมีเวลามาเกี่ยวข้อง แม้ว่าในตัว MCU จะมีนาฬิกาแต่มันไม่สะดวก พอตัดไฟ ไฟดับ ไฟตก เวลาก็หายไป และต้องมาหาวันที่ วัน เดือนปี คศ แถมยังมีปีอธิกสุรทินอีก
ดังนั้นเรามักจะใช้ตัว module นาฬิกาเข้ามาเสริมจัดการตรงนี้ให้ง่ายๆแทน
ดูหมือนก็ไม่น่าจะมีปัญหาใช่ไหม ใช่ ถ้าเราทำโปรเจคที่เวลาเพี้ยนได้หลายร้อย millisecond แต่บางคนเริ่มเจอปัญหา
นั่นแสดงความยินดีด้วยเพราะแสดงว่าคุณเริ่มทำโปรเจคยากๆได้แล้ว ไม่ใช้มือใหม่อีกต่อไป เพราะคุณเห็นความเพี้ยนของเวลาเล็กๆได้
ปัญหามาจากไหน
อุปกรณ์พวกนี้ มันมีการสื่อสารข้อมูลระหว่าง Module RTC กับ MCU มันย่อมกินเวลา เวลาที่ระบบทำงานต้องหยุดรอ โดยจะเห็นได้ชัดมากเวลาที่เราต้องแสดงผลอะไรแบบต่อเนื่องเช่น LED strip จะเห็นมันแสดงผลอืดมาก หากเราแก้ปัญหาโดยการให้มันอ่านค่าเวลาไม่บ่อยนานๆที ผลก็คือ เวลาควบคุมก็จะไม่ตรง realtime
กระทู้นี้เป็นการแชร์วิธีการแก้ปัญหาของผมเท่านั้น ครับ หากใครมี วิธีอื่นก็ต่อได้ตามสบายครับ ไม่คาดหวังว่าใครจะมาอ่านแล้วรู้เรื่องเพราะมันเฉพาะทาง แต่เผื่อไว้ว่าอนาคตใครทำอะไรแล้วมีปัญหานี้ก็เอาไปใช้ได้
เรามาดู การใช้ RTC สมมุติว่าผมใช้ RTC DS3231 (หรือ module ก็ลองประยุกต์เอาเอง) บน Arduino Nano โปรแกรม Code การอ่านค่า RTC ทั่วไป จะเป็นแบบนี้
//***********************************************************************************
#include "Wire.h"
#include "DS3231.h"
DS3231 xclock;
RTCDateTime dt;
int s, m, h; //time sec, min, Hour
int D, M, Y; //Date, Month
long LoopTimeIn,LoopTimeOut;
void setup() {
Serial.begin(115200);
xclock.begin();
//xclock.setDateTime(2019, 7, 28, 13, 37, 0);// ใช้ตั้ง RTC เฉพาะ ครั้งแรก (ปี,เดือน,วัน, ชั่วโมง,นาที,วินาที)
RTCread();
}
void loop() {
LoopTimeIn=micros();
RTCread();
LoopTimeOut=micros();
Serial.print("Read Clock Time=");
Serial.print(LoopTimeOut-LoopTimeIn) ;
Serial.print(" microsec ,") ;
Serial.print("Time ");
Serial.print(h);
Serial.print(":");
Serial.print(m);
Serial.print(":");
Serial.print(s);
Serial.print(" ");
Serial.print(D);
Serial.print("/");
Serial.print(M);
Serial.print("/");
Serial.print(Y);
Serial.println("");
}
void RTCread()
{
dt = xclock.getDateTime();
s = dt.second;
m = dt.minute;
h = dt.hour;
xclock.forceConversion();
D = dt.day;
M = dt.month;
Y = dt.year;
}
//***********************************************************************************
เวลาที่ใช้ในการอ่านค่า เวลาคือประมาณ 135,050 microsec หรือ 135 microsec นานมาก
ซึ่งเยอะมากพอดูและสังเกตเห็นได้ในบาง Project ว่าเลขวินาทีที่แสดงผลมันเขย่ง เร็ว ช้าแบบสังเกตดีๆรู้สึกได้
หรือมองอีกมุมหนึ่งคือ Project นี้ไม่สามารถ Refresh เวลา ในช่วงเวลาได้ต่ำกว่า 135 ms เลย
วิธีการแก้ปัญหาที่จะนำเสนอต่อไปนี้คือการรวม เอาเวลาจาก RTC และ clock ใน MCU มาใช้ด้วยกันแบบ Hybrid โดย เวลา RTC ซึ่งมีข้อดีคือเวลาไม่หายเวลาไฟดับ ไม่ต้องตั้งใหม่ เวลาเปิดใหม่ และ Clock ใน MCU ที่อ่านเร็วมากไม่เสียเวลา
หลักการคือเราจะอ่านเวลาจาก RTC ครั้งแรกและอ่านอีกเป็นช่วงๆ (แต่ไม่เกิน 30 วันในแต่ละช่วง แต่ไม่ควรนานขนาดนั้นแค่ 1-2 นาทีก็พอแล้ว) เป็นค่าเริ่มต้นและนำไปบวกกับเวลาที่เคลื่อนไปจากตำแหน่งที่อ่าน ซึ่งมาจาก clock ของ MCU เอาเวลาที่ได้มาคำนวณทดเวลา นาที ชั่วโมงไป ก็จะได้เวลาจริง ณ จุดใดๆ ดังโปรแกรมนี้
//***********************************************************************************
#include “Wire.h”
#include “DS3231.h”
DS3231 xclock;
RTCDateTime dt;
int s, m, h; //time sec, min, Hour
int D, M, Y; //Date, Month
unsigned long HybridTimeStart;
int HybridRefresh = 120; //in sec to refresh hybrid time to real RTC time
int hF, mF, sF;//Fix h,m,s
long LoopTimeIn,LoopTimeOut;
void setup() {
Serial.begin(115200);
xclock.begin();
//xclock.setDateTime(2019, 7, 28, 13, 37, 0);
HybridTimeStart = millis();
RTCread();
}
void loop() {
LoopTimeIn=micros();
GetTime();
//RTCread();
LoopTimeOut=micros();
Serial.print("Read Clock Time=");
Serial.print(LoopTimeOut-LoopTimeIn) ;
Serial.print(" microsec ,") ;
Serial.print("Time ");
Serial.print(h);
Serial.print(":");
Serial.print(m);
Serial.print(":");
Serial.print(s);
Serial.print(" ");
Serial.print(D);
Serial.print("/");
Serial.print(M);
Serial.print("/");
Serial.print(Y);
Serial.println("");
}
void GetTime() {//RTC Time
static unsigned long TotalSec;
if ((HybridTimeStart + (HybridRefresh * 1000)) < millis())
{ RTCread();
HybridTimeStart = millis();
Serial.print("Hybrid Update");
}
s = sF;
m = mF;
h = hF;
long xtrasec;
xtrasec = byte((millis() - HybridTimeStart) / 1000);
TotalSec = h * 3600L + m * 60 + s + xtrasec;
s = TotalSec % 60;
h = TotalSec / 3600;
m = ((TotalSec - ((TotalSec / 3600) * 3600)) / 60);
if (h >= 24)h = h - 24;
}
void RTCread()
{
dt = xclock.getDateTime();
s = dt.second;
m = dt.minute;
h = dt.hour;
xclock.forceConversion();
D = dt.day;
M = dt.month;
Y = dt.year;
sF = s; //fix sec for hybrid use
mF = m;
hF = h;
}
//***********************************************************************************
โดยเราเพิ่ม HybridRefresh เป็นช่วงเวลาที่เราอ่าน RTC ในตัวอย่างคือทุก 120 วินาที ผลคือ
เวลาที่อ่านนาฬิกาเหลือ 176 microsec ไม่ถึง 0.2 ของ millisec ซึ่งเร็วกว่าเก่ามากๆ หลักการง่ายๆแต่ได้ผล
ทำให้เราสามารถ update เวลาเราได้บ่อยมากๆ วินาทีละพันครั้งยังได้ และเวลาที่แสดงผลก็จะตรงกับเวลาจริงมาก
ขอจบแค่นี้แหละครับหวังว่าคงได้ประโยชน์บ้าง อนึ่งหากต้องการมันแม่นเข้าไปอีกก็ลบ เวลาที่อ่านได้ด้วยเวลาที่ใช้ไปจากการอ่าน แต่ผมมองว่ามันไม่จำเป็นหรอก เพราะช่วงตั้งเวลาก็เพี้ยนกว่านั้นแล้ว
หมายเหตุ: หากใช้ ESP8266 และมี Internet เราไม่ต้องใช้ RTC เลยครับอ่านเวลาจาก NTP server แทนเลย
ใครจะวิจารณ์ หรือเสนอเพิ่มอะไรก็ต่อด้านล่างตามสบายครับ
การปรับปรุง โมดุล นาฬิกา RTC, Real Time Clock สำหรับ Micro Controller, Arduino, ESP8266 ให้เร็วแม่นยำ แก้ปัญหา lack
ดังนั้นเรามักจะใช้ตัว module นาฬิกาเข้ามาเสริมจัดการตรงนี้ให้ง่ายๆแทน
ดูหมือนก็ไม่น่าจะมีปัญหาใช่ไหม ใช่ ถ้าเราทำโปรเจคที่เวลาเพี้ยนได้หลายร้อย millisecond แต่บางคนเริ่มเจอปัญหา
นั่นแสดงความยินดีด้วยเพราะแสดงว่าคุณเริ่มทำโปรเจคยากๆได้แล้ว ไม่ใช้มือใหม่อีกต่อไป เพราะคุณเห็นความเพี้ยนของเวลาเล็กๆได้
ปัญหามาจากไหน
อุปกรณ์พวกนี้ มันมีการสื่อสารข้อมูลระหว่าง Module RTC กับ MCU มันย่อมกินเวลา เวลาที่ระบบทำงานต้องหยุดรอ โดยจะเห็นได้ชัดมากเวลาที่เราต้องแสดงผลอะไรแบบต่อเนื่องเช่น LED strip จะเห็นมันแสดงผลอืดมาก หากเราแก้ปัญหาโดยการให้มันอ่านค่าเวลาไม่บ่อยนานๆที ผลก็คือ เวลาควบคุมก็จะไม่ตรง realtime
กระทู้นี้เป็นการแชร์วิธีการแก้ปัญหาของผมเท่านั้น ครับ หากใครมี วิธีอื่นก็ต่อได้ตามสบายครับ ไม่คาดหวังว่าใครจะมาอ่านแล้วรู้เรื่องเพราะมันเฉพาะทาง แต่เผื่อไว้ว่าอนาคตใครทำอะไรแล้วมีปัญหานี้ก็เอาไปใช้ได้
เรามาดู การใช้ RTC สมมุติว่าผมใช้ RTC DS3231 (หรือ module ก็ลองประยุกต์เอาเอง) บน Arduino Nano โปรแกรม Code การอ่านค่า RTC ทั่วไป จะเป็นแบบนี้
//***********************************************************************************
#include "Wire.h"
#include "DS3231.h"
DS3231 xclock;
RTCDateTime dt;
int s, m, h; //time sec, min, Hour
int D, M, Y; //Date, Month
long LoopTimeIn,LoopTimeOut;
void setup() {
Serial.begin(115200);
xclock.begin();
//xclock.setDateTime(2019, 7, 28, 13, 37, 0);// ใช้ตั้ง RTC เฉพาะ ครั้งแรก (ปี,เดือน,วัน, ชั่วโมง,นาที,วินาที)
RTCread();
}
void loop() {
LoopTimeIn=micros();
RTCread();
LoopTimeOut=micros();
Serial.print("Read Clock Time=");
Serial.print(LoopTimeOut-LoopTimeIn) ;
Serial.print(" microsec ,") ;
Serial.print("Time ");
Serial.print(h);
Serial.print(":");
Serial.print(m);
Serial.print(":");
Serial.print(s);
Serial.print(" ");
Serial.print(D);
Serial.print("/");
Serial.print(M);
Serial.print("/");
Serial.print(Y);
Serial.println("");
}
void RTCread()
{
dt = xclock.getDateTime();
s = dt.second;
m = dt.minute;
h = dt.hour;
xclock.forceConversion();
D = dt.day;
M = dt.month;
Y = dt.year;
}
//***********************************************************************************
เวลาที่ใช้ในการอ่านค่า เวลาคือประมาณ 135,050 microsec หรือ 135 microsec นานมาก
ซึ่งเยอะมากพอดูและสังเกตเห็นได้ในบาง Project ว่าเลขวินาทีที่แสดงผลมันเขย่ง เร็ว ช้าแบบสังเกตดีๆรู้สึกได้
หรือมองอีกมุมหนึ่งคือ Project นี้ไม่สามารถ Refresh เวลา ในช่วงเวลาได้ต่ำกว่า 135 ms เลย
วิธีการแก้ปัญหาที่จะนำเสนอต่อไปนี้คือการรวม เอาเวลาจาก RTC และ clock ใน MCU มาใช้ด้วยกันแบบ Hybrid โดย เวลา RTC ซึ่งมีข้อดีคือเวลาไม่หายเวลาไฟดับ ไม่ต้องตั้งใหม่ เวลาเปิดใหม่ และ Clock ใน MCU ที่อ่านเร็วมากไม่เสียเวลา
หลักการคือเราจะอ่านเวลาจาก RTC ครั้งแรกและอ่านอีกเป็นช่วงๆ (แต่ไม่เกิน 30 วันในแต่ละช่วง แต่ไม่ควรนานขนาดนั้นแค่ 1-2 นาทีก็พอแล้ว) เป็นค่าเริ่มต้นและนำไปบวกกับเวลาที่เคลื่อนไปจากตำแหน่งที่อ่าน ซึ่งมาจาก clock ของ MCU เอาเวลาที่ได้มาคำนวณทดเวลา นาที ชั่วโมงไป ก็จะได้เวลาจริง ณ จุดใดๆ ดังโปรแกรมนี้
//***********************************************************************************
#include “Wire.h”
#include “DS3231.h”
DS3231 xclock;
RTCDateTime dt;
int s, m, h; //time sec, min, Hour
int D, M, Y; //Date, Month
unsigned long HybridTimeStart;
int HybridRefresh = 120; //in sec to refresh hybrid time to real RTC time
int hF, mF, sF;//Fix h,m,s
long LoopTimeIn,LoopTimeOut;
void setup() {
Serial.begin(115200);
xclock.begin();
//xclock.setDateTime(2019, 7, 28, 13, 37, 0);
HybridTimeStart = millis();
RTCread();
}
void loop() {
LoopTimeIn=micros();
GetTime();
//RTCread();
LoopTimeOut=micros();
Serial.print("Read Clock Time=");
Serial.print(LoopTimeOut-LoopTimeIn) ;
Serial.print(" microsec ,") ;
Serial.print("Time ");
Serial.print(h);
Serial.print(":");
Serial.print(m);
Serial.print(":");
Serial.print(s);
Serial.print(" ");
Serial.print(D);
Serial.print("/");
Serial.print(M);
Serial.print("/");
Serial.print(Y);
Serial.println("");
}
void GetTime() {//RTC Time
static unsigned long TotalSec;
if ((HybridTimeStart + (HybridRefresh * 1000)) < millis())
{ RTCread();
HybridTimeStart = millis();
Serial.print("Hybrid Update");
}
s = sF;
m = mF;
h = hF;
long xtrasec;
xtrasec = byte((millis() - HybridTimeStart) / 1000);
TotalSec = h * 3600L + m * 60 + s + xtrasec;
s = TotalSec % 60;
h = TotalSec / 3600;
m = ((TotalSec - ((TotalSec / 3600) * 3600)) / 60);
if (h >= 24)h = h - 24;
}
void RTCread()
{
dt = xclock.getDateTime();
s = dt.second;
m = dt.minute;
h = dt.hour;
xclock.forceConversion();
D = dt.day;
M = dt.month;
Y = dt.year;
sF = s; //fix sec for hybrid use
mF = m;
hF = h;
}
//***********************************************************************************
โดยเราเพิ่ม HybridRefresh เป็นช่วงเวลาที่เราอ่าน RTC ในตัวอย่างคือทุก 120 วินาที ผลคือ
เวลาที่อ่านนาฬิกาเหลือ 176 microsec ไม่ถึง 0.2 ของ millisec ซึ่งเร็วกว่าเก่ามากๆ หลักการง่ายๆแต่ได้ผล
ทำให้เราสามารถ update เวลาเราได้บ่อยมากๆ วินาทีละพันครั้งยังได้ และเวลาที่แสดงผลก็จะตรงกับเวลาจริงมาก
ขอจบแค่นี้แหละครับหวังว่าคงได้ประโยชน์บ้าง อนึ่งหากต้องการมันแม่นเข้าไปอีกก็ลบ เวลาที่อ่านได้ด้วยเวลาที่ใช้ไปจากการอ่าน แต่ผมมองว่ามันไม่จำเป็นหรอก เพราะช่วงตั้งเวลาก็เพี้ยนกว่านั้นแล้ว
หมายเหตุ: หากใช้ ESP8266 และมี Internet เราไม่ต้องใช้ RTC เลยครับอ่านเวลาจาก NTP server แทนเลย
ใครจะวิจารณ์ หรือเสนอเพิ่มอะไรก็ต่อด้านล่างตามสบายครับ