ESP8266是一款功能强大的物联网芯片,广泛应用于智能家居、远程控制和其他嵌入式系统中。在许多实际应用中,获取准确的时间是非常重要的,例如日志记录、定时任务调度等。通过NTP(网络时间协议),我们可以让ESP8266设备从互联网上同步时间。
下面我们将详细介绍如何使用ESP8266实现NTP时间同步,并获取网络时间。
NTP是一种用于通过计算机网络同步时钟的协议。它通常使用UDP协议在端口123上进行通信。NTP客户端向服务器发送请求,服务器返回当前时间戳。客户端根据这个时间戳调整本地时间。
ESP8266可以作为NTP客户端,连接到公共NTP服务器(如pool.ntp.org
)以获取标准时间。
首先需要让ESP8266连接到WiFi网络,这是获取网络时间的前提条件。
#include <ESP8266WiFi.h>
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
接下来,我们需要编写代码来实现NTP时间同步。这里我们使用UDP协议直接与NTP服务器通信。
#include <WiFiUdp.h>
unsigned int localPort = 2390; // local port to listen for UDP packets
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "pool.ntp.org";
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
WiFiUDP udp;
void sendNTPpacket(IPAddress& address) {
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
packetBuffer[0] = 0b11100011; // LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
packetBuffer[1] = 0;
packetBuffer[2] = 6;
packetBuffer[3] = 0xEC;
// all NTP fields have been initialized, now you can send a packet requesting a timestamp:
udp.beginPacket(address, 123); //NTP requests are to port 123
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();
}
time_t getNtpTime() {
IPAddress ntpServerIP;
if (WiFi.hostByName(ntpServerName, ntpServerIP)) {
Serial.println("NTP server IP: " + ntpServerIP.toString());
} else {
Serial.println("Error resolving NTP server name");
return 0;
}
udp.begin(localPort);
sendNTPpacket(ntpServerIP);
uint32_t beginWait = millis();
while (millis() - beginWait < 1500) {
int size = udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
udp.read(packetBuffer, NTP_PACKET_SIZE);
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
unsigned long secsSince1900 = highWord << 16 | lowWord;
const unsigned long seventyYears = 2208988800UL;
unsigned long epoch = secsSince1900 - seventyYears;
return epoch;
}
}
Serial.println("No NTP response :-(");
return 0;
}
将上述功能整合到主程序中:
void setup() {
Serial.begin(115200);
setup_wifi();
Serial.println("Starting UDP");
udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(udp.localPort());
time_t t = getNtpTime();
if (t) {
struct tm *ptm = gmtime(&t);
Serial.print(ptm->tm_year + 1900);
Serial.print("/");
Serial.print(ptm->tm_mon + 1);
Serial.print("/");
Serial.print(ptm->tm_mday);
Serial.print(" ");
Serial.print(ptm->tm_hour);
Serial.print(":");
Serial.print(ptm->tm_min);
Serial.print(":");
Serial.println(ptm->tm_sec);
}
}
void loop() {
// Your application logic here
}