Để tạo ra đồng hồ thời gian thực thì có nhiều cách khác nhau, hôm nay mình xin giới thiệu với bạn 2 cách, một cách sử dụng phần cứng là DS1307 và cách khác là dùng phần mềm lấy đồng hồ thời gian thực từ server, mỗi cách đều có ưu nhược điểm khác nhau, mời các bạn cùng theo dõi qua bài viết.

Trước khi bắt đầu chúng ta cần chuẩn bị đồ nghề 1 chút, để trực quan sinh động mình sẽ thử trên phần cứng trước

Chuẩn bị

Phần cứng

  • ESP8266 phiên bản bất kỳ, mình dùng luôn NodeMCU
  • Modul DS1307
  • Dây nối và cáp

Phần mềm

Tất cả các thư viện trên các bạn có thể tải trực tiếp về giải nén vào mục C:\Program Files (x86)\Arduino\libraries hoặc tải từ Sketch -> Include Library -> Manage Libraries

Đọc thời gian thực từ DS1307 với ESP8266

Để có thể thực hiện điều này một cách nhanh nhất mình sử dụng thư viện RTClib

Kết nối

Chương trình đồng bộ thời gian từ máy tính để đặt thời gian ban đầu cho RTC, sau đó đọc thời gian và hiển thị lên máy tính thông qua serial với baud là 115200

#include <Wire.h>
#include <SPI.h>

#include "RTClib.h"
RTC_DS1307 RTC;
void setup () {
  Wire.begin(4, 5); // Chan 4,5 I2C cua ESP8266
  RTC.begin();      // Khoi dong RTC
  delay(500);
  // Dong bo thoi gian voi may tinh
  RTC.adjust(DateTime(__DATE__, __TIME__)); 
  delay(1000);
  Serial.begin(115200); // Khoi dong serial port de lay du lieu

}
void loop() {
  DateTime now = RTC.now(); // Thoi gian = thoi gian RTC hien tai
  // In thời gian
  Serial.print(now.year(), DEC); // Năm
  Serial.print('/');
  Serial.print(now.month(), DEC); // Tháng
  Serial.print('/');
  Serial.print(now.day(), DEC); // Ngày
  Serial.print(' ');
  Serial.print(now.hour(), DEC); // Giờ
  Serial.print(':');
  Serial.print(now.minute(), DEC); // Phút
  Serial.print(':');
  Serial.print(now.second(), DEC); // Giây
  Serial.println();
  delay(1000); // Delay
}

Kết quả là giờ phút giây như sau

Sau khi giao tiếp xong thì mình lại suy nghĩ có cách nào để bỏ bớt phần cứng đi không, chẳng hạn như bỏ luôn cái DS1307 để tiết kiệm thêm chút, chưa kể là lúc đồng bộ thời gian từ trên máy tính xuống thì cũng hơi chậm hơn thực tế vài chục giây, thật may là có 1 cách hợp lý hơn là tận dụng khả năng kết nối mạng wifi sẵn có để đồng bộ luôn thời gian từ server.

Tiếp tục chơi chiêu lập trình tốc độ bàn thờ với việc sử dụng thư viện và arduino cho ESP8266

Chương trình

/*
   This sketch shows an example of sending a reading to data.sparkfun.com once per day.
   It uses the Sparkfun testing stream so the only customizing required is the WiFi SSID and password.
   The Harringay Maker Space
   License: Apache License v2
*/
#include <NTPtimeESP.h>

NTPtime NTPch("ch.pool.ntp.org");   // Server NTP
char *ssid      = "ten_wifi";               // Ten WiFi SSID
char *password  = "password";               // Mat khau wifi

/*
 * Cac truong co trong struct DateTime:
 * struct strDateTime
{
  byte hour;
  byte minute;
  byte second;
  int year;
  byte month;
  byte day;
  byte dayofWeek;
  boolean valid;
};
 */
strDateTime dateTime;

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println("Booted");
  Serial.println("Connecting to Wi-Fi");

  WiFi.mode(WIFI_STA);
  WiFi.begin (ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println("WiFi connected");
}

void loop() {

  // Tham so dau tien la Time zone duoi dang floating point (7.0 la VN); 
  // Tham so thu hai la DayLightSaving: 1 voi thoi gian; 2 la thoi gian US (o VN khong su dung)
  dateTime = NTPch.getNTPtime(7.0, 0);
  
  // Kiem tra dateTime.valid truoc khi dua ra gia tri thoi gian
  if(dateTime.valid){
    NTPch.printDateTime(dateTime);

    byte actualHour = dateTime.hour;      // Gio
    byte actualMinute = dateTime.minute;  // Phut
    byte actualsecond = dateTime.second;  // Giay
    int actualyear = dateTime.year;       // Nam
    byte actualMonth = dateTime.month;    // Thang
    byte actualday =dateTime.day;         // Ngay
    byte actualdayofWeek = dateTime.dayofWeek;
  }
}

Trong code chỉ cần lưu ý đoạn

char *ssid = "ten_wifi"; // Ten WiFi SSID
char *password = "password"; // Mat khau wifi

để thực hiện kết nối wifi vào mạng của bạn

dateTime = NTPch.getNTPtime(7.0, 0);

Code này lấy đúng giờ VN không có daylight saving time với múi giờ là 7.0

Kết quả

Vậy là đã xong 2 bước thử ra kết quả, giờ NTP là cái gì nhỉ, chúng ta thử tìm hiểu lại một chút về các khái niệm để hiểu rõ hơn xem sao

NTP Server là gì ?

NTP là viết tắt của Network Time Protocol, một giao thức dugf để kết nối và đồng bộ giữa các máy chủ với nhau từ những năm 1980. Nhiệm vụ của NTP là đơn giản động bộ tất cả các thành phần trong mạng với giờ UTC trong thời gian lên tới mili giây. Vì mỗi thành phần có những sai số khác nhau nên để làm được điều này cần thông qua thuật toán gọi là “intersection algorithm” của ông Keith Marlzullo, các bạn nếu có hứng thú có thể tìm hiểu thêm. Với việc đồng bộ thời gian nhanh chóng như vậy thì đồng hồ thời gian thực của chúng ta gần như tuyệt đối.

Làm sao để có thể dùng NTP Server

Có bao giờ bạn tư hỏi thời gian của máy tính/ laptop của mình được lấy từ đâu không ? Nó chính được lấy từ server NTP đấy. Thông thường NTP Server sẽ mở một kết nối UDP trên port local, sau đó gửi và nhận các gói tin UDP trong cùng một mạng với các máy chủ, thông tin của gói UDP sẽ là thời gian UNIX, độ chính xác, độ trễ, múi giờ và nhiều phương thức khác để bạn có thể trích xuất ra sử dụng cho mình. Từ windows sẽ có các service kết nối tới NTP Server để đồng bộ dữ liệu về.

Độ chính xác của NTP Server ?

Với hệ thống kiến trúc phân cấp các cấp độ của đồng hồ NTP Server có dạng như hình bên dưới

Ta có thể thấy có rất nhiều yếu tố có thể ảnh hưởng tới độ chính xác của NTP như:

  • Tốc độ kết nối của các client
  • Server được lựa chọn để đồng bộ (strata)
  • Khoảng cách tín hiệu từ các server
  • Chất lượng và độ phức tạp của các thuật toán được sử dụng

Để có được thời gian chính xác cao thì người ta khuyên chúng ta nên chọn những server gần với nơi ở của mình, ví dụ như

Thời gian Unix timestamp là gì ?

Có một điểm thú vị là những thời gian ngày tháng năm như chúng ta biết thường dựa trên lịch, nhưng với má tính thì cũng có một “lịch riêng” của nó, Unix time stamp là cách thức để lưu trữ thời gian dựa trên tổng số giây. Cách tính này được bắt đầu từ ngày 1/1/1970, vậy với hệ thống gốc dùng cho việc đo thời gian dựa trên nền 32 bit và chỉ có thể ghi nhận 4.294.967.296 giây hay 136 năm, bao quát được giai đoạn từ 1901 đến 2038, và đến ngày thứ Ba, 19/1/2038, tất cả các hệ thống UNIX sẽ khởi động lại đồng hồ, việc khởi động lại đồng hồ khá là nguy hiểm nên các nhà phát triển phần mềm đã hực hiện chuyển đổi hệ thống sang nền 64 bit, nghĩa là có thể dùng thời gian trong khoảng 293 tỉ năm. Giờ thì khỏi phải lo reset đồng hồ nữa rồi.

Tạm kết

Thế là mình cũng đã nói được sơ qua về cách tạo ra đồng hồ thời gian thực với DS1307 và ESP8266 cũng như cách để đồng bộ thời gian thực từ server NTP, ngoài ra cũng có một số khái niệm vui vui lý thuyết để các bạn tham khảo thêm. Rất may là có sẵn những thư viện để mình có thể dùng và kiểm tra luôn. Hi vọng bài viết sẽ giúp ích phần nào trong hệ thống của bạn.

Tham khảo [1] [2] [3] [4]