ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

通过sntp同步系统时间

2019-08-08 11:38:49  阅读:667  来源: 互联网

标签:02d 同步 rtc sntp 系统 tp tm time


通过sntp同步系统时间

小型物联网设备,很少有接口提供给用户进行数据交互,那么我们设备的系统时间只能够通过获取网络时间后,再更新到本地。那么,就少不了使用sntp协议。
ntp协议:NTP(Network Time Protocol)网络时间协议基于UDP,用于网络时间同步的协议,使网络中的计算机时钟同步到UTC(通用协调时,可以理解为0时区的时间,领先东八区8个小时),再配合各个时区的偏移调整就能实现精准同步对时功能。
sntp协议:简单网络时间协议(Simple Network Time Protocol),由 NTP 改编而来,主要用来同步因特网中的计算机时钟。在 RFC2030 中定义。主要运用于小型的设备,占用内存小。

注意:NTP时间戳从1900年开始记秒数,而UNIX时间戳从1970年开始记秒数

一.常用时间函数介绍

首先介绍time.h中的常用api;

1.time();

函数原型:time_t time(time_t *t)
介绍:C 库函数 time_t time(time_t *seconds) 返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位。如果 seconds 不为空,则返回值也存储在变量 seconds 中。
返回值:1970-01-01 00:00:00 起至今经过的时间,单位秒

2.ctime()

函数原型:char *ctime(const time_t *timer)
介绍:C 库函数 char *ctime(const time_t *timer) 返回一个表示当地时间的字符串,当地时间是基于参数 timer。
返回的字符串格式如下: Www(星期) Mmm (月)dd(日) hh:mm:ss(时分秒) yyyy(年)
返回值:是基于参数 timer计算,1970-01-01 00:00:00 经过timer时间后的时间字符串

3.localtime()

函数原型:struct tm *localtime(const time_t *timer)
介绍:C 库函数 struct tm *localtime(const time_t *timer) 使用 timer 的值来填充 tm 结构。timer 的值被分解为 tm 结构,并用本地时区表示。
返回值:填充tm结构体,表示1970-01-01 00:00:00 经过timer时间后的时间结构体
注意:年份输出需要+1900,月份输出需要+1才能得到准确的utc时间
tm结构体:

struct tm {
   int tm_sec;         /* 秒,范围从 0 到 59                */
   int tm_min;         /* 分,范围从 0 到 59                */
   int tm_hour;        /* 小时,范围从 0 到 23                */
   int tm_mday;        /* 一月中的第几天,范围从 1 到 31                    */
   int tm_mon;         /* 月份,范围从 0 到 11                */
   int tm_year;        /* 自 1900 起的年数                */  
   int tm_wday;        /* 一周中的第几天,范围从 0 到 6                */
   int tm_yday;        /* 一年中的第几天,范围从 0 到 365                    */
   int tm_isdst;       /* 夏令时                        */    
};

4.mktime()

函数原型:time_t mktime(struct tm * timeptr)
介绍:C库函数time_t mktime(struct tm * timeptr)把timeptr所指向的结构转换为一个依据本地时区的time_t值。
参数:tm结构体,同上。
返回值:将参数timeptr所指的tm结构数据转换成从公元1970年1月1日0时0分0秒算起至今的UTC时间所经过的秒数。

二.功能实现

下面分析某项目将网络时间更新到本地的流程,平台可能存在差异,实现流程大致相同的。
源码分析
创建一个sntp客户端,目的从网络中获取时间,更新。

static void sntp_client(void)
{
    /** Set this to 1 to allow config of SNTP server(s) by DNS name */
#if (!SNTP_SERVER_DNS)
    struct ip4_addr test_addr;
#endif
    hal_rtc_time_t r_time = {6,6,6,1,1,6,0};
    hal_rtc_status_t ret = HAL_RTC_STATUS_OK;

    //Set RTC to a incorrect time.
    
    //设置默认系统时间
    ret = hal_rtc_set_time(&r_time);
    // LOG_I(sntp_client_main, "[%d]cur_time[%d:%d:%d]", ret, r_time.rtc_hour, r_time.rtc_min, r_time.rtc_sec);

	// 设置sntp服务器ip地址或者DNS(目的地址),从什么服务器获取时间
    /** Set this to 1 to allow config of SNTP server(s) by DNS name */
#if SNTP_SERVER_DNS
    sntp_setservername(0, "1.cn.pool.ntp.org");
    sntp_setservername(1, "1.hk.pool.ntp.org");
#else
    IP4_ADDR(&test_addr, 213, 161, 194, 93);
    sntp_setserver(0, (const ip_addr_t *)(&test_addr));
    IP4_ADDR(&test_addr, 129, 6, 15, 29);
    sntp_setserver(1, (const ip_addr_t *)(&test_addr));
#endif

	//初始化设置
    sntp_init();

   // LOG_I(sntp_client_main, "SNTP init done");
}
/**
 * Initialize this module.
 * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
 */
void
sntp_init(void)
{
#ifdef SNTP_SERVER_ADDRESS
#if SNTP_SERVER_DNS
  sntp_setservername(0, SNTP_SERVER_ADDRESS);
#else
#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
#endif
#endif /* SNTP_SERVER_ADDRESS */

  if (sntp_pcb == NULL) {
    SNTP_RESET_RETRY_TIMEOUT();
    
    //创建udp,用于接收udp包,时间数据
    sntp_pcb = udp_new();
    LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
    if (sntp_pcb != NULL) {
    
    //有数据,处理接收数据,同步到本地,由sntp_recv处理。
      udp_recv(sntp_pcb, sntp_recv, NULL);
#if SNTP_STARTUP_DELAY
      sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
#else
      sntp_request(NULL);
#endif
    }
  }
}

上述程序执行成功,再次获取本地时间,本地时间就会被更新。

uint32_t get_rtc_stamp_time(char * cur_time)
{
	hal_rtc_time_t r_time;
    hal_rtc_status_t ret = HAL_RTC_STATUS_OK;
	
	time_t timep = 0;    
	struct tm p;
	struct tm *tp;
	
	//获取本地时间,是utc时间
	ret = hal_rtc_get_time(&r_time);
	if (ret == HAL_RTC_STATUS_OK)
	{
		// printf("cur_time[%d,%d,%d,%d]\r\n", r_time.rtc_year, r_time.rtc_mon, r_time.rtc_day, r_time.rtc_week);
		// printf("[%d]cur_time[%d:%d:%d]\r\n", ret, r_time.rtc_hour, r_time.rtc_min, r_time.rtc_sec);
	#if 1
		p.tm_year = r_time.rtc_year + 2000 - 1900;//DATA%100 + 2000 -1900;
		p.tm_mon = r_time.rtc_mon-1;//(DATA/100) %100 -1;
		p.tm_mday = r_time.rtc_day;//DATA/10000;
		
		p.tm_hour= r_time.rtc_hour;//(UTCTime / 10000);
		p.tm_min= r_time.rtc_min;//(UTCTime / 100)%100;
		p.tm_sec= r_time.rtc_sec;//UTCTime % 100;
		
		//从utc时间转换成东八区时间
		timep=mktime(&p);
		timep = timep+28800;
		tp = localtime(&timep);  //0时区与东八区相差8个小时
		//printf("%d %d %d %d %d %d\n",(tp->tm_year+1900), (tp->tm_mon+1), tp->tm_mday,tp->tm_hour, tp->tm_min, tp->tm_sec);
		sprintf(cur_time,"%02d-%02d-%02d %02d:%02d:%02d",(tp->tm_year+1900), (tp->tm_mon+1), tp->tm_mday,tp->tm_hour, tp->tm_min, tp->tm_sec);
		
		//下图log
		printf("%02d-%02d-%02d %02d:%02d:%02d",(tp->tm_year+1900), (tp->tm_mon+1), tp->tm_mday,tp->tm_hour, tp->tm_min, tp->tm_sec);
	#endif
		//sprintf(cur_time,"%d-%02d-%02d %d %02d:%02d:%02d",r_time.rtc_year, r_time.rtc_mon, r_time.rtc_day, r_time.rtc_week,r_time.rtc_hour, r_time.rtc_min, r_time.rtc_sec);

		
	}else{
		printf("get_rtc_stamp_time fail\r\n");
	}
	return timep;
}

测试log如下图所示
在这里插入图片描述

标签:02d,同步,rtc,sntp,系统,tp,tm,time
来源: https://blog.csdn.net/qq_38240926/article/details/98847270

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有