RTC 或實時時鐘是電子和嵌入式設備中最常用的模塊,用于跟蹤時間。但是 RTC 的問題是計算機中的微芯片不是那么準確,它們只能提供本地設備的時間。另一方面,使用互聯(lián)網(wǎng)從 NTP 服務器獲取時間是獲取時間的更好解決方案,因為它更準確并且可以提供世界上任何地理區(qū)域的時間。我們只需要一個 Wi-Fi 模塊并訪問互聯(lián)網(wǎng)即可通過使用 NTP 服務器獲取世界上任何位置的時間。在本教程中,我們將使用 ESP8266 NodeMCU 從 NTP 服務器獲取當前時間和日期,并將其顯示在 OLED 顯示屏上。
網(wǎng)絡時間協(xié)議 (NTP)
NTP 是用于在計算機網(wǎng)絡之間同步時鐘的最古老的網(wǎng)絡 Internet 協(xié)議 (IP) 之一。它由特拉華大學的 David L. Mills 于 1981 年設計。該協(xié)議可用于在幾毫秒內(nèi)將許多網(wǎng)絡與協(xié)調(diào)世界時 (UTC)同步。UTC 是世界調(diào)節(jié)時鐘和時間的主要時間標準。UTC 不會因不同的地理位置而改變和變化。NTP 使用 UTC 作為時間參考,并通過 Internet 提供準確和同步的時間。
NTP 工作在分層的客戶端-服務器模型上。頂級型號具有稱為“stratum0”的參考時鐘,如原子鐘、無線電波、GPS、GSM,可從衛(wèi)星接收時間。從stratum0接收時間的服務器稱為“stratum1”,從stratum1接收時間的服務器稱為“stratum2”,依此類推。這種情況繼續(xù)下去,時間的準確性在每個階段之后都在下降。NTP 自動選擇幾個可用時間源中最好的一個進行同步,這使其具有容錯能力。
所以在這個項目中,我們使用 ESP8266 NodeMCU 從 NTP 服務器獲取時間并將其顯示在 OLED 顯示器上。
ESP8266 可以使用互聯(lián)網(wǎng)訪問 NTP 服務器以獲取準確的時間。這里 NTP 工作在客戶端-服務器模式,ESP8266 作為客戶端設備使用 UDP(用戶數(shù)據(jù)報協(xié)議)與NTP 服務器連接??蛻舳讼?NTP 服務器發(fā)送一個請求包,然后 NTP 發(fā)送一個時間戳包,其中包含準確度、時區(qū)、UNIX 時間戳等信息。然后客戶端將日期和時間詳細信息分離出來,可以根據(jù)需要在應用程序中進一步使用。
所需組件
單色 7 針 SSD1306 0.96” OLED 顯示屏
ESP8266 NodeMCU
微型 USB 數(shù)據(jù)線
面包板
公對公跳線
電路圖和連接
這款 7 針 OLED 顯示器使用 SPI 協(xié)議與 ESP8266 模塊通信,下面是連接 OLED SPI 針與 NodeMCU 以顯示互聯(lián)網(wǎng)時間的電路圖和連接表。
代碼說明
首先,我們必須將 NTP 庫下載并安裝到 ESP8266 中。有許多可用于 NTP 客戶端的庫。您可以從 Arduino IDE 安裝其中的任何一個。在本教程中,我安裝了Taranais 的 NTPClient 庫,因為它易于使用并且具有從 NTP 服務器獲取日期和時間的功能。
要安裝 NTP 庫,首先使用上面的鏈接下載庫,然后使用 Arduino IDE 安裝它。要安裝它,請轉(zhuǎn)到Sketch 》 Include Library 》 Add .ZIP Library,然后通過轉(zhuǎn)到您下載 zip 文件夾的位置打開 Zip 文件夾并重新啟動 Arduino IDE。
NTPClient 庫附帶示例。打開 Arduino IDE 并轉(zhuǎn)到示例 》 NTPClient 》 高級。此草圖中給出的代碼在串行監(jiān)視器上顯示來自 NTP 服務器的時間。我們將使用此草圖在 OLED 顯示屏上顯示當前時間和日期。
本教程末尾提供了完整的代碼,這里我解釋了代碼的幾個重要部分。
ESP8266WiFi 庫提供 ESP8266 特定的 Wi-Fi 例程以連接到網(wǎng)絡。WiFiUDP.h處理發(fā)送和接收 UDP 包。由于我們使用 SPI 協(xié)議將 OLED 與 NodeMCU 連接,因此我們將導入“SPI.h”庫。而“Adafruit_GFX.h”和“Adafruit_SSD1306.h”用于OLED顯示。
#include#include // 提供我們調(diào)用的 ESP8266 特定 Wi-Fi 例程以連接到網(wǎng)絡 #include // 處理 UDP 包的發(fā)送和接收 #include // 用于將 OLED 與 NodeMCU 連接的 SPI #include #include
我們的 OLED 尺寸為 128x64,因此我們將屏幕寬度和高度分別設置為 128 和 64。因此,為連接到 NodeMCU 的 OLED 引腳定義變量以進行 SPI 通信。
#define SCREEN_WIDTH 128 // OLED 顯示寬度,以像素為單位 #define SCREEN_HEIGHT 64 // OLED 顯示高度,以像素為單位 // 使用軟件 SPI 連接 SSD1306 顯示器的聲明(默認情況): #define OLED_MOSI D7 #define OLED_CLK D5 #define OLED_DC D2 #define OLED_CS D8 #define OLED_RESET D3
Adafruit_SSD1306 顯示器(SCREEN_WIDTH、SCREEN_HEIGHT、OLED_MOSI、OLED_CLK、OLED_DC、OLED_RESET、OLED_CS);
在下面的代碼行中,將“your_ssid”和“your_password”替換為您的 Wi-Fi SSID 和密碼。
const char *ssid = "your_ssid"; const char *password = "your_password";
通過向WiFi.begin函數(shù)提供 SSID 和密碼來設置 WI-Fi 連接。ESP8266 的連接需要一些時間才能連接到 NodeMCU,所以我們必須等到它連接上。
WiFi.begin(ssid, 密碼); 而(WiFi.status()!= WL_CONNECTED){ 延遲(500); Serial.print("."); }
要請求日期和時間,請使用 NTP 服務器的地址初始化時間客戶端。為了獲得更好的準確性,請選擇靠近您的地理區(qū)域的 NTP 服務器的地址。在這里,我們使用“ pool.ntp.org ”,它提供來自世界各地的服務器。如果您想從亞洲選擇服務器,您可以使用“ asia.pool.ntp.org ”。timeClient還采用您的時區(qū)的 UTC 時間偏移量(以毫秒為單位)。例如,印度的 UTC 偏移量為 +5:30,因此我們以毫秒為單位轉(zhuǎn)換此偏移量,等于 5*60*60+30*60 = 19800。
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 19800,60000);
SSD1306_SWITCHCAPVCC在內(nèi)部產(chǎn)生 3.3V 電壓來初始化顯示。當 OLED 啟動時,它會顯示“WELCOME TO CIRCUIT DIGEST”,文字大小為 2,顏色為藍色,持續(xù) 3 秒。
if(!display.begin(SSD1306_SWITCHCAPVCC)) { Serial.println(F("SSD1306 分配失敗")); 為了(;;); // 不要繼續(xù),永遠循環(huán) } display.clearDisplay(); display.setTextSize(2); // 繪制 2X 比例的文本 display.setTextColor(BLUE); display.setCursor(5, 2); display.println("歡迎來到"); display.println("電路"); display.println("摘要"); 顯示.顯示(); 延遲(3000);
NTP 客戶端使用begin()函數(shù)初始化,以從 NTP 服務器設置日期和時間。
timeClient.begin();
Update()函數(shù)用于在我們向 NTP 服務器請求時接收日期和時間。
timeClient.update();
波特率設置為 115200 以在串行監(jiān)視器上打印時間。
序列號.開始(115200); Serial.println(timeClient.getFormattedTime());
getHours()、getMinutes()、getSeconds()、getDay是庫函數(shù),并從 NTP 服務器提供當前的小時、分鐘、秒和天。下面的代碼用于區(qū)分 AM 和 PM 之間的時間。如果我們使用getHours()獲得的小時數(shù)大于 12,那么我們將該時間設置為 PM,否則設置為 AM。
int hh = timeClient.getHours(); int mm = timeClient.getMinutes(); int ss = timeClient.getSeconds(); int day = timeClient.getDay(); 如果(hh>12) { hh=hh-12; 顯示.打?。╤h); display.print(":"); 顯示.打印(毫米); display.print(":"); 顯示.打印(ss); display.println("PM"); } 其他 { display.print(hh); display.print(":"); 顯示.打印(毫米); display.print(":"); 顯示.打印(ss); display.println("AM"); } int day = timeClient.getDay(); display.println("'"+arr_days[天]+"'");
getFormattedDate()用于從 NTP 服務器獲取“yyyy-mm-dd”格式的日期。此函數(shù)以“yyyy-mm-dd T hh:mm:ss格式給出日期和時間。但是我們只需要日期,因此我們必須將這個以date_time格式存儲的字符串拆分為由substring()函數(shù)完成的“T”,然后將日期存儲在“date”變量中。
date_time = timeClient.getFormattedDate(); int index_date = date_time.indexOf("T"); 字符串日期 = date_time.substring(0, index_date); 序列號.println(日期); display.println(日期); 顯示.顯示();
這就是OLED 互聯(lián)網(wǎng)時鐘最終的樣子:
#include
#include
#include
#include
#include
#include
#define SCREEN_WIDTH 128 // OLED 顯示寬度,以像素為單位
#define SCREEN_HEIGHT 64 // OLED 顯示高度,以像素為單位
// 使用軟件 SPI 連接的 SSD1306 顯示器的聲明(默認情況):
#define OLED_MOSI D7
#define OLED_CLK D5
#define OLED_DC D2
#define OLED_CS D8
#define OLED_RESET D3
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
const char *ssid = "CircuitLoop";
const char *password = "circuitdigest101";
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 19800,60000);
字符串 arr_days[]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
字符串日期時間;
// 您可以指定時間服務器池和偏移量(以秒為單位,
// 稍后可以使用 setTimeOffset() 更改)。另外,您可以指定
// 更新間隔(以毫秒為單位,可以使用 setUpdateInterval() 更改)。
無效設置(){
Serial.begin(115200);
WiFi.begin(ssid, 密碼);
而(WiFi.status()!= WL_CONNECTED){
延遲(500);
Serial.print(".");
}
if(!display.begin(SSD1306_SWITCHCAPVCC))
{
Serial.println(F("SSD1306 分配失敗"));
為了(;;); // 不要繼續(xù),永遠循環(huán)
}
display.clearDisplay();
display.setTextSize(2); // 繪制 2X 比例的文本
display.setTextColor(WHITE);
display.setCursor(5, 2);
display.println("歡迎來到");
display.println("電路");
display.println("摘要");
顯示.顯示();
延遲(3000);
timeClient.begin();
}
無效循環(huán)(){
timeClient.update();
display.clearDisplay();
Serial.println(timeClient.getFormattedTime());
display.setTextSize(2); // 繪制 2X 比例的文本
display.setTextColor(BLUE);
display.setCursor(0, 2);
int hh = timeClient.getHours();
int mm = timeClient.getMinutes();
int ss = timeClient.getSeconds();
如果(hh>12)
{
hh=hh-12;
顯示.打?。╤h);
display.print(":");
顯示.打?。ê撩祝?;
display.print(":");
顯示.打印(ss);
display.println("PM");
}
其他
{
display.print(hh);
display.print(":");
顯示.打?。ê撩祝?br />
display.print(":");
顯示.打?。╯s);
display.println("AM");
}
int day = timeClient.getDay();
display.println("'"+arr_days[天]+"'");
date_time = timeClient.getFormattedDate();
int index_date = date_time.indexOf("T");
字符串日期 = date_time.substring(0, index_date);
序列號.println(日期);
display.println(日期);
顯示.顯示();// 顯示初始文本
}
-
OLED
+關注
關注
119文章
6213瀏覽量
224497 -
NTP
+關注
關注
1文章
174瀏覽量
13932 -
ESP8266
+關注
關注
50文章
962瀏覽量
45177
發(fā)布評論請先 登錄
相關推薦
評論