【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)

文章目录

  • 原创声明
  • 前言
  • 一、SNTP 是什么?
  • 二、Cube 快速配置
    • 2.1 STM32 ETH 设置
    • 2.2 修改 PHY 地址
    • 2.3 LWIP SNTP 配置
    • 2.4 开启 STM32 RTC
  • 三、生成工程的简单测试
    • 3.1 手动修改 MAC 地址
    • 3.2 Ping 测试
  • 四、使用步骤
    • 4.1 开启 Lwip Debug
    • 4.2 初始化 SNTP
    • 4.3 加入服务器 IP列表
    • 4.4 编写处理函数
    • 4.5 从RTC中获取时间戳
    • 5.6 最终效果
  • 总结
  • 授权须知


原创声明

本文为 HinGwenWoong 原创,如果这篇文章对您有帮助,欢迎转载,转载请阅读文末的【授权须知】,感谢您对 HinGwenWoong 文章的认可!


前言

物联网的设备,离不开时间戳的使用,下面介绍 STM32 + LWIP 如何 使用 SNTP 获取网络时间

我是 HinGwenWoong ,一个有着清晰目标不停奋斗的程序猿,热爱技术,喜欢分享,码字不易,如果帮到您,请帮我在屏幕下方点赞 ,您的点赞可以让技术传播得更远更广,谢谢!


一、SNTP 是什么?

SNTP协议采用客户端/服务器的工作方式,可以采用单播(点对点)或者广播(一点对多点)模式操作。SNTP服务器通过接收GPS信号或自带的原子钟作为系统的时间基准。单播模式下,SNTP客户端能够通过定期访问SNTP服务器获得准确的时间信息,用于调整客户端自身所在系统的时间,达到同步时间的目的。广播模式下,SNTP服务器周期性地发送消息给指定的IP广播地址或者IP多播地址。SNTP客户端通过监听这些地址来获得时间信息。

网络中一般存在很多台SNTP服务器,客户端会通过一定的算法选择最好的几台服务器使用。如果一台SNTP服务器在工作过程中失去了外部时间源,此时SNTP服务器会告诉SNTP客户端“我失去了外部时间”。当SNTP客户端收到这个信息时,就会丢弃发生故障的SNTP服务器发给它的时间信息,然后重新选择其他的SNTP服务器。


二、Cube 快速配置

2.1 STM32 ETH 设置

在这里插入图片描述

2.2 修改 PHY 地址

本项目使用的是 LAN8720 芯片,需要修改 PHY Address0
【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)_第1张图片

2.3 LWIP SNTP 配置

【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)_第2张图片

2.4 开启 STM32 RTC

【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)_第3张图片


三、生成工程的简单测试

3.1 手动修改 MAC 地址

Cube 生成的 MAC 地址是固定的,防止和测试环境中的其他设备相撞,需要打开文件 ethernetif.c 手动修改 MAC 地址,我这里提取了 芯片ID作为MAC地址的最后几位,这里是 STM32F767 的芯片ID的地址 0x1FF0F420
【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)_第4张图片

uint32_t sn0 = *(uint32_t *)(0x1FF0F420);//STM32 cpu id
MACAddr[3] = (sn0 >> 16) & 0xFF;
MACAddr[4] = (sn0 >> 8) & 0xFFF;
MACAddr[5] = sn0 & 0xFF;

3.2 Ping 测试

编译 -> 烧录 到单片机里面,拿一条和 PC 在同一局域网内的网线,根据 MX_LWIP_Init()函数下面设置的 IP 测试 ping 功能,下面是成功的结果图:
【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)_第5张图片


四、使用步骤

4.1 开启 Lwip Debug

打开 lwipopts.hLwip 开启 debug,并重写 打印函数,并打开 SNTPDebug 模式【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)_第6张图片
代码:

//开启 LWIP DEBUG 
#define LWIP_DEBUG 
  #include "bsp_printlog.h" 
  #define LWIP_PLATFORM_DIAG(x) do {print_log x;} while(0)

4.2 初始化 SNTP


/*!
* @brief Lwip 的 SNTP 初始化封装接口
*        执行条件:无
*
* @retval: 无
*/
void bsp_sntp_init(void)
{
     
	//设置 SNTP 的获取方式 -> 使用向服务器获取方式
	sntp_setoperatingmode(SNTP_OPMODE_POLL);
	
	//SNTP 初始化
	sntp_init();
	
	//加入授时中心的IP信息
	set_sntp_server_list();
}

4.3 加入服务器 IP列表

/*!
* @brief 设置 SNTP 的服务器地址,
* 		 加入多个 IP 以免某个 IP 获取不了时间
*        执行条件:无
*
* @retval: 无
*/
void set_sntp_server_list(void)
{
     
	uint32_t server_list[SNTP_MAX_SERVERS] =	{
       
													0x279148D2,  //国家授时中心
													0x42041876,
													0x5F066CCA,
													0x0B6C1978,
													0x0B0C5CB6,
													0x58066BCB,
													0x14731978,
													0xC51F70CA,
													0x521D70CA,
													0x820176CA,
													0x510176CA,
												};
	ip_addr_t sntp_server;
												
	for(int i = 0; i < SNTP_MAX_SERVERS; i++)
	{
     
		sntp_server.addr = server_list[i];
		sntp_setserver(i, &sntp_server);  // 国家授时中心
	}
}

4.4 编写处理函数

打开 lwipopts.h文件,定义 SNTP 的处理函数接口

//定义 Lwip SNTP 的 处理函数
#include "bsp_sntp.h"
#define SNTP_SET_SYSTEM_TIME		sntp_set_time

在应用代码中实现 sntp_set_time 函数接口,下面的例子是将获取到的时间戳经过转化成 年月日时分秒 设置到 RTC 中

/*!
* @brief SNTP 获取时间戳的处理函数
*        执行条件:无
*
* @param [in] : sntp 获取的时间戳
*
* @retval: 无
*/
void sntp_set_time(uint32_t sntp_time)
{
     
	if(sntp_time == 0)
	{
     
		print_log("sntp_set_time: wrong!@@\n");
		return;
	}
	
	print_log("sntp_set_time: c00, enter!\n");
	print_log("sntp_set_time: c01, get time = %u\n", sntp_time);

	struct tm *time;
	RTC_TimeTypeDef sTime = {
     0};
	RTC_DateTypeDef sDate = {
     0};

	sntp_time += (8 * 60 * 60); ///北京时间是东8区需偏移8小时

	time = localtime(&sntp_time);

	/*
	 * 设置 RTC 的 时间
	 */
	sTime.Hours = time->tm_hour;
	sTime.Minutes = time->tm_min;
	sTime.Seconds = time->tm_sec;
	sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sTime.StoreOperation = RTC_STOREOPERATION_RESET;
	if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
	{
     
		Error_Handler();
	}
	
	/*
	 * 设置 RTC 的 日期
	 */
	sDate.WeekDay = time->tm_wday;
	sDate.Month = (time->tm_mon) + 1;
	sDate.Date = time->tm_mday;
	sDate.Year = (time->tm_year) + 1900 - 2000;
	if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
	{
     
		Error_Handler();
	}

	print_log("sntp_set_time: c02, decode time: 20%d-%02d-%02d %d:%d:%d\n", \
				sDate.Year, sDate.Month, sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds);
	
	print_log("sntp_set_time: c03, test get = %u\n", get_timestamp());
	print_log("sntp_set_time: c04, set rtc time done\n");
}

4.5 从RTC中获取时间戳

/*!
 * @brief 获取当前时间戳
 *
 * @param [in] none
 *
 * @retval 当前时间戳
 */
uint32_t get_timestamp(void)
{
     
    struct tm stm;
    static RTC_DateTypeDef g_Date = {
     0};
    static RTC_TimeTypeDef g_Time = {
     0};

    ///获取时间必须在获取日期前
    HAL_RTC_GetTime(&hrtc, &g_Time, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc, &g_Date, RTC_FORMAT_BIN);

    stm.tm_year = g_Date.Year + 100;    //RTC_Year rang 0-99,but tm_year since 1900

    stm.tm_mon = g_Date.Month - 1;      //RTC_Month rang 1-12,but tm_mon rang 0-11

    stm.tm_mday = g_Date.Date;          //RTC_Date rang 1-31 and tm_mday rang 1-31

    stm.tm_hour = g_Time.Hours;         //RTC_Hours rang 0-23 and tm_hour rang 0-23

    stm.tm_min = g_Time.Minutes;        //RTC_Minutes rang 0-59 and tm_min rang 0-59

    stm.tm_sec = g_Time.Seconds;

	return (mktime(&stm) - (8 * 60 * 60));///配置时由于东八区增加8小时,现为时间戳,需减去
}

5.6 最终效果

使用 RTT 连接 STM32 (详见我的教程【嵌入式小技巧】stm32 实现 Segger RTT 打印(超详细))
编译、烧录到单片机,可以看到获取时间戳成功,获取的时间经过自己的函数,设置到RTC中,获取的时候也获取相同
【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)_第7张图片


总结

以上是 STM32 + LWIP 如何 使用 SNTP 获取网络时间 的全部内容,本文介绍了获取网络时间的一个方法,让嵌入式物联网设备能够时钟和网络同步。


更多阅读推荐
  • 【嵌入式实战】STM32+Lwip 实现 DHCP+HostName(超详细) : 在 DHCP 的基础上 Ping 域名的方式获取 DHCP 的 IP
  • 【嵌入式实战】STM32+FreeRTOS+LWIP+WolfSSL 实现 HTTPS(超详细)
  • 【嵌入式小技巧】stm32 实现 Segger RTT 打印(超详细)

我是 HinGwenWoong ,一个有着清晰目标不停奋斗的程序猿,热爱技术,喜欢分享,码字不易,如果帮到您,请帮我在屏幕下方点赞 ,您的点赞可以让技术传播得更远更广,谢谢!


授权须知

  1. 原创文章在推送两天后才可进行转载
  2. 转载文章,禁止声明原创
  3. 不允许直接二次转载,转载请根据原文链接联系作者
  4. 若无需改版,在文首清楚标注作者及来源/原文链接,并删除【原创声明】,即可直接转载。
    但对于未注明转载来源/原文链接的文章,我将保留追述的权利。

作者:HinGwenWoong
一个有着清晰目标不停奋斗的程序猿,热爱技术,喜欢分享,共同进步!
CSDN: HinGwenWoong
原文链接:【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)

  1. 若需要修改文章的排版,请根据原文链接联系作者
  2. 再次感谢您的认可,转载请遵守如上转载须知!

你可能感兴趣的:(嵌入式SMT32,stm32,嵌入式,物联网,网络)