使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

描述

  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 显示器上。

ESP8266

  ESP8266 可以使用互联网访问 NTP 服务器以获取准确的时间。这里 NTP 工作在客户端-服务器模式,ESP8266 作为客户端设备使用 UDP(用户数据报协议)与NTP 服务器连接。客户端向 NTP 服务器发送一个请求包,然后 NTP 发送一个时间戳包,其中包含准确度、时区、UNIX 时间戳等信息。然后客户端将日期和时间详细信息分离出来,可以根据需要在应用程序中进一步使用。

  所需组件

  单色 7 针 SSD1306 0.96” OLED 显示屏

  ESP8266 NodeMCU

  微型 USB 数据线

  面包板

  公对公跳线

  电路图和连接

  这款 7 针 OLED 显示器使用 SPI 协议与 ESP8266 模块通信,下面是连接 OLED SPI 针与 NodeMCU 以显示互联网时间的电路图和连接表。

ESP8266

ESP8266

  代码说明

  首先,我们必须将 NTP 库下载并安装到 ESP8266 中。有许多可用于 NTP 客户端的库。您可以从 Arduino IDE 安装其中的任何一个。在本教程中,我安装了Taranais 的 NTPClient 库,因为它易于使用并且具有从 NTP 服务器获取日期和时间的功能。

ESP8266

  要安装 NTP 库,首先使用上面的链接下载库,然后使用 Arduino IDE 安装它。要安装它,请转到Sketch 》 Include Library 》 Add .ZIP Library,然后通过转到您下载 zip 文件夹的位置打开 Zip 文件夹并重新启动 Arduino IDE。

ESP8266

ESP8266

  NTPClient 库附带示例。打开 Arduino IDE 并转到示例 》 NTPClient 》 高级。此草图中给出的代码在串行监视器上显示来自 NTP 服务器的时间。我们将使用此草图在 OLED 显示屏上显示当前时间和日期。

ESP8266

  本教程末尾提供了完整的代码,这里我解释了代码的几个重要部分。

ESP8266WiFi 库提供 ESP8266 特定的 Wi-Fi 例程以连接到网络。WiFiUDP.h处理发送和接收 UDP 包。由于我们使用 SPI 协议将 OLED 与 NodeMCU 连接,因此我们将导入“SPI.h”库。而“Adafruit_GFX.h”和“Adafruit_SSD1306.h”用于OLED显示。

 

#include  
#include  // 提供我们调用的 ESP8266 特定 Wi-Fi 例程以连接到网络
#include  // 处理 UDP 包的发送和接收
#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函数提供 SSID 和密码来设置 WI-Fi 连接。ESP8266 的连接需要一些时间才能连接到 NodeMCU,所以我们必须等到它连接上。

 

WiFi.begin(ssid, 密码); 
  而(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。

ESP8266

  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); // 绘制 2X 比例的文本
  display.setTextColor(BLUE); 
  display.setCursor(5, 2); 
  display.println("欢迎来到"); 
  display.println("电路"); 
  display.println("摘要"); 
  显示.显示();
  延迟(3000);

 

NTP 客户端使用begin()函数初始化  ,以从 NTP 服务器设置日期和时间。

 

timeClient.begin();

 

Update()函数用于在我们向 NTP 服务器请求时接收日期和时间。

 

timeClient.update();

 

波特率设置为 115200 以在串行监视器上打印时间。

 

序列号.开始(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 day = timeClient.getDay();

如果(hh>12)
  { 
    hh=hh-12; 
    显示.打印(hh);
    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”格式的日期。此函数以“yyyy-mm-dd T hh:mm:ss格式给出日期和时间。但是我们只需要日期,因此我们必须将这个以date_time格式存储的字符串拆分为由substring()函数完成的“T”,然后将日期存储在“date”变量中。

 

date_time = timeClient.getFormattedDate(); 
  int index_date = date_time.indexOf("T"); 
  字符串日期 = date_time.substring(0, index_date); 
  序列号.println(日期); 
  display.println(日期); 
  显示.显示();     

 

  这就是OLED 互联网时钟最终的样子:

ESP8266

#include

#include // 提供我们调用的 ESP8266 特定 Wi-Fi 例程以连接到网络

#include // 处理 UDP 包的发送和接收

#include // 用于将 OLED 与 NodeMCU 连接的 SPI

#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 分配失败"));

为了(;;); // 不要继续,永远循环

}

display.clearDisplay();

display.setTextSize(2); // 绘制 2X 比例的文本

display.setTextColor(WHITE);

display.setCursor(5, 2);

display.println("欢迎来到");

display.println("电路");

display.println("摘要");

显示.显示();

延迟(3000);

timeClient.begin();

}


无效循环(){

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;

显示.打印(hh);

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[天]+"'");



date_time = timeClient.getFormattedDate();

int index_date = date_time.indexOf("T");

字符串日期 = date_time.substring(0, index_date);

序列号.println(日期);

display.println(日期);

显示.显示();// 显示初始文本

}
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
tqfenghanjietq 2023-04-03
0 回复 举报
看到的代码有的被翻译成中文了,反过来就不晓得准确的了。 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分