极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 70239|回复: 27

【翻译教程】enc28J60 和 Arduino (13)——用NTP获取Internet时间

[复制链接]
发表于 2013-4-21 12:26:53 | 显示全部楼层 |阅读模式
本帖最后由 zcbzjx 于 2013-4-22 08:17 编辑

缺了第12篇,没合适的实验条件,以后再翻译吧。

在我这个应用曾经用服务器头文件中的时间数据,获取internet时间。办法很蠢,现在给大家翻译这篇文章,介绍一个比较好的办法。



今天的教程是通过NTP(网络时间协议)从互联网得到一个准确的时间。

NTP

NTP是一个客户端-服务器协议,他工作在应用层,采用UDP传输协议,使用端口为123。

如果你发送一个请求到某个时间服务器,时间服务器会返回一个64位的值(时间戳):
  • 前32位表示自1900年1月1日间隔的秒数;
  • 后32位用以表示秒以下的部份,并加上网络延时量的估计.理论上可以精确到到2的-32次方秒,实际使用大约只有50ms(广域网)左右,在局域网可达1ms。在实际中您应找最近而且最稳定的时间服务器作为时间源。




在互联网上有很多时间服务器:比如美国的 NIST (译者注:貌似我家电信ADSL翻墙才可打开网址)(National Institute of Standards and Technology) 提供整个互联网的时间服务;我住在意大利,所以在这个例子我选择由 INRiM (Istituto Nazionale di Ricerca Metereologica)提供的时间服务器:
  1. static byte ntpServer[] = {193,204,114,232};
复制代码
Arduino

在EtherCard库针对NTP请求有两个方法:

  • ntpRequest(ntpServer, srcPort),向指定的服务器发送一个请求;
  • ntpProcessAnswer(&timeStamp, srcPort), 获取响应,提取时间戳(仅仅前32位)。


srcPort参数是用来在众多的enc28J60模块接收的包中发现一个包含NTP服务器回应的数据包:你可以自己选择这个值,但是ntpRequest方法和ntpProcessAnswer方法中这个参数应该一致。



取得时间戳的值后,你必须转换成date-time格式。这个方法过程如下:

  • 计算出时间戳对应的年数;
  • 在剩下的时间中计算出有多少个月份;
  • 相同的方法计算出日期,小时,分钟;
  • 最后剩下的就是秒数。


几个容易弄错的地方:

可能是闰年:如果是闰年必须用366*86500秒替代365*86500秒,判断是否为闰年可以用下面的方法:
  1. boolean isLeapYear(unsigned int year) {
  2.   return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
  3. }
复制代码
每个月份的天数是变化的:把这些值存入一个数组,格式如下:
  1. static int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
复制代码
如果是闰年,二月份为29天
  1. if(isLeapYear(year) && month == 1) seconds = SECONDS_IN_DAY * 29;
复制代码
最后,时间戳是参考的GMT(格林尼治标准时间),如果你居住在不同的时区,你必须修正这个值:
  1. #define TIME_ZONE               +1
  2. [...]
  3. printDate(timeStamp + 3600 * TIME_ZONE);
复制代码
完整的代码在Github上......下面是一个关于它的工作截图:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

评分

参与人数 1 +5 收起 理由
幻生幻灭 + 5 坚持不懈!

查看全部评分

回复

使用道具 举报

发表于 2013-8-25 23:03:44 | 显示全部楼层
感谢楼主分享,学习中~~~
回复 支持 1 反对 0

使用道具 举报

发表于 2013-4-21 14:08:45 | 显示全部楼层
占座,稍后读
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-4-21 14:13:34 | 显示全部楼层
又挣了5块钱。不错不错。。{:soso_e106:}
回复 支持 反对

使用道具 举报

发表于 2013-4-21 14:53:34 | 显示全部楼层
学习了,谢谢
回复 支持 反对

使用道具 举报

发表于 2013-4-21 20:48:51 | 显示全部楼层
纠正一点,time.nist.gov是不需要翻墙的。我的WINDOWS一直默认这个TIME服务器,每次返回数据都成功的。
不过内容还是学习下,ARDUINO访问时间服务器属于高级网络应用了
回复 支持 反对

使用道具 举报

发表于 2013-4-21 23:52:23 | 显示全部楼层
果断节约一个ds1307了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-4-22 08:19:23 | 显示全部楼层
wasdpkj 发表于 2013-4-21 23:52
果断节约一个ds1307了

恩,再用time.h库就可以做时钟了,不过对于用陶瓷晶振的Arduino,建议较短时间就校对一次,陶瓷晶振的精度太低了。。不过谁让他体积小嘞。
回复 支持 反对

使用道具 举报

发表于 2013-4-22 17:39:41 | 显示全部楼层
本帖最后由 wasdpkj 于 2013-4-22 18:27 编辑
zcbzjx 发表于 2013-4-22 08:19
恩,再用time.h库就可以做时钟了,不过对于用陶瓷晶振的Arduino,建议较短时间就校对一次,陶瓷晶振的精度 ...


我偷了个懒, 时钟部分,直接用现成的printDate做算法
回复 支持 反对

使用道具 举报

发表于 2013-5-14 15:12:28 | 显示全部楼层
谢谢楼主分享,正在一篇一篇看
回复 支持 反对

使用道具 举报

发表于 2013-8-28 10:07:05 | 显示全部楼层
markmark~~
回复 支持 反对

使用道具 举报

发表于 2014-2-21 01:54:59 | 显示全部楼层
mark一下,以后读
回复 支持 反对

使用道具 举报

发表于 2014-8-29 21:28:43 | 显示全部楼层
有点难度了……有点费劲
回复 支持 反对

使用道具 举报

发表于 2014-10-15 19:39:17 | 显示全部楼层
为什么我收不到返回的timeStamp???

Serial Monitor一直都保持这个样子的

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2014-10-15 19:49:45 | 显示全部楼层
用的是"210.72.145.44  (国家授时中心服务器IP地址)"

这个要设置端口的吗?
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-25 15:36 , Processed in 0.045778 second(s), 30 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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