SNTP基本知识

1、定义
SNTP是简单网络时间协议,而NTP网络时间协议就是网络计算机上同步计算时间的协议,具有高度的精确性,实际上也用不到这么高精度的算法。所以就在NTP上简化了以下变成SNTP,SNTP协议主要被用来同步因特网上计算机的时间。
2、工作方式
SNTP采用客户端/服务器的工作方式,可以采用单播或者广播的模式。
单播即客户端定期直接与SNTP服务器交互获取时间差进行校时。广播则是SNTP服务器定期向指定的多播地址发送时间信息,SNTP客户端通过监听这些多播地址来获取时间信息进行同步。UNIX网络编程中有SNTP广播方式的部分实现代码。
3、SNTP校时原理
SNTP协议主要是通过记录客户端向服务器发送数据包时的时间戳t1,服务器端接收到该数据包时的时间戳t2,服务器向客户端回应时的时间戳t3和最后客户端接收到服务器回应时的时间戳t4来计算客户端时间和服务器端时间的偏差,从而进行校时操作,如下图所示:

则t1与t2之间的时间差为((T2-T1)+ (T3-T4))/2
数据包在网络上的传播时间是 (T2-T1) + (T4-T3)

SNTP接口

1、sntp_setserver
功能:通过 IP 地址设置 SNTP 服务器,⼀共最多⽀持设置 3 个 SNTP 服务器
函数定义:void sntp_setserver(unsigned char idx, ip_addr_t *addr)
参数:
unsigned char idx:SNTP 服务器编号,最多⽀持 3 个 SNTP 服务器(0 ~ 2);0 号为主服务器,1 号和 2 号为备⽤服务器。
ip_addr_t *addr:IP 地址;⽤户需⾃⾏确保,传⼊的是合法 SNTP 服务器
返回:⽆
2、sntp_getserver
功能:查询 SNTP 服务器的 IP 地址,对应的设置接⼝为:sntp_setserver
函数定义: ip_addr_t sntp_getserver(unsigned char idx)
参数: unsigned char idx:SNTP 服务器编号,最多⽀持 3 个 SNTP 服务器(0 ~ 2)
返回:IP 地址
3、sntp_setservername
功能:通过域名设置 SNTP 服务器,⼀共最多⽀持设置 3 个 SNTP 服务器
函数定义:void sntp_setservername(unsigned char idx, char *server)
参数
unsigned char idx:SNTP 服务器编号,最多⽀持 3 个 SNTP 服务器(0 ~ 2);0 号为主服务器,1 号和 2 号为备⽤服务器。
char *server:域名;⽤户需⾃⾏确保,传⼊的是合法 SNTP 服务器
返回:无
4、sntp_getservername
功能:查询 SNTP 服务器的域名,仅⽀持查询通过 sntp_setservername 设置的 SNTP 服务器
函数定义:char * sntp_getservername(unsigned char idx)
参数: unsigned char idx:SNTP 服务器编号,最多⽀持 3 个 SNTP 服务器(0 ~ 2)
返回:服务器域名
5、sntp_init
功能:SNTP 初始化
函数定义:void sntp_init(void)
参数:⽆
返回:⽆
6、sntp_stop
功能:SNTP 关闭
函数定义:void sntp_stop(void)
参数:⽆
返回:⽆
7、sntp_get_current_timestamp
功能:查询当前距离基准时间 (1970.01.01 00:00:00 GMT + 8) 的时间戳,单位:秒
函数定义:uint32 sntp_get_current_timestamp()
参数:⽆
返回:距离基准时间的时间戳
8、sntp_get_real_time
功能:查询实际时间 (GMT + 8)
函数定义:char* sntp_get_real_time(long t)
参数:long t:与基准时间相距的时间戳
返回:实际时间
9、sntp_set_timezone
功能:设置时区信息
注意:调⽤本接⼝前,请先调⽤ sntp_stop
函数定义:bool sntp_set_timezone (sint8 timezone)
参数:sint8 timezone:时区值,参数范围:-11 ~ 13
返回:
true:成功
false:失败
示例:

 sntp_stop();if( true    ==    sntp_set_timezone(-5)   )   {sntp_init();}

10、.sntp_get_timezone
功能:查询时区信息
函数定义:sint8 sntp_get_timezone (void)
参数:⽆
返回:时区值,参数范围:-11 ~ 13

例程

首先在user_init函数中初始化串口,等待串口稳定后,使OLED显示初始化的内容,并且将ESP8266设置成STA模式,并且进行1秒钟的重复定时。这个user_init函数与之前UDP通信TCP通信的函数一样。区别在于需要OLED显示的内容不同。

void ICACHE_FLASH_ATTR user_init(void)
{uart_init(115200,115200);  // 初始化串口波特率os_delay_us(10000);          // 等待串口稳定os_printf("\t Project:\t%s\r\n", ProjectName);os_printf("\t SDK version:\t%s", system_get_sdk_version());// OLED显示初始化OLED_Init();                              // OLED初始化OLED_ShowString(0,0,"                ");    // Internet TimeOLED_ShowString(0,2,"Clock =         "); // Clock:时钟OLED_ShowString(0,4,"Temp  =         ");   // Temperature:温度OLED_ShowString(0,6,"Humid =         "); // Humidity:湿度LED_Init_JX();     // LED初始化ESP8266_STA_Init_JX();         // ESP8266_STA初始化OS_Timer_IP_Init_JX(1000,1);   // 1秒重复定时(获取IP地址)
}

设置好STA相关参数后,获取IP地址,如果成功获取到IP地址后,就初始换SNTP。

void ICACHE_FLASH_ATTR ESP8266_STA_Init_JX()
{struct station_config STA_Config;  // STA参数结构体struct ip_info ST_ESP8266_IP;        // STA信息结构体// 设置ESP8266的工作模式wifi_set_opmode(0x01);              // 设置为STA模式,并保存到Flash/*// 设置STA模式下的IP地址【ESP8266默认开启DHCP Client,接入WIFI时会自动分配IP地址】
wifi_station_dhcpc_stop();                      // 关闭 DHCP ClientIP4_ADDR(&ST_ESP8266_IP.ip,192,168,8,35);      // 配置IP地址IP4_ADDR(&ST_ESP8266_IP.gw,192,168,8,1);       // 配置网关地址IP4_ADDR(&ST_ESP8266_IP.netmask,255,255,255,0);    // 配置子网掩码wifi_set_ip_info(STATION_IF,&ST_ESP8266_IP);   // 设置STA模式下的IP地址*/// 结构体赋值,配置STA模式参数os_memset(&STA_Config, 0, sizeof(struct station_config));    // STA参数结构体 = 0os_strcpy(STA_Config.ssid,ESP8266_STA_SSID);                // 设置WIFI名os_strcpy(STA_Config.password,ESP8266_STA_PASS);          // 设置WIFI密码wifi_station_set_config(&STA_Config);    // 设置STA参数,并保存到Flash// wifi_station_connect();       // ESP8266连接WIFI
}

初始化SNTP函数。ESP8266最多设置三个SNTP服务器,其中SNTP服务器0是主服务器,剩下的两个是备用服务器。我们可以调用sntp_setservername(0, "us.pool.ntp.org");sntp_setserver(2, addr);API来设置服务器。参数1是SNTP的优先级。第一个API的参数2是SNTP的域名第二个API的参数2是指SNTP服务器的32位IP地址,在这个API之前调用ipaddr_aton("210.72.145.44", addr);API将字符串转换成点分二进制位32位的IP地址。之后调用sntp_init();这个API初始化SNTP。最后设置了1秒钟的重复定时。

void ICACHE_FLASH_ATTR ESP8266_SNTP_Init_JX(void)
{ip_addr_t * addr = (ip_addr_t *)os_zalloc(sizeof(ip_addr_t));sntp_setservername(0, "us.pool.ntp.org");  // 服务器_0【域名】sntp_setservername(1, "ntp.sjtu.edu.cn"); // 服务器_1【域名】ipaddr_aton("210.72.145.44", addr);           // 点分十进制 => 32位二进制sntp_setserver(2, addr);                  // 服务器_2【IP地址】os_free(addr);                                // 释放addrsntp_init();   // SNTP初始化APIOS_Timer_SNTP_Init_JX(1000,1);             // 1秒重复定时(SNTP)
}

在SNTP定时回调函数中使用TimeStamp = sntp_get_current_timestamp();获取当前距离基准时间的时间戳,基准时间为1970.01.01 00:00:00 GMT+8。如果这个时间戳不等于0,就说明我们的SNTP获取网络时间成功。我们调用下一个APIStr_RealTime = sntp_get_real_time(TimeStamp);参数为距离基准时间的时间戳,来获取当前时间的真实时间。接着串口打印时间戳和实际时间。之后我们根据获取到的实际时间用OLED显示。并且OLED显示读取到的温湿度

void ICACHE_FLASH_ATTR OS_Timer_SNTP_cb(void  * arg)
{// 字符串整理 相关变量u8 C_Str = 0;                // 字符串字节计数char A_Str_Data[20] = {0};   // 【"日期"】字符串数组char *T_A_Str_Data = A_Str_Data;   // 缓存数组指针char A_Str_Clock[10] = {0};   // 【"时间"】字符串数组char * Str_Head_Week;       // 【"星期"】字符串首地址char * Str_Head_Month;     // 【"月份"】字符串首地址char * Str_Head_Day;       // 【"日数"】字符串首地址char * Str_Head_Clock;     // 【"时钟"】字符串首地址char * Str_Head_Year;      // 【"年份"】字符串首地址uint32 TimeStamp;      // 时间戳char * Str_RealTime;  // 实际时间的字符串// 查询当前距离基准时间(1970.01.01 00:00:00 GMT+8)的时间戳(单位:秒)TimeStamp = sntp_get_current_timestamp();if(TimeStamp)       // 判断是否获取到偏移时间{//os_timer_disarm(&OS_Timer_SNTP);   // 关闭SNTP定时器// 查询实际时间(GMT+8):东八区(北京时间)Str_RealTime = sntp_get_real_time(TimeStamp);// 【实际时间】字符串 == "周 月 日 时:分:秒 年"os_printf("SNTP_TimeStamp = %d\r\n",TimeStamp);      // 时间戳os_printf("\r\nSNTP_InternetTime = %s",Str_RealTime);  // 实际时间// 时间字符串整理,OLED显示【"日期"】、【"时间"】字符串 // 【"年份" + ' '】填入日期数组Str_Head_Year = Str_RealTime;    // 设置起始地址while( *Str_Head_Year )        // 找到【"实际时间"】字符串的结束字符'\0'Str_Head_Year ++ ;// 【注:API返回的实际时间字符串,最后还有一个换行符,所以这里 -5】Str_Head_Year -= 5 ;           // 获取【"年份"】字符串的首地址T_A_Str_Data[4] = ' ' ;os_memcpy(T_A_Str_Data, Str_Head_Year, 4);        // 【"年份" + ' '】填入日期数组T_A_Str_Data += 5;              // 指向【"年份" + ' '】字符串的后面的地址// 获取【日期】字符串的首地址Str_Head_Week    = Str_RealTime;                            // "星期" 字符串的首地址Str_Head_Month = os_strstr(Str_Head_Week, " ") + 1;    // "月份" 字符串的首地址Str_Head_Day   = os_strstr(Str_Head_Month,    " ") + 1;    // "日数" 字符串的首地址Str_Head_Clock = os_strstr(Str_Head_Day,  " ") + 1;    // "时钟" 字符串的首地址// 【"月份" + ' '】填入日期数组C_Str = Str_Head_Day - Str_Head_Month;              // 【"月份" + ' '】的字节数os_memcpy(T_A_Str_Data, Str_Head_Month, C_Str); // 【"月份" + ' '】填入日期数组T_A_Str_Data += C_Str;      // 指向【"月份" + ' '】字符串的后面的地址// 【"日数" + ' '】填入日期数组C_Str = Str_Head_Clock - Str_Head_Day;                // 【"日数" + ' '】的字节数os_memcpy(T_A_Str_Data, Str_Head_Day, C_Str);       // 【"日数" + ' '】填入日期数组T_A_Str_Data += C_Str;      // 指向【"日数" + ' '】字符串的后面的地址// 【"星期" + ' '】填入日期数组C_Str = Str_Head_Month - Str_Head_Week - 1;       // 【"星期"】的字节数os_memcpy(T_A_Str_Data, Str_Head_Week, C_Str);       // 【"星期"】填入日期数组T_A_Str_Data += C_Str;       // 指向【"星期"】字符串的后面的地址// OLED显示【"日期"】、【"时钟"】字符串*T_A_Str_Data = '\0';     // 【"日期"】字符串后面添加'\0'OLED_ShowString(0,0,A_Str_Data);        // OLED显示日期os_memcpy(A_Str_Clock, Str_Head_Clock, 8);       // 【"时钟"】字符串填入时钟数组A_Str_Clock[8] = '\0';OLED_ShowString(64,2,A_Str_Clock);     // OLED显示时间}// 每5秒,读取/显示温湿度数据//-----------------------------------------------------------------------------------------C_Read_DHT11 ++ ;      // 读取DHT11计时if(C_Read_DHT11>=5)     // 5秒计时{C_Read_DHT11 = 0;  // 计时=0if(DHT11_Read_Data_Complete() == 0)       // 读取DHT11温湿度{DHT11_NUM_Char(); // DHT11数据值转成字符串OLED_ShowString(64,4,DHT11_Data_Char[1]);   // DHT11_Data_Char[0] == 【温度字符串】OLED_ShowString(64,6,DHT11_Data_Char[0]); // DHT11_Data_Char[1] == 【湿度字符串】}else{OLED_ShowString(64,4,"----"); // Temperature:温度OLED_ShowString(64,6,"----"); // Humidity:湿度}}//-----------------------------------------------------------------------------------------
}

现象

下载程序,打开串口助手,复位ESP8266,等待几秒后。我们可以看到串口助手成功获取到距离基准时间的时间戳。

根据时间戳成功获取当前的实际时间,与我们电脑的网络时间一直,说明我们的ESP8266成功获取到我们准确的实际时间,ESP8266的OLED上可以显示当前的时间以及温湿度。我从OLED上看到时间会跟着时间时间一秒一秒的增加。

参考链接

https://www.bilibili.com/video/BV1dJ411S723?p=43
https://www.cnblogs.com/jiangzhaowei/p/8830583.html
https://zhidao.baidu.com/question/572961879.html

学习日记——ESP8266SNTP相关推荐

  1. java的圆周率_java学习日记,圆周率的打印

    前段时间看到听说学习java每天写技术贴会对自己提升很大,我现在学习java也就2个周,算不上技术贴,就写写学习日记吧. 昨天师傅给我出了一道题,说是试试用java打印圆周率. 刚开始我的思路是,如果 ...

  2. GPU(CUDA)学习日记(十一)------ 深入理解CUDA线程层次以及关于设置线程数的思考

    GPU(CUDA)学习日记(十一)------ 深入理解CUDA线程层次以及关于设置线程数的思考 标签: cuda存储线程结构网格 2012-12-07 16:30 6298人阅读 评论(4)收藏 举 ...

  3. GPU(CUDA)学习日记(十三)------ CUDA内存简介

    GPU(CUDA)学习日记(十三)------ CUDA内存简介 标签: cuda存储线程结构 2012-12-07 16:53 2902人阅读 评论(0)收藏 举报 分类: GPU(16) CUDA ...

  4. GPU(CUDA)学习日记(九)------ CUDA存储器模型

    GPU(CUDA)学习日记(九)------ CUDA存储器模型 标签: cuda存储bindingcache编程api 2012-09-27 10:53 1677人阅读 评论(1) 收藏 举报 分类 ...

  5. 语言余一个负数_C语言学习日记(8)——整数溢出

    小时候喜欢玩电子计算器,觉得很神奇,想要算什么数,立刻就能算出来.当时看着计算器的液晶屏幕就想,如果算一个很大的数,超过了屏幕上面数字的位数,会怎么样呢?试了以后结果是INF,那就是无穷大了.虽然当时 ...

  6. SpringMVC学习日记 1.Spring框架

    SpringMVC学习日记 1.Spring框架 Spring简介 Spring框架是一个开源框架,由Rod Johnson组织和开发,生产目的在于简化企业级应用的开发. 主要特性 非侵入(no-in ...

  7. 微信开发学习日记(一):快速阅读5本书,掌握整体背景

    2015年1月开始学习微信开发. 已经有多年开发经验了,从网上文章来看,微信开发主要是接口,然后是业务逻辑,不是很难.所以,我比较强调学习效率.一天学一点,是不能满足我的快速学习欲望的.       ...

  8. const 指针_C语言学习日记(11)——const与指针

    对于一个普通指针typet *p.p有三个最基本的能力,第一就是可以通过p = &obj来指向一个type类型对象,并随意切换指向对象.第二就是通过value = *p来读取它指向的对象的值. ...

  9. 十五的学习日记20160926-你不知道的JS笔记/

    十五的学习日记20160926 JavaScript 一个用于检测正负值的函数,可以用它辨别-0值. 我觉得挺好用,以后可以写到自己的工具库里. //函数:检查传入参数是否为正数.Number=> ...

最新文章

  1. 详解BSCI实验四:配置BGP
  2. python制作adobe photoshop插件_Adobe Photoshop风格的后期处理和OpenCV
  3. 视频监控行业解决方案
  4. python能做游戏吗-python能开发游戏吗
  5. 云效 Flow——Java构建并通过云效上传二方库到 Maven 私有仓库
  6. SDN第二章 win10远程桌面Ubuntu
  7. WPF任务栏同步进度
  8. LeetCode 1256. 加密数字(bitset)
  9. A_Pancers团队项目设计完善编码测试
  10. Unity2020.1新功能探路:Profiler相关更新
  11. ffmpeg h264 解码 转
  12. Android 文件管理器 Android文件管理器源代码
  13. mysql 执行计划 视频_实战讲解MySQL执行计划,面试官当场要了我
  14. 《单细胞生物》教学反思
  15. SpringData JPA整理
  16. 公开SNS社区即时找朋友链的源代码和部署方案(续六)
  17. ctf MISC disordered_zip
  18. 20210406森林里的兔子
  19. Paul Graham:如何做好天使投资
  20. python中字符串的处理_Python中字符串的处理技巧分享

热门文章

  1. Linux学习资源推荐
  2. 初一计算机课怎么上,如何上好初中信息技术课
  3. 公共数据 | CHFS中国家庭金融调查数据
  4. 西门子V20变频器PID控制恒压供水的具体步骤
  5. C语言easyx制作华容道游戏,huarongdao 用EasyX编写的华容道程序 - 下载 - 搜珍网
  6. asp.net 2.0控件开发电子书 下载
  7. 名词解释语言表达的6c原则,货币银行学中的“6C原则”是什么意思
  8. 16GB大内存该怎么玩儿?
  9. 中国石油大学《化工过程设备设计》第三阶段在线作业
  10. Python爬虫——使用线程池爬取同程旅行景点数据并做数据可视化