RTC或实时时钟是电子产品和嵌入式设备中最常用的模块,用于跟踪时间。但是RTC的问题在于计算机中的微芯片不是那么精确,它们只能提供本地设备的时间。另一方面,使用互联网从NTP服务器获取时间是获取时间的更好解决方案,因为它更准确,并且可以提供世界任何地理区域的时间。我们只需要一个Wi-Fi模块即可访问互联网,即可使用NTP服务器获取世界上任何位置的时间。在本教程中,我们将使用ESP8266 NodeMCU从NTP服务器获取当前时间和日期,并将其显示在OLED显示屏上。
网络时间协议(NTP)
NTP是最早的联网Internet协议(IP)之一,用于在计算机网络之间同步时钟。它是由特拉华大学的David L. Mills于1981年设计的。此协议可用于在几毫秒内将许多网络同步到协调世界时(UTC)。 UTC是世界调节时钟和时间的主要时间标准。 UTC不会更改,并且会随地理位置的不同而不同。 NTP使用UTC作为时间参考,并在Internet上提供准确且同步的时间。
NTP在分层的客户端-服务器模型上工作。顶级型号具有称为“ stratum0”的参考时钟,例如原子钟,无线电波,GPS,GSM,它们从卫星接收时间。从stratum0接收时间的服务器称为“ stratum1”,从stratum1接收时间的服务器称为“ stratum2”,依此类推。在每个阶段之后,这都会继续,时间的准确性会继续降低。NTP自动选择几个可用时间源中的最佳者进行同步,从而使其成为具有容错能力的协议。
因此,在此项目中,我们使用ESP8266 NodeMCU从NTP服务器获取时间,并将其显示在OLED显示屏上。上一教程中使用ESP32来构建这种互联网时钟。
ESP8266可以通过互联网访问NTP服务器,以获取准确的时间。此处NTP工作在客户端-服务器模式,ESP8266用作客户端设备,并使用UDP(用户数据报协议)与NTP服务器连接。客户端向NTP服务器发送一个请求数据包,然后NTP发送一个时间戳数据包,其中包含诸如准确性,时区,UNIX时间戳等信息。然后,客户端将日期和时间详细信息分开,可以根据需要在应用程序中进一步使用。
所需组件
- 单色7针SSD1306 0.96英寸OLED显示屏
- ESP8266 NodeMCU
- 微型USB电缆
- 面包板
- 公对公跳线
电路图和连接
该7针OLED显示器使用SPI协议与ESP8266模块通信,以下是将OLED SPI引脚与NodeMCU连接以显示互联网时间的电路图和连接表。
没有。 |
OLED显示器 |
NodeMCU |
1个 |
地线 |
地线 |
2 |
VDD |
3.3伏 |
3 |
SCK |
D5 |
4 |
MOSI(SPI)或SDA(I2C) |
D7 |
5 |
重启 |
D3 |
6 |
直流电 |
D2 |
7 |
CS |
D8 |
要了解更多此单色7针OLED显示屏及其与ESP8266 NodeMCU的接口的更多信息,请点击链接。
代码说明
首先我们必须下载NTP库并将其安装到ESP8266中。有许多可用于NTP客户端的库。您可以从Arduino IDE安装其中的任何一个。在本教程中,我已经安装了Taranais的NTPClient库,因为它易于使用并且具有从NTP服务器获取日期和时间的功能。ESP8266 NodeMCU可以使用Arduino IDE轻松编程。
要安装NTP库,请首先使用上面的链接下载该库,然后使用Arduino IDE安装它。要安装它,请转到 草图>包含库>添加.ZIP库 ,然后通过转到下载zip文件夹的位置打开Zip文件夹,然后重新启动Arduino IDE。
NTPClient库附带示例。打开Arduino IDE并 转到示例> NTPClient>高级 。此草图中给出的代码在串行监视器上显示来自NTP服务器的时间。我们将使用此草图在OLED显示屏上显示当前时间和日期。
本教程末尾提供了完整的代码,在这里我解释了代码的几个重要部分。
ESP8266WiFi库提供了ESP8266特定的Wi-Fi例程以连接到网络。WiFiUDP.h处理发送和接收UDP包。由于我们使用SPI协议将OLED与NodeMCU接口,因此我们将导入“ SPI.h”库。OLED显示使用“ Adafruit_GFX.h”和“ Adafruit_SSD1306.h”。
#包括
我们的OLED尺寸为128x64,因此我们将屏幕的宽度和高度分别设置为128和64。因此,请定义用于SPI通信的连接到NodeMCU的OLED引脚的变量。
#define SCREEN_WIDTH 128 // OLED显示宽度,以像素为单位 #define SCREEN_HEIGHT 64 // OLED显示高度,以像素 为 单位//使用软件SPI连接的SSD1306显示的声明(默认情况):#define OLED_MOSI D7 #define OLED_CLK D5 #define OLED_DC D2 #定义OLED_CS D8 #定义OLED_RESET D3
Adafruit_SSD1306显示屏(SCREEN_WIDTH,SCREEN_HEIGHT,OLED_MOSI,OLED_CLK,OLED_DC,OLED_RESET,OLED_CS);
在下面的代码行中,用您的Wi-Fi SSID和密码替换“ your_ssid”和“ your_password”。
const char * ssid =“ your_ssid”; const char * password =“ your_password”;
通过将SSID和密码提供给 WiFi.begin 功能来设置WI-Fi连接。ESP8266的连接需要一些时间才能连接到NodeMCU,因此我们必须等到它连接起来。
WiFi.begin(ssid,密码); while(WiFi.status()!= WL_CONNECTED){ 延迟(500); Serial.print(“。”); }
要请求日期和时间,请使用NTP服务器的地址初始化时间客户端。为了获得更高的准确性,请选择靠近您的地理区域的NTP服务器的地址。在这里,我们使用“ pool.ntp.org ”来提供来自全球的服务器。如果您希望从亚洲选择服务器,则可以使用“ asia.pool.ntp.org ”。 timeClient 还采用UTC时间偏移量(以您的时区为单位)。例如,印度的UTC偏移量为+5:30,因此我们以毫秒为单位转换此偏移量,等于5 * 60 * 60 + 30 * 60 = 19800。
区 |
UTC时间偏移(小时和分钟) |
UTC时间偏移(秒) |
印度 |
+5:30 |
19800 |
伦敦 |
0:00 |
0 |
纽约 |
-5:00 |
-18000 |
WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP,“ pool.ntp.org”,19800,60000);
SSD1306_SWITCHCAPVCC 可以在内部产生3.3V 电压 以初始化显示。当OLED启动时,它会显示“ WELCOME TO CIRCUIT DIGEST ”,文字大小为2,蓝色为3秒钟。
if(!display.begin(SSD1306_SWITCHCAPVCC)) { Serial.println(F(“ SSD1306分配失败”)); 对于(;;); //不要继续,永远循环 } display.clearDisplay(); display.setTextSize(2); //绘制2倍比例缩放的文本 display.setTextColor(BLUE); display.setCursor(5,2); display.println(“ WELCOME TO”); display.println(“ CIRCUIT”); display.println(“ DIGEST”); display.display(); 延迟(3000);
使用 begin() 函数初始化NTP客户端, 以设置NTP服务器的日期和时间。
timeClient.begin();
每当我们向NTP服务器请求时, Update() 函数用于接收日期和时间。
timeClient.update();
波特率设置为115200以在串行监视器上打印时间。
Serial.begin(115200); Serial.println(timeClient.getFormattedTime());
getHours(),getMinutes(),getSeconds(),getDay 是库函数,并提供来自NTP服务器的当前小时,分钟,秒和天。以下代码用于区分AM和PM之间的时间。如果使用 getHours() 的小时数大于12,则将该时间设置为PM,否则设置为AM。
int hh = timeClient.getHours(); int mm = timeClient.getMinutes(); int ss = timeClient.getSeconds(); int天= timeClient.getDay(); if(hh> 12) { hh = hh-12; display.print(hh); display.print(“:”); display.print(mm); display.print(“:”); display.print(ss); display.println(“ PM”); } else { display.print(hh); display.print(“:”); display.print(mm); display.print(“:”); display.print(ss); display.println(“ AM”); } int day = timeClient.getDay(); display.println(“'” + arr_days +“'”);
getFormattedDate() 用于从NTP服务器获取 “ yyyy-mm-dd” 格式的日期。此功能以 “ yyyy-mm-dd T hh:mm:ss” 格式给出日期和时间。但是我们只需要日期,因此我们必须将以 date_time 格式存储的字符串拆分为“ T” ( 由 substring() 函数完成 ) ,然后将日期存储在 “ date” 变量中。
date_time = timeClient.getFormattedDate(); int index_date = date_time.indexOf(“ T”); 字符串日期= date_time.substring(0,index_date); Serial.println(date); display.println(date); display.display();
这就是OLED互联网时钟最终的外观: