W6300从网络获取时间
更新于 2026年10月9日
本篇总结
在 W6300 上实现 SNTP 授时功能,从 SNTP 服务器获取准确时间并打印北京时间。
硬件平台:本例程基于 W6300-EVB-M4 开发板运行。
采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W6300-EVB-M4 开发板
本示例演示如何在 W6300 上实现 SNTP 授时功能,通过实战例程讲解如何让 W6300 从 SNTP 服务器获取准确的实际时间。该例程用到的其他网络协议(例如 DHCP、DNS),请参考相关章节。有关 W6300 的初始化过程,请参考 Network install 章节,这里不再赘述。
前置工具准备
开始本例程前,请确认以下工具已安装:
- WIZ UartTool V1.0:串口调试工具:点击下载
SNTP 协议简介
SNTP(Simple Network Time Protocol)是一种基于 UDP 协议的网络时间协议,主要用于在计算机网络中同步设备的时间。SNTP 旨在提供简单的时间校准服务,相比 NTP(Network Time Protocol),SNTP 功能更为简单,精度相对较低。
SNTP 协议特点:
- 使用 UDP 通信:SNTP 使用 UDP 协议在端口 123 进行通信
- 支持请求-响应模式:单次请求-响应完成时间同步——客户端发送请求,服务器返回当前时间戳
- 实现和部署成本低:实现简单,通常只需要少量代码,便于嵌入式系统集成
- 与 NTP 兼容:SNTP 是 NTP 的子集,客户端可与 NTP 服务器通信以获取时间
- 支持单向时间同步:特定场景下可仅基于服务器时间戳完成时间同步,无需计算网络延迟
SNTP 应用场景
通过将时间同步到本地时钟,实现:协同工作(各模块按预定时间顺序执行任务)、日志与事件管理(确保日志时间和事件记录准确)、定时任务(支持定时任务准确执行)。
时区介绍
通过 SNTP 获取世界标准时间(UTC)后,需要根据所在时区进行加减运算以计算当地时间。例如中国位于 UTC+8 时区,在示例代码中定义为 39。因此获取 UTC 后需加 8 小时才能转换为中国时间。
SNTP 协议同步时间的基本流程
- 客户端发送时间请求:客户端向 SNTP 服务器发送请求数据包,并记录 T1 时间戳信息
- 服务器接收请求并处理:服务器记录接收时间 T2,生成响应数据包,包含 T2(接收时间)和 T3(发送时间)
- 客户端接收响应并计算时间:客户端提取 T2、T3,记录接收时间 T4,计算网络延迟和本地时间校准值
- 调整本地时间:客户端根据校准时间调整本地时钟,同步到服务器时间
时间戳定义
时间戳的定义是指从 1900 年 1 月 1 日 00:00:00 UTC 开始的秒数。SNTP 的发送和接收报文为固定结构,通常为 48 字节。
硬件连接与拓扑
请注意:
本示例需要访问互联网,请确保 W6300 的网络环境及配置能够正常访问互联网。
- Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
- 网线连接开发板 RJ45 网口 到路由器 LAN 口,路由器需连接互联网
- 确保 W6300 与 MH2457 之间的 QSPI 连线正确(CSn、SCK、DATA0~DATA3)
│ W6300 │──网线──│ 路由器/网关 │──互联网──│ SNTP 服务器 │
│ (SNTP │ │ (DHCP/DNS) │ │ cn.pool.ntp.org │
│ Client) │ │ 192.168.1.1 │ │ UDP :123 │
└────┬──────┘ └─────────────────┘ └──────────────────┘
│ QSPI
┌────┴──────┐
│ MH2457 │──────────→ WIZ UartTool
│ MCU │
└───────────┘
工程结构
工程核心文件如下:
Project/
├── main.c ← 系统入口:串口、GPIO、QSPI 初始化 + user_run()
└── USER/
├── user_main.c ← 网络地址定义 + SNTP 服务器 + user_run() 主流程
├── sntp.c ← SNTP 协议实现(SNTP_init / SNTP_run / calcdatetime)
├── do_dns.c ← DNS 域名解析
├── wiz_platform.c/h ← 平台适配:debug_usart_init、wizchip_gpio_init、hspi_init
└── wiz_interface.c/h ← W6300 驱动接口:wizchip_initialize、network_init、PHY 检测、软件定时器
步骤1:通过 DNS 解析 SNTP 服务器域名
文件:USER/user_main.c — 使用 do_dns() 将 SNTP 服务器域名 cn.pool.ntp.org 解析为 IP 地址。
uint8_t sntp_server_name[] = "cn.pool.ntp.org";
uint8_t sntp_server_ip[4] = {0, 0, 0, 0};
if (do_dns(ethernet_buf, sntp_server_name, sntp_server_ip))
{
if (sntp_server_ip[0] != 0U)
{
printf("Use Default Server Internet Protocol Address:%d.%d.%d.%d\r\n",
sntp_server_ip[0], sntp_server_ip[1], sntp_server_ip[2], sntp_server_ip[3]);
}
else
{
printf("No default server address, unable to connect to the server\r\n");
while (1) { }
}
}
do_dns() 将域名解析为 IP 写入 sntp_server_ip。若返回非 0 表示解析失败或未获取到有效 IP,此时程序进入死循环等待,防止后续使用空地址发起 SNTP 请求。W6300 平台的 do_dns() 内部通过软件定时器链表注册 DNS_time_handler() 提供时基。
步骤2:SNTP 初始化
文件:USER/sntp.c | 函数:SNTP_init() — 传入 Socket 通道号、SNTP 服务器地址、时区和缓存,完成 SNTP 报文组包并注册。
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;
NTPformat.poll = 0;
NTPformat.precision = 0;
NTPformat.rootdelay = 0;
NTPformat.rootdisp = 0;
NTPformat.refid = 0;
NTPformat.reftime = 0;
NTPformat.org = 0;
NTPformat.rec = 0;
NTPformat.xmt = 1; /* transmit timestamp */
Flag = (NTPformat.leap<<6)+(NTPformat.version<<3)+NTPformat.mode;
memcpy(ntpmessage,(void const*)(&Flag),1);
}
在主程序中调用 SNTP_init(SOCKET_ID, sntp_server_ip, timezone, ethernet_buf),其中 timezone = 39U 对应中国 UTC+8 时区,ethernet_buf 兼作 SNTP 收发缓存。
关键参数
version=4(NTP v4)、mode=3(客户端模式)、Flag 字节由 leap、version、mode 拼接而成。
步骤3:发送 SNTP 请求报文并解析响应
文件:USER/sntp.c | 函数:SNTP_run() — 运行 UDP 状态机:SOCK_CLOSED 时打开 Socket,SOCK_UDP 时发送请求并监听响应,收到响应后解析时间戳并转换为日期。
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
uint8_t addr_len;
switch(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;
recvfrom(NTP_SOCKET, data_buf, RSR_len, (uint8_t *)&destip, &destport, &addr_len);
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)
{
sendto(NTP_SOCKET, ntpmessage, sizeof(ntpmessage),
NTPformat.dstaddr, ntp_port, 4);
ntp_retry_cnt++;
}
else
{
if((ntp_retry_cnt % 0xFFF) == 0)
{
sendto(NTP_SOCKET, ntpmessage, sizeof(ntpmessage),
NTPformat.dstaddr, ntp_port, 4);
ntp_retry_cnt++;
}
}
}
else
{
ntp_retry_cnt = 0;
close(NTP_SOCKET);
}
break;
case SOCK_CLOSED:
socket(NTP_SOCKET, Sn_MR_UDP, ntp_port, 0);
break;
}
return 0;
}
关键点:SNTP 响应报文 48 字节,最后 8 字节是服务器发送时间戳(xmt),因此 startindex = 40。get_seconds_from_ntp_server() 解析时间戳并按时区偏移,calcdatetime() 转换为年/月/日/时/分/秒。W6300 平台的 recvfrom() / sendto() 需要额外传入地址长度参数(IPv4 为 4)。
时区处理
get_seconds_from_ntp_server() 里通过 time_zone 变量对 UTC 秒数进行偏移。中国 UTC+8 对应 time_zone = 39,此时 seconds += 8*3600。
步骤4:主循环获取时间并打印
文件:USER/user_main.c — 循环调用 SNTP_run() 直到获取时间成功,然后打印北京时间并退出循环。
SNTP_init(SOCKET_ID, sntp_server_ip, timezone, ethernet_buf);
while (1)
{
if (SNTP_run(&date))
{
printf("Beijing time now: %04d-%02d-%02d %02d:%02d:%02d\r\n",
date.yy, date.mo, date.dd, date.hh, date.mm, date.ss);
break;
}
}
与 W55MH32 例程不同,W6300 版本没有 RTC 硬件,获取到时间后直接打印,然后退出循环。如果需要周期更新时间或持续打印,可以去掉 break 并加入定时逻辑。
运行验证
打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1)。烧录例程运行后,首先进行 PHY 链路检测和 DHCP 获取网络地址,然后 DNS 解析 SNTP 服务器,获取时间并打印。预期串口输出如下:
MH2457 W6300 QSPI example start
W6300 SNTP example
PHY link
The current Mbtis speed : 100Mbps
The current Duplex Mode : Full-Duplex
DHCP running
DHCP success!
====================================================================================================
W6300 network configuration : DHCP
MAC : 00:08:DC:12:34:56
IP : 192.168.1.8
Subnet Mask : 255.255.255.0
Gateway : 192.168.1.1
DNS : 192.168.1.1
====================================================================================================
> Translated cn.pool.ntp.org to 139.199.215.251
Beijing time now: 2026-10-09 10:58:41
SNTP 获取成功后,串口打印 Beijing time now: 2026-10-09 10:58:41,表示已成功从 SNTP 服务器获取当前时间并转换为北京时间。

常见问题
Q: SNTP 和 NTP 有什么区别
SNTP 是 NTP 的简化版本,功能更简单、精度相对较低,但实现和部署成本低,适合嵌入式系统。NTP 精度更高,但协议复杂,需要更多计算资源。SNTP 是 NTP 的子集,可以与 NTP 服务器通信获取时间。
Q: 为什么 SNTP 使用 UDP 而不是 TCP
SNTP 采用单次请求-响应模式,报文小(48 字节),使用 UDP 可以降低协议开销,避免 TCP 三次握手的延迟。SNTP 只需要一次请求和一次响应即可完成时间同步,UDP 的无连接特性恰好满足这种需求。
Q: 时区参数 time_zone 为什么是 39 而不是 8
time_zone 不是时区小时数,而是代码中定义的时区编号。代码里维护了一张从 UTC-12 到 UTC+14 的完整时区表,中国 UTC+8 对应表中第 39 项,因此传入 39。这个设计便于覆盖全球所有时区(包括半小时、45 分钟时区)。
Q: SNTP 获取时间失败怎么办
排查步骤:① 确认开发板能访问互联网;② 确认 DNS 解析成功(串口打印 > Translated cn.pool.ntp.org to ...);③ 检查 123 端口是否被防火墙拦截;④ 更换其他 SNTP 服务器(如 time.windows.com);⑤ 检查 QSPI 连线是否牢固、W6300 是否正常初始化。
总结
本文讲解了如何在 W6300 芯片上实现 SNTP 授时功能:
- SNTP 协议:基于 UDP 123 端口的简化网络时间协议,单次请求-响应完成时间同步,实现简单、资源占用少
- 时区处理:SNTP 返回 UTC 时间,需按时区偏移计算当地时间,中国 UTC+8 对应 time_zone = 39
- 初始化流程:DNS 解析 SNTP 服务器 → SNTP_init 组包 → SNTP_run 循环获取 → 打印北京时间
- 关键 API:
SNTP_init()初始化、SNTP_run()循环获取、calcdatetime()时间戳转日期 - W6300 平台特有:无 RTC 硬件,获取时间后直接打印;recvfrom/sendto 需传地址长度;DNS 时基通过软件定时器链表提供
- 应用价值:为日志时间戳、定时任务、多模块协同提供准确的本地时间基准