NTP 是网络时间协议,将获取到的网络时间同步到本地,是本地时间与网络同步。
一般来说,STM32通过W5500从NTP服务器获取到之后,会存同步到DS1302时钟芯片中,再读取DS1302时间在应用中使用。
DS1302的时间设置和读取,可以参考 《STM32F10x读取DS1302的时间,通过USART显示在串口调试助手上》。
NTP协议是基于UDP基础上封装的协议,NTP报文格式 可以参考 《NTP报文格式》。
STM32驱动W5500,使用UDP来实现获取NTP网络时间的代码实现:NTP服务器IP选取 202.112.10.60,端口固定为123.
ntp.c
-
#include "types.h"
-
#include "ntp.h"
-
#include "socket.h"
-
#include "w5500.h"
-
-
#include <string.h>
-
#include <stdio.h>
-
-
uint8 NTP_SERVER_IP[
4] = {
202,
112,
10,
60};
-
-
void func_analysis_ntp_back_msg(uint8* buf, uint16 idx, TSTAMP *tstmp, DATETIME *datetime)
-
{
-
TSTAMP seconds =
0;
-
uint8 i =
0 ,zone = TIMEZONE8;
-
for (i =
0; i <
4; i++)
-
{
-
seconds = (seconds <<
8) | buf[idx + i];
-
}
-
switch (zone)
-
{
-
case
0:
-
seconds -=
12*
3600;
-
break;
-
case
1:
-
seconds -=
11*
3600;
-
break;
-
case
2:
-
seconds -=
10*
3600;
-
break;
-
case
3:
-
seconds -= (
9*
3600+
30*
60);
-
break;
-
case
4:
-
seconds -=
9*
3600;
-
break;
-
case
5:
-
case
6:
-
seconds -=
8*
3600;
-
break;
-
case
7:
-
case
8:
-
seconds -=
7*
3600;
-
break;
-
case
9:
-
case
10:
-
seconds -=
6*
3600;
-
break;
-
case
11:
-
case
12:
-
case
13:
-
seconds -=
5*
3600;
-
break;
-
case
14:
-
seconds -= (
4*
3600+
30*
60);
-
break;
-
case
15:
-
case
16:
-
seconds -=
4*
3600;
-
break;
-
case
17:
-
seconds -= (
3*
3600+
30*
60);
-
break;
-
case
18:
-
seconds -=
3*
3600;
-
break;
-
case
19:
-
seconds -=
2*
3600;
-
break;
-
case
20:
-
seconds -=
1*
3600;
-
break;
-
case
21:
//£¿
-
case
22:
-
break;
-
case
23:
-
case
24:
-
case
25:
-
seconds +=
1*
3600;
-
break;
-
case
26:
-
case
27:
-
seconds +=
2*
3600;
-
break;
-
case
28:
-
case
29:
-
seconds +=
3*
3600;
-
break;
-
case
30:
-
seconds += (
3*
3600+
30*
60);
-
break;
-
case
31:
-
seconds +=
4*
3600;
-
break;
-
case
32:
-
seconds += (
4*
3600+
30*
60);
-
break;
-
case
33:
-
seconds +=
5*
3600;
-
break;
-
case
34:
-
seconds += (
5*
3600+
30*
60);
-
break;
-
case
35:
-
seconds += (
5*
3600+
45*
60);
-
break;
-
case
36:
-
seconds +=
6*
3600;
-
break;
-
case
37:
-
seconds += (
6*
3600+
30*
60);
-
break;
-
case
38:
-
seconds +=
7*
3600;
-
break;
-
case
39:
-
seconds +=
8*
3600;
-
break;
-
case
40:
-
seconds +=
9*
3600;
-
break;
-
case
41:
-
seconds += (
9*
3600+
30*
60);
-
break;
-
case
42:
-
seconds +=
10*
3600;
-
break;
-
case
43:
-
seconds += (
10*
3600+
30*
60);
-
break;
-
case
44:
-
seconds +=
11*
3600;
-
break;
-
case
45:
-
seconds += (
11*
3600+
30*
60);
-
break;
-
case
46:
-
seconds +=
12*
3600;
-
break;
-
case
47:
-
seconds += (
12*
3600+
45*
60);
-
break;
-
case
48:
-
seconds +=
13*
3600;
-
break;
-
case
49:
-
seconds +=
14*
3600;
-
break;
-
}
-
-
*tstmp = seconds;
-
//calculation for date
-
calc_date_time(seconds, datetime);
-
}
-
-
-
void calc_date_time(TSTAMP seconds, DATETIME *datetime)
-
{
-
uint8 yf =
0;
-
uint32 p_year_total_sec;
-
uint32 r_year_total_sec;
-
TSTAMP n=
0, d=
0, total_d=
0, rz=
0;
-
uint16 y=
0, r=
0, yr=
0;
-
signed
long
long yd=
0;
-
-
n = seconds;
-
total_d = seconds/(SECS_PERDAY);
-
d=
0;
-
p_year_total_sec=SECS_PERDAY*
365;
-
r_year_total_sec=SECS_PERDAY*
366;
-
while(n>=p_year_total_sec)
-
{
-
if((EPOCH+r)%
400==
0 || ((EPOCH+r)%
100!=
0 && (EPOCH+r)%
4==
0))
-
{
-
n = n -(r_year_total_sec);
-
d = d +
366;
-
}
-
else
-
{
-
n = n - (p_year_total_sec);
-
d = d +
365;
-
}
-
r+=
1;
-
y+=
1;
-
-
}
-
-
y += EPOCH;
-
-
datetime->yy = y;
-
-
yd=
0;
-
yd = total_d - d;
-
-
yf=
1;
-
while(yd>=
28)
-
{
-
-
if(yf==
1 || yf==
3 || yf==
5 || yf==
7 || yf==
8 || yf==
10 || yf==
12)
-
{
-
yd -=
31;
-
if(yd<
0)
break;
-
rz +=
31;
-
}
-
-
if (yf==
2)
-
{
-
if (y%
400==
0 || (y%
100!=
0 && y%
4==
0))
-
{
-
yd -=
29;
-
if(yd<
0)
break;
-
rz +=
29;
-
}
-
else
-
{
-
yd -=
28;
-
if(yd<
0)
break;
-
rz +=
28;
-
}
-
}
-
if(yf==
4 || yf==
6 || yf==
9 || yf==
11 )
-
{
-
yd -=
30;
-
if(yd<
0)
break;
-
rz +=
30;
-
}
-
yf +=
1;
-
-
}
-
-
datetime->mo = yf;
-
yr = total_d-d-rz;
-
-
yr +=
1;
-
-
datetime->dd = yr;
-
-
seconds = seconds%SECS_PERDAY;
-
datetime->hh = seconds/
3600;
-
datetime->mm = (seconds%
3600)/
60;
-
datetime->ss = (seconds%
3600)%
60;
-
-
}
-
/*
-
TSTAMP change_datetime_to_seconds(void)
-
{
-
TSTAMP seconds=0;
-
uint32 total_day=0;
-
uint16 i=0,run_year_cnt=0,l=0;
-
-
l = dt_ntp.yy;
-
-
-
for(i=EPOCH;i<l;i++)
-
{
-
if((i%400==0) || ((i%100!=0) && (i%4==0)))
-
{
-
run_year_cnt += 1;
-
}
-
}
-
-
total_day=(l-EPOCH-run_year_cnt)*365+run_year_cnt*366;
-
-
for(i=1;i<=dt_ntp.mm;i++)
-
{
-
if(i==5 || i==7 || i==10 || i==12)
-
{
-
total_day += 30;
-
}
-
if (i==3)
-
{
-
if (l%400==0 && l%100!=0 && l%4==0)
-
{
-
total_day += 29;
-
}
-
else
-
{
-
total_day += 28;
-
}
-
}
-
if(i==2 || i==4 || i==6 || i==8 || i==9 || i==11)
-
{
-
total_day += 31;
-
}
-
}
-
-
seconds = (total_day+dt_ntp.dd-1)*24*3600;
-
seconds += dt_ntp.ss;//seconds
-
seconds += dt_ntp.mm*60;//minute
-
seconds += dt_ntp.hh*3600;//hour
-
-
return seconds;
-
}
-
*/
-
-
uint8 func_pack_ntp_message(uint8 *ntp_server_ip, uint8 *ntp_message)
-
{
-
uint8 flag;
-
NTPFORMAT ntpfmt;
-
ntpfmt.dstaddr[
0] = ntp_server_ip[
0];
-
ntpfmt.dstaddr[
1] = ntp_server_ip[
1];
-
ntpfmt.dstaddr[
2] = ntp_server_ip[
2];
-
ntpfmt.dstaddr[
3] = ntp_server_ip[
3];
-
-
ntpfmt.leap =
11;
/* leap indicator */
-
ntpfmt.version =
3;
/* version number */
-
ntpfmt.mode =
3;
/* mode */
-
ntpfmt.stratum =
0;
/* stratum */
-
ntpfmt.poll =
0;
/* poll interval */
-
ntpfmt.precision =
0;
/* precision */
-
ntpfmt.rootdelay =
0;
/* root delay */
-
ntpfmt.rootdisp =
0;
/* root dispersion */
-
ntpfmt.refid =
0;
/* reference ID */
-
ntpfmt.reftime =
0;
/* reference time */
-
ntpfmt.org =
0;
/* origin timestamp */
-
ntpfmt.rec =
0;
/* receive timestamp */
-
ntpfmt.xmt =
1;
/* transmit timestamp */
-
-
flag = (ntpfmt.leap <<
6) + (ntpfmt.version <<
3 ) + ntpfmt.mode;
//one byte Flag
-
ntp_message[
0] = flag;
-
return
0;
-
}
-
-
uint8 func_get_ntp_time(uint8 sock, TSTAMP *tstamp, DATETIME *datetime, uint16 timeout_ms)
-
{
-
uint16 cnt_timeout =
0;
-
uint8 ntp_message[
48] = {
0,};
-
uint8 ntp_back_msg[
256] = {
0,};
-
uint8 ntp_s_ip[
4] = {
0,};
-
uint16 ntp_s_port, len;
-
//socket init
-
if(getSn_SR(sock) == SOCK_CLOSED)
-
{
-
socket(sock, Sn_MR_UDP, NTP_PORT,
0);
-
}
-
//pack NTP message
-
func_pack_ntp_message(NTP_SERVER_IP, ntp_message);
-
//send ntp message
-
sendto(sock, ntp_message,
sizeof(ntp_message), NTP_SERVER_IP, NTP_PORT);
-
//wait for NTP message back
-
for(;;)
-
{
-
if(getSn_IR(sock) & Sn_IR_RECV)
-
{
-
setSn_IR(sock, Sn_IR_RECV);
-
}
-
if ((len = getSn_RX_RSR(sock)) >
0)
-
{
-
len = recvfrom(sock, ntp_back_msg,
sizeof(ntp_back_msg), ntp_s_ip, &ntp_s_port);
-
if(len >=
48 && ntp_s_port == NTP_PORT)
-
{
-
//analysis
-
func_analysis_ntp_back_msg(ntp_back_msg,
40, tstamp, datetime);
-
break;
-
}
-
}
-
-
cnt_timeout ++;
-
if(cnt_timeout > timeout_ms)
-
{
-
close(sock);
-
return
1;
-
}
-
delay_ms(
1);
-
}
-
//close socket
-
close(sock);
-
return
0;
-
}
ntp.h
-
#ifndef __NTP_H__
-
#define __NTP_H__
-
#include "types.h"
-
-
#ifndef __Z_UTIL_TIME_H
-
#define __Z_UTIL_TIME_H
-
#include "z_util_time.h"
-
#endif
-
-
#define NTP_PORT 123
-
#define EPOCH 1900 // NTP start year
-
#define TIMEZONE0 22
-
#define TIMEZONE8 39
-
typedef
unsigned
long
long TSTAMP;
-
-
-
typedef
signed
char s_char;
-
typedef
unsigned
int tdist;
-
-
typedef
struct _ntpformat
-
{
-
uint8 dstaddr[
4];
/* destination (local) address */
-
char version;
/* version number */
-
char leap;
/* leap indicator */
-
char mode;
/* mode */
-
char stratum;
/* stratum */
-
char poll;
/* poll interval */
-
s_char precision;
/* precision */
-
tdist rootdelay;
/* root delay */
-
tdist rootdisp;
/* root dispersion */
-
tdist refid;
/* reference ID */
-
TSTAMP reftime;
/* reference time */
-
TSTAMP org;
/* origin timestamp */
-
TSTAMP rec;
/* receive timestamp */
-
TSTAMP xmt;
/* transmit timestamp */
-
} NTPFORMAT;
-
-
typedef
struct _datetime
-
{
-
uint16 yy;
-
uint8 mo;
-
uint8 dd;
-
uint8 hh;
-
uint8 mm;
-
uint8 ss;
-
} DATETIME;
-
-
#define SECS_PERDAY 86400UL // seconds in a day = 60*60*24
-
#define UTC_ADJ_HRS 9 // SEOUL : GMT+9
-
-
void calc_date_time(TSTAMP seconds, DATETIME *datetime);
-
uint8 func_pack_ntp_message(uint8 *ntp_server_ip, uint8 *ntp_message);
-
void func_analysis_ntp_back_msg(uint8* buf, uint16 idx, TSTAMP *tstmp, DATETIME *datetime);
-
uint8 func_get_ntp_time(uint8 sock, TSTAMP *tstamp, DATETIME *datetime, uint16 timeout_ms);
-
#endif
-
测试的主函数代码:
-
#ifndef __STM32F10X_H
-
#define __STM32F10X_H
-
#include "stm32f10x.h"
-
#endif
-
-
#ifndef __Z_UTIL_TIME_H
-
#define __Z_UTIL_TIME_H
-
#include "z_util_time.h"
-
#endif
-
-
#ifndef __Z_HARDWARE_LED_H
-
#define __Z_HARDWARE_LED_H
-
#include "z_hardware_led.h"
-
#endif
-
-
#ifndef __Z_HARDWARE_SPI_H
-
#define __Z_HARDWARE_SPI_H
-
#include "z_hardware_spi.h"
-
#endif
-
-
#ifndef __Z_HARDWARE_USART2_H
-
#define __Z_HARDWARE_USART2_H
-
#include "z_hardware_usart2.h"
-
#endif
-
-
#include "w5500.h"
-
#include "socket.h"
-
#include "w5500_conf.h"
-
#include "dhcp.h"
-
#include "ntp.h"
-
-
int main(void)
-
{
-
DHCP_Get dhcp_get;
-
TSTAMP tstmp;
-
DATETIME dt;
-
uint8 buffer[
1024];
-
-
u8 mac[
6]={
0,
0,
0,
0,
0,
0};
-
-
init_led();
-
init_hardware_usart2_dma(
9600);
-
init_system_spi();
-
func_w5500_reset();
-
-
getMacByLockCode(mac);
-
setSHAR(mac);
-
-
/*DHCP TEST*/
-
sysinit(txsize, rxsize);
-
setRTR(
2000);
-
setRCR(
3);
-
-
//DHCP
-
if(func_dhcp_get_ip_sub_gw(
0, mac, &dhcp_get,
500) ==
0)
-
{
-
func_usart2_dma_send_bytes(dhcp_get.lip,
4);
-
setSUBR(dhcp_get.dns);
-
setGAR(dhcp_get.gw);
-
setSIPR(dhcp_get.lip);
-
}
-
for(;;)
-
{
-
delay_ms(
500);
-
-
if(func_get_ntp_time(
1, &tstmp, &dt,
2000) ==
0)
-
{
-
int len;
-
memset(buffer,
0,
sizeof(buffer));
-
len =
sprintf((
char*)buffer,
"%04d-%02d-%02d %02d:%02d:%02d", dt.yy, dt.mo, dt.dd, dt.hh, dt.mm, dt.ss);
-
func_usart2_dma_send_bytes(buffer, len);
-
}
-
-
func_led1_on();
-
delay_ms(
460);
-
func_led1_off();
-
delay_ms(
560);
-
-
}
-
}
-
通过串口将获取的网络时间打印出来,测试的效果:
可以看出测试的时间和windows的时间,相差不大。