设为首页收藏本站

arduino 单片机机器人爱好者之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 7515|回复: 48

ESP8266 wifi 网络时钟(精准免校时时钟) NTP网络时间协议 OneNet NTP服务

  [复制链接]

签到天数: 510 天

[LV.9]以坛为家II

发表于 2016-9-12 14:29:50 | 显示全部楼层 |阅读模式
本帖最后由 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服务器: windowsNTP.jpg 从图中可以看到有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"
串口打印:
NTP time.png
时区更改,在NTPClick.ino中,定义STD_TIMEZONE_OFFSET
[C++] 纯文本查看 复制代码
#define STD_TIMEZONE_OFFSET +8  

世界时区分布图:
time-zone-offset.png


库文件下载地址:


该用户从未签到

发表于 2016-10-1 20:51:03 | 显示全部楼层
感谢分享,学习
回复 支持 反对

使用道具 举报

签到天数: 2 天

[LV.1]初来乍到

发表于 2016-10-6 10:41:24 | 显示全部楼层
能说你的东西不好不,先标记个。
回复 支持 反对

使用道具 举报

签到天数: 1 天

[LV.1]初来乍到

发表于 2016-10-23 23:23:24 | 显示全部楼层
谢楼主分享。。。。。。。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2016-11-12 00:09:45 | 显示全部楼层
这个东西太好了,一直想找呢,LUA的容易,arduino的太少了。。。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2016-11-12 00:35:46 | 显示全部楼层
经测试,无法编译。。。不知道是H文件存档目录的问题还是啥。。。楼主能细说以下么。。
回复 支持 反对

使用道具 举报

签到天数: 510 天

[LV.9]以坛为家II

 楼主| 发表于 2016-11-12 08:57:25 | 显示全部楼层
squallwsx 发表于 2016-11-12 00:35
经测试,无法编译。。。不知道是H文件存档目录的问题还是啥。。。楼主能细说以下么。。

有截图错误截图吗?库文件是否添加进去了
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2016-11-12 10:49:42 | 显示全部楼层
AllBlue 发表于 2016-11-12 08:57
有截图错误截图吗?库文件是否添加进去了

无标题.jpg

如图,就错误应该是H头文件没有加载到的样子。但是我是有好好的把Time.h和Timezone.h都放arduino\libraries里各自建立的同文件名的文件夹里面的。。。另,为何NTP.h加载用的是引号,这个文件我也一样放到libraries里新建同文件名的文件夹或者和ino放一起都试过,还是不行。。。
回复 支持 反对

使用道具 举报

签到天数: 510 天

[LV.9]以坛为家II

 楼主| 发表于 2016-11-12 16:32:05 | 显示全部楼层
squallwsx 发表于 2016-11-12 10:49
如图,就错误应该是H头文件没有加载到的样子。但是我是有好好的把Time.h和Timezone.h都放arduino\lib ...

Time 和Timezone 都是库,不单单是 time.h文件就够的,需要将整个库文件下载放到libraries 文件夹中,NTP.h文件不需要放到库文件中,和主程序放在一个文件夹中即可随主程序打开!Q2912630748 不行就联系
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|联系我们|YFRobot ( 苏ICP备13017135  

GMT+8, 2017-11-22 11:36 , Processed in 0.133704 second(s), 27 queries .

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表