本帖最后由 AllBlue 于 2017-10-6 09:02 编辑
ESP8266 ntp网络时钟 永不校时时钟首先我们认识下NTP是什么?
NTP,Network Time Protocol,网络时间协议;它是用来使网络中的各个计算机时间同步的一种协议。它的用途是把计算机的时钟同步到世界协调时UTC,其精度在局域网内可达0.1ms,在互联网上绝大多数的地方其精度可以达到1-50ms。原理(看了上面的NTP介绍,原理就很简单了):
ESP8266连接到network,并获取NTP(Network Time Protocol,网络时间协议)。
提供NTP服务的有很多,windows系统就有自动更新时间,其实就是windows公司提供的NTP服务,根据下图找到window NTP服务器:
从图中可以看到有5个服务器支持:time.windows.com 、time.nist.gov 、time-nw.nist.gov 、time-a.nist.gov 、time-b.nist.gov。
你可以点击“立即更新”按钮试试看是否可以正常工作。
下面是测试例程,使用的是ESP8266 模块,arduino IDE开发):
[C] 纯文本查看 复制代码 /*
NTP Clock Program -- 网络时钟
Network Time Protocol (NTP)
ESP8266 连接到NET WORK ,获取NTP
[url=https://github.com/PaulStoffregen/Time]https://github.com/PaulStoffregen/Time[/url]
[url=https://github.com/JChristensen/Timezone]https://github.com/JChristensen/Timezone[/url]
by: yfrobot
[url=http://www.yfrobot.com]http://www.yfrobot.com[/url]
*/
#include <ESP8266WiFi.h>
#include <Time.h>
#include <Timezone.h>
#include "NTP.h"
// Set your WiFi login credentials
#define WIFI_SSID "YFROBOT" // 使用时请修改为当前你的 wifi ssid
#define WIFI_PASS "yfrobot2016" // 使用时请修改为当前你的 wifi 密码
#define ledPin 14 // 定义ledPin连接到GPIO14
// This clock is in the Mountain Time Zone
// Change this for your timezone
// 北京时间时区
#define STD_TIMEZONE_OFFSET +8 // Standard Time offset (-7 is mountain time)
// ***************************************************************
// TimeZone and Daylight Savings Time Rules
// ***************************************************************
// Define daylight savings time rules for the China
TimeChangeRule mySTD = {"", First, Sun, Jan, 0, STD_TIMEZONE_OFFSET * 60};
Timezone myTZ(mySTD, mySTD);
WiFiClient client;
// This function is called once a second
void updateDisplay(void) {
TimeChangeRule *tcr; // Pointer to the time change rule
// Read the current UTC time from the NTP provider
time_t utc = now();
// Convert to local time taking DST into consideration
time_t localTime = myTZ.toLocal(utc, &tcr);
// Map time to pixel positions
int weekdays= weekday(localTime);
int days = day(localTime);
int months = month(localTime);
int years = year(localTime);
int seconds = second(localTime);
int minutes = minute(localTime);
int hours = hour(localTime) ; //12 hour format use : hourFormat12(localTime) isPM()/isAM()
Serial.println("");
Serial.print("Current local time:");
Serial.print(days);
Serial.print("/");
Serial.print(months);
Serial.print("/");
Serial.print(years);
Serial.print(" - ");
Serial.print(hours);
Serial.print(":");
Serial.print(minutes);
Serial.print(":");
Serial.print(seconds);
Serial.print(" - ");
Serial.print(dayStr(weekdays));
Serial.println("");
}
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
delay(10);
// We start by connecting to a WiFi network
initNTP(WIFI_SSID, WIFI_PASS);
}
// Previous seconds value
time_t previousSecond = 0;
void loop() {
// Update the display only if time has changed
if (timeStatus() != timeNotSet) {
if (second() != previousSecond) {
previousSecond = second();
// Update the display
updateDisplay();
}
}
delay(1000);
}
NTP.h 文件:
[C] 纯文本查看 复制代码 /*
ESP8266 NeoPixel NTP Clock Program
NTP.h - Network Time Protocol Functions
Portions of this code were extracted from the
Time library examples by Michael Margolis and
Paul Stoffregen. Other portions from the NTPClient
example program from the Arduino ESP8266 package.
Concept, Design and Implementation by: Craig A. Lindley
Last Update: 04/12/2016
*/
#ifndef NTP_H
#define NTP_H
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <TimeLib.h>
#include <WiFiUdp.h>
#define LOCALPORT 5000 // Local port to listen for UDP packets
#define NTP_PACKET_SIZE 48 // NTP time stamp is in the first 48 bytes of the message
// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;
byte packetBuffer[NTP_PACKET_SIZE]; // Buffer to hold incoming and outgoing packets
// Don't hardwire the IP address or we won't get the benefits of the time server pool.
const char *ntpServerName ;//= "time.windows.com";//"1.cn.pool.ntp.org";
IPAddress timeServerIP(183,230,40,42); //ONENET -- NTP
// Send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address) {
// Set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// All NTP fields have been given values, 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();
}
// NTP Time Provider Code
time_t getNTPTime() {
int attempts = 10;
// Try multiple attempts to return the NTP time
while (attempts--) {
// Get a server from the pool
if(ntpServerName != NULL){
WiFi.hostByName(ntpServerName, timeServerIP);
}
Serial.printf("Time server IP address: ");
Serial.println(timeServerIP);
while (udp.parsePacket() > 0); // Discard any previously received packets
Serial.println("Transmitted NTP Request");
sendNTPpacket(timeServerIP);
uint32_t beginWait = millis();
while (millis() - beginWait < 1500) {
int size = udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println("Received NTP Response");
udp.read(packetBuffer, NTP_PACKET_SIZE); // Read packet into the buffer
unsigned long secsSince1900;
// Convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long) packetBuffer[40] << 24;
secsSince1900 |= (unsigned long) packetBuffer[41] << 16;
secsSince1900 |= (unsigned long) packetBuffer[42] << 8;
secsSince1900 |= (unsigned long) packetBuffer[43];
Serial.println("Got the time");
return secsSince1900 - 2208988800UL;
}
delay(10);
}
Serial.println("Retrying NTP request");
delay(4000);
}
Serial.println("No NTP Response");
return 0;
}
// Login to WiFi network and assign the time sync provider
void initNTP(const char *ssid, const char *password) {
// Set station mode
WiFi.mode(WIFI_STA); //set work mode: WIFI_AP /WIFI_STA /WIFI_AP_STA
// Start by connecting to a WiFi network
WiFi.begin(ssid, password);
int i = 0;
while ((WiFi.status() != WL_CONNECTED) && (i++ < 30)) {
delay(500);
Serial.printf(".");
}
if (i == 31) {
Serial.printf("\nCould not connect to: %s\n", ssid);
return;
}
Serial.printf("\nConnected to: %s\n", ssid);
delay(500);
// Login suceeded so set UDP local port
udp.begin(LOCALPORT);
// Set the time provider to NTP
setSyncProvider(getNTPTime);
}
#endif
程序下载:github 项目地址:https://github.com/YFROBOT-TM/YFRobot-NTPClock_OneNet
该例程中使用的是ONENET的NTP服务,服务器IP和端口号:183.230.40.42:80。测试可用!
想要使用上面提到的window NTP,定义NTP.h文件中的ntpServerName,像下面这样:
[C] 纯文本查看 复制代码
const char *ntpServerName = "time.windows.com"; //"1.cn.pool.ntp.org" 串口打印:
时区更改,在NTPClick.ino中,定义STD_TIMEZONE_OFFSET :
[C++] 纯文本查看 复制代码 #define STD_TIMEZONE_OFFSET +8
世界时区分布图:
库文件下载地址:
|