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

   日期:2020-09-01     浏览:547    评论:0    
核心提示:文章目录前言一、SNTP 是什么?二、Cube 快速配置2.1 SNTP 设置2.2 开启 RTC三、使用步骤3.1 开启 Lwip Debug3.2 初始化 SNTP3.2 加入服务器 IP列表3.2 编写处理函数3.3 从RTC中获取时间戳3.4 最终效果总结前言物联网的设备,离不开时间戳的使用,下面介绍 STM32 + LWIP 如何 使用 SNTP 获取网络时间码字不易,如果帮到您,请帮我在屏幕下方点赞 ???? ,您的点赞可以让技术传播得更远更广,谢谢!一、SNTP 是什么?SN

文章目录

  • 前言
  • 一、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 最终效果
  • 总结

前言

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

码字不易,如果帮到您,请帮我在屏幕下方点赞 ,您的点赞可以让技术传播得更远更广,谢谢!

一、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

2.3 LWIP SNTP 配置

2.4 开启 STM32 RTC

三、生成工程的简单测试

3.1 手动修改 MAC 地址

Cube 生成的 MAC 地址是固定的,防止和测试环境中的其他设备相撞,需要打开文件 ethernetif.c 手动修改 MAC 地址,我这里提取了 芯片ID作为MAC地址的最后几位,这里是 STM32F767 的芯片ID的地址 0x1FF0F420

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 功能,下面是成功的结果图:

四、使用步骤

4.1 开启 Lwip Debug

打开 lwipopts.hLwip 开启 debug,并重写 打印函数,并打开 SNTPDebug 模式
代码:

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

4.2 初始化 SNTP



void bsp_sntp_init(void)
{
	//设置 SNTP 的获取方式 -> 使用向服务器获取方式
	sntp_setoperatingmode(SNTP_OPMODE_POLL);
	
	//SNTP 初始化
	sntp_init();
	
	//加入授时中心的IP信息
	set_sntp_server_list();
}

4.3 加入服务器 IP列表


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 中


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);

	
	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();
	}
	
	
	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中获取时间戳


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 获取网络时间 的全部内容,本文介绍了获取网络时间的一个方法,让嵌入式物联网设备能够时钟和网络同步。

码字不易,如果帮到您,请帮我在屏幕下方点赞 ,您的点赞可以让技术传播得更远更广,谢谢!

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服