NodeMCU(ESP8266)获取NTP时间

NodeMCU(ESP8266)获取NTP时间

很久没有搞ESP8266了,可能是这两年工作太忙了,又或者是对生活失去了斗志,所以最近又重新把两年前的东西重新收拾收拾。

NTP协议

我之前有写一篇NTP 入门介绍,大家如果有对NTP不了解的,可以先查阅这篇《NTP 入门介绍

为啥要同步时间

之前看到有一个用户通过esp8266做了一个时钟出来( ESP8266物联网创意点阵时钟,女朋友看了都想要!
),自己也想搞一个类似的,然后就发现他有一个功能就是网络自动校准时间,才了解到有NTP这个协议的存在,所以就找到一些代码研究了一番,所以就有了今天这篇博文。

实现思路

esp8266感觉是一个很简单的东西,网上有很多的代码示例,这里我更推荐使用官方的示例库。

如何从官方的示例库中找到我们要用的示例代码:

  • net-client-demo
2.png
1.png

代码

根据上述的示例和其他用户分享的库文件使用方法,我们稍微整理一下,把代码改成我们想要的样子。

  1. 先连接wifi
  2. 判断时间是否是正确的,如果不正确就去同步时间
  3. 如果时间正确就每秒中增加我们的时钟信息,顺便打印出来

上代码

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Ticker.h>

#ifndef STASSID
#define STASSID "你的WiFi名称"
#define STAPSK  "你的WiFi密码"
#endif

const char * ssid = STASSID;
const char * pass = STAPSK;
// 定义时分秒
unsigned int h = 99, m = 99, s = 99;
// 监听本地UDP数据包端口
unsigned int localPort = 2390;
// NTP服务器IP地址
IPAddress timeServerIP;
// NTP服务器网址
const char* ntpServerName = "time.windows.com";
// NTP数据包数据长度
const int NTP_PACKET_SIZE = 48;

byte packetBuffer[ NTP_PACKET_SIZE];

WiFiUDP udp;
// 创建一个需要定时调度的对象
Ticker ticker;

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.print("连接wifi中 ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");

  Serial.println("WiFi已连接");
  Serial.println("设备IP地址: ");
  Serial.println(WiFi.localIP());

  Serial.println("开启UDP通信");
  udp.begin(localPort);
  Serial.print("本地端口为: ");
  Serial.println(udp.localPort());
}

void loop() {
  //get a random server from the pool
  WiFi.hostByName(ntpServerName, timeServerIP);
  if (h == 99 || m == 99 || s == 99) {
    sendNTPpacket(timeServerIP); // send an NTP packet to a time server
    // 等一秒后获取结果
    delay(1000);
    setTimes();
    // 设置定时累加时间操作
    ticker.attach(1, addtime);
  }
}


/**
   累加时间
*/
void addtime() {
  if (s == 59) {
    s = 0;
    if (m == 59) {
      m = 0;
      if (h == 23) {
        h = 0;
      } else {
        h++;
      }
    } else {
      m++;
    }
  } else {
    s++;
  }
  Serial.print("当前时间为: ");
  Serial.print(h);
  Serial.print(":");
  Serial.print(m);
  Serial.print(":");
  Serial.println(s);
}

/**
   获取十分秒信息
*/
void setTimes() {
  //解析Udp数据包
  int cb = udp.parsePacket();
  if (!cb) {
    //解析包为空
    Serial.println("没有接收到任何的数据包!");
  } else {
    //解析包不为空
    Serial.print("接收到的数据包的长度为: ");
    Serial.println(cb);
    // 解析UDP数据包中的数据
    udp.read(packetBuffer, NTP_PACKET_SIZE);
    // 说明 todo这里获取到的时间其实不是真实的时间,实际上还包含了网络延时的,但是为了方便,这里我们忽略这个因素的存在
    // 取出t2时间的高位和低位数据拼凑成以秒为单位的时间戳
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // 拼凑成以秒为单位的时间戳(时间戳的记录以秒的形式从 1900-01-01 00:00:00 算起)
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    Serial.print("1900年格式标准的时间戳为:");
    Serial.println(secsSince1900);
    // 前面的32bit是时间戳的秒数(是用1900-01-01 00:00:00开始的秒数,但是我们的是1970年,所以需要减掉2208988800秒)
    const unsigned long seventyYears = 2208988800UL;
    unsigned long epoch = secsSince1900 - seventyYears;
    Serial.print("1970年格式标准的时间戳为:");
    Serial.println(epoch);

    // 这里加8 是因为时区的问题,如果不加8,得到的结果就会是其他时区的时间
    h =  (epoch  % 86400L) / 3600 + 8;
    m = (epoch % 3600) / 60;
    s = epoch % 60;
  }
}

/**
   发送ntp协议数据包
*/
void sendNTPpacket(IPAddress& address) {
  Serial.println("发送ntp数据包...");
  // 将字节数组的数据全部设置为0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // 请求部分其实是有很多数据的,具体的请看参考请求报文说明,这里我们就只设置一个请求头部分即可
  packetBuffer[0] = 0b11100011;
  // 配置远端ip地址和端口
  udp.beginPacket(address, 123);
  // 把数据写入发送缓冲区
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  // 发送数据
  udp.endPacket();
}

效果图

3.png

参考文章

ESP8266物联网创意点阵时钟,女朋友看了都想要!
从零开始的ESP8266探索(11)-定时任务调度器Ticker使用演示
ESP8266 – WiFiUDP库

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容