前言
上一章我们用W5500_EVB_PICO 开发板做Ping数据测试IP检测连通性,那么本章我们进行W5500_EVB_PICO SNTP的测试。
什么是NTP?
NTP(Network Time Protocol)网络时间协议基于UDP,用于网络时间同步的协议,使网络中的计算机时钟同步到UTC,再配合各个时区的偏移调整就能实现精准同步对时功能。提供NTP对时的服务器有很多,比如微软的NTP对时服务器,利用NTP服务器提供的对时功能,可以使我们的设备时钟系统能够正确运行。
NTP报文格式
NTP报文格式如上图所示,它的字段含义参考如下:
LI 闰秒标识器,占用2个bit
VN 版本号,占用3个bits,表示NTP的版本号,现在为3
Mode 模式,占用3个bits,表示模式
stratum(层),占用8个bits
Poll 测试间隔,占用8个bits,表示连续信息之间的最大间隔
Precision 精度,占用8个bits,,表示本地时钟精度
Root Delay根时延,占用8个bits,表示在主参考源之间往返的总共时延
Root Dispersion根离散,占用8个bits,表示在主参考源有关的名义错误
Reference Identifier参考时钟标识符,占用8个bits,用来标识特殊的参考源
参考时间戳,64bits时间戳,本地时钟被修改的最新时间。
原始时间戳,客户端发送的时间,64bits。
接受时间戳,服务端接受到的时间,64bits。
传送时间戳,服务端送出应答的时间,64bits。
认证符(可选项)
连接方式
开发板和主机都接在路由器LAN口
获取网络时间测试
1.相关代码
我们打开例程中库文件的sntp_client.c文件,可以看到两个有关于ntp的两个函数,分别是SNTP_init函数和SNRTP_run函数,SNTP_init函数第一个参数是socket号,第二参数是获取时间的服务器ip,第三个参数是所要获取时间的时区(中国是东八区,sntp.c文件中能找到对应编号),第四个参数是缓存buf;然后SNTP_run的函数是传入一个datetime结构类型的参数,结构体里面有相应的参数。
void SNTP_init(uint8_t s, uint8_t *ntp_server, uint8_t tz, uint8_t *buf)
{NTP_SOCKET = s;NTPformat.dstaddr[0] = ntp_server[0];NTPformat.dstaddr[1] = ntp_server[1];NTPformat.dstaddr[2] = ntp_server[2];NTPformat.dstaddr[3] = ntp_server[3];time_zone = tz;data_buf = buf;uint8_t Flag;NTPformat.leap = 0; /* leap indicator */NTPformat.version = 4; /* version number */NTPformat.mode = 3; /* mode */NTPformat.stratum = 0; /* stratum */NTPformat.poll = 0; /* poll interval */NTPformat.precision = 0; /* precision */NTPformat.rootdelay = 0; /* root delay */NTPformat.rootdisp = 0; /* root dispersion */NTPformat.refid = 0; /* reference ID */NTPformat.reftime = 0; /* reference time */NTPformat.org = 0; /* origin timestamp */NTPformat.rec = 0; /* receive timestamp */NTPformat.xmt = 1; /* transmit timestamp */Flag = (NTPformat.leap<<6)+(NTPformat.version<<3)+NTPformat.mode; //one byte Flagmemcpy(ntpmessage,(void const*)(&Flag),1);
}
int8_t SNTP_run(datetime *time)
{uint16_t RSR_len;uint32_t destip = 0;uint16_t destport;uint16_t startindex = 40; //last 8-byte of data_buf[size is 48 byte] is xmt, so the startindex should be 40switch(getSn_SR(NTP_SOCKET)){case SOCK_UDP:if ((RSR_len = getSn_RX_RSR(NTP_SOCKET)) > 0){if (RSR_len > MAX_SNTP_BUF_SIZE) RSR_len = MAX_SNTP_BUF_SIZE; // if Rx data size is lager than TX_RX_MAX_BUF_SIZErecvfrom(NTP_SOCKET, data_buf, RSR_len, (uint8_t *)&destip, &destport);get_seconds_from_ntp_server(data_buf,startindex);time->yy = Nowdatetime.yy;time->mo = Nowdatetime.mo;time->dd = Nowdatetime.dd;time->hh = Nowdatetime.hh;time->mm = Nowdatetime.mm;time->ss = Nowdatetime.ss;ntp_retry_cnt=0;close(NTP_SOCKET);return 1;}if(ntp_retry_cnt<0xFFFF){if(ntp_retry_cnt==0)//first send request, no need to wait{sendto(NTP_SOCKET,ntpmessage,sizeof(ntpmessage),NTPformat.dstaddr,ntp_port);ntp_retry_cnt++;}else // send request again? it should wait for a while{if((ntp_retry_cnt % 0xFFF) == 0) //wait time{sendto(NTP_SOCKET,ntpmessage,sizeof(ntpmessage),NTPformat.dstaddr,ntp_port);
#ifdef _SNTP_DEBUG_printf("ntp retry: %d\r\n", ntp_retry_cnt);
#endifntp_retry_cnt++;}}}else //ntp retry fail{ntp_retry_cnt=0;
#ifdef _SNTP_DEBUG_printf("ntp retry failed!\r\n");
#endifclose(NTP_SOCKET);}break;case SOCK_CLOSED:socket(NTP_SOCKET,Sn_MR_UDP,ntp_port,0);break;}// Return value// 0 - failed / 1 - successreturn 0;
}
datetime类型结构体
typedef struct _datetime
{uint16_t yy;uint8_t mo;uint8_t dd;uint8_t hh;uint8_t mm;uint8_t ss;
} datetime;
2.测试现象
编译烧录完成之后打开串行监视器,复位一下W5500_EVB_PICO,然后串口上就会开始打印网络配置信息,然后开始获取时间,看到串口上一秒打印一次时间,表示成功。
相关连接:
本章例程链接