当前位置:   article > 正文

初出茅庐的小李博客之机智云获取网络实时时间(NTP)_获取网络时间

获取网络时间

机智云获取网络实时时间

机智云代码中其实这么一个函数gizwitsGetNTP( )可以获取网络时间,今天就在STM32F407上教大家如何通过机智云获取NTP网络时间。

简单介绍一下NTP:

网络时间同步现在有2种同步协议NTP和PTP,NTP与PTP不同在于时间戳的产生位置。NTP是通过软件来记录协议相关网络包的发出和到达时刻,同步精度可以达到优于10ms。

NTP 是网络时间协议(Network Time Protocol),他用来同步网络中各个计算机时间的协议。在机智云串口协议中,支持获取 NTP 网络同步时间的功能。

网络时间同步:

网络时间同步是指将计算机或设备的时间与网络上的时间源保持一致。

NTP网络时间同步服务器:

NTP网络时间服务器是为网络设备提供精确、标准、安全、可靠和多功能的时间服务的最佳解决方案,能提供精确的同步时钟信号

我们实现的原理就是通过编程控制Wifi模块连上机智云的网络时间服务器从而获取一个跟网络同步的时间,这个时间可以有很多用途

例如可以作为校准RTC等。

具体方式:

找到API接口函数:

在这里插入图片描述

分析API接口函数:

/**
* @brief Get the the network time

* Protocol 4.13:"Device MCU send" of "the MCU requests access to the network time"

* @param[in] none
* @return none
*/
void gizwitsGetNTP(void)
{
    int32_t ret = 0;
    protocolCommon_t getNTP;

    gizProtocolHeadInit((protocolHead_t *)&getNTP);
    getNTP.head.cmd = CMD_GET_NTP;
    getNTP.head.sn = gizwitsProtocol.sn++;
    getNTP.head.len = exchangeBytes(sizeof(protocolCommon_t)-4);
    getNTP.sum = gizProtocolSum((uint8_t *)&getNTP, sizeof(protocolCommon_t));
    ret = uartWrite((uint8_t *)&getNTP, sizeof(protocolCommon_t));
    if(ret < 0)
    {
        GIZWITS_LOG("ERR[NTP]: uart write error %d \n", ret);
    }

    gizProtocolWaitAck((uint8_t *)&getNTP, sizeof(protocolCommon_t));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

从源码中可以看到:

第一步:定义结构体变量

protocolCommon_t getNTP;//定义了一个结构体变量

构体类型如下:


/** Protocol common data frame(4.2、4.4、4.6、4.9、4.10) protocol structure */
typedef struct
{
    protocolHead_t          head;                   ///< Protocol standard header structure
    uint8_t                 sum;                    ///< checksum
} protocolCommon_t;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这个结构体里面有两个成员:
第1个仍然是一个结构体:

/** Protocol standard header structure */
typedef struct
{
    uint8_t   head[2];       ///< The head is 0xFFFF
    uint16_t  len;  ///< From cmd to the end of the entire packet occupied by the number of bytes
    uint8_t   cmd;                    ///< command
    uint8_t   sn;                     ///< 
    uint8_t   flags[2];               ///< flag,default is 0
} protocolHead_t;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

第2个则是一个校验结果sum

第二步:填充结构体信息:

填充内容包括:0xFF 0xFF 数据桢头

命令字节: cmd

sn: sn

字节数目:len

校验结果:sum


gizProtocolHeadInit((protocolHead_t *)&getNTP);
getNTP.head.cmd = CMD_GET_NTP;
getNTP.head.sn = gizwitsProtocol.sn++;
getNTP.head.len = exchangeBytes(sizeof(protocolCommon_t)-4);
getNTP.sum = gizProtocolSum((uint8_t *)&getNTP, sizeof(protocolCommon_t));
ret = uartWrite((uint8_t *)&getNTP, sizeof(protocolCommon_t));

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

校验采用累积和校验:

/*
* @brief Checksum calculation
* @param [in] buf   : data 
* @param [in] len   : data len
* @return sum : Checksum
*/
  uint8_t ICACHE_FLASH_ATTR gizProtocolSum(uint8_t *buf, uint32_t len)
  {
    uint8_t     sum = 0;
    uint32_t    i = 0;
    if(buf == NULL || len <= 0)
    {
        return 0;
    }
    for(i=2; i<len-1; i++)
    {
        sum += buf[i];
    }
    return sum;
  }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

第三步把组包好的数据发送到Wifi模块

调用接口:

/*
* @brief uartWrite
* Serial write operation, send data to the WiFi module
* @param buf      : Data address
* @param len       : Data length
* @return : Not 0,Serial send success;
*           -1,Input Param Illegal
*/
int32_t uartWrite(uint8_t *buf, uint32_t len)
{
    uint32_t i = 0;
    if(NULL == buf)
    {
        return -1;
    }
    #ifdef PROTOCOL_DEBUG   //如果宏定义了打印的宏 则打印日志  MCU发送到wifi的信息
    GIZWITS_LOG("MCU2WiFi[%4d:%4d]: ", gizGetTimerCount(), len);
    for(i=0; i<len; i++)
    {
        GIZWITS_LOG("%02x ", buf[i]);
    }
    GIZWITS_LOG("\n");
    #endif

    for(i=0; i<len; i++)
    {
           //MCU跟WiFi通信的接口底层仍然是串口通信  这里是串口2
			USART_SendData(USART2, buf[i]);
			while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
            if(i >=2 && buf[i] == 0xFF)//除了帧头部分的0xFF原样发 后面遇到的都要在后面补上0x55 这个是协议规定
            {
                //MCU跟WiFi通信的接口底层仍然是串口通信  这里是串口2
                USART_SendData(USART2,0x55);
                while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
            }
    }
    return len;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

第四步:根据写入的结果打印日志信息


    ret = uartWrite((uint8_t *)&getNTP, sizeof(protocolCommon_t));
    if(ret < 0)
    {
        GIZWITS_LOG("ERR[NTP]: uart write error %d \n", ret);//返回值是-1则代表出现了错误
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

第五步:把定义的结构体部分关键信息赋值到WaitAck这个结构体中

gizProtocolWaitAck((uint8_t *)&getNTP, sizeof(protocolCommon_t));

/*
* @brief Protocol ACK check processing function
* @param [in] data            : data adress
* @param [in] len             : data length
* @return 0, suceess; other, failure
*/
  static int8_t gizProtocolWaitAck(uint8_t *gizdata, uint32_t len)
  {
    if(NULL == gizdata)
    {
        GIZWITS_LOG("ERR: data is empty \n");
        return -1;
    }
    memset((uint8_t *)&gizwitsProtocol.waitAck, 0, sizeof(protocolWaitAck_t));//
    memcpy((uint8_t *)gizwitsProtocol.waitAck.buf, gizdata, len);
    gizwitsProtocol.waitAck.dataLen = (uint16_t)len;
    gizwitsProtocol.waitAck.flag = 1;
    gizwitsProtocol.waitAck.sendTime = gizGetTimerCount();
    return 0;
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

protocolWaitAck_t结构体成员如下


/** resend strategy structure */
typedef struct
{
    uint8_t     num;                    ///< resend times
    uint8_t     flag;                   ///< 1,Indicates that there is a need to wait for the ACK;0,Indicates that there is no need to wait for the ACK
    uint8_t      buf[MAX_PACKAGE_LEN];   ///< resend data buffer
    uint16_t     ataLen;                ///< resend data length
    uint32_t     sendTime;               ///< resend time
} protocolWaitAck_t;
                        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

改结构体嵌套在gizwitsProtocol_t中
在这里插入图片描述

/** Protocol main and very important struct */
typedef struct
{
    uint8_t issuedFlag;                             ///< P0 action type
    uint8_t protocolBuf[MAX_PACKAGE_LEN];           ///< Protocol data handle buffer
    uint8_t transparentBuff[MAX_PACKAGE_LEN];       ///< Transparent data storage area
    uint32_t transparentLen;                        ///< Transmission data length
    
    uint32_t sn;                                    ///< Message SN
    uint32_t timerMsCount;                          ///< Timer Count 
    
    protocolWaitAck_t waitAck;                      ///< Protocol wait ACK data structure
    
    eventInfo_t issuedProcessEvent;                 ///< Control events
    eventInfo_t wifiStatusEvent;                    ///< WIFI Status events
    eventInfo_t NTPEvent;                           ///< NTP events
    eventInfo_t moduleInfoEvent;                    ///< Module Info events

	gizwitsReport_t reportData;                     ///< The protocol reports data for standard product
    dataPoint_t gizCurrentDataPoint;                ///< Current device datapoints status
    dataPoint_t gizLastDataPoint;                   ///< Last device datapoints status
    moduleStatusInfo_t wifiStatusData;              ///< WIFI signal intensity
    protocolTime_t TimeNTP;                         ///< Network time information
#if MODULE_TYPE
    gprsInfo_t   gprsInfoNews;
#else  
    moduleInfo_t  wifiModuleNews;                   ///< WIFI module Info
#endif
	
}gizwitsProtocol_t; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

至此代码的分析完毕,我们只需要大概的流程即可,里面实现的细节暂且不用深究,接下来我们来写一个代码调用该API并把获取到的网络实时时间通过串口调试工具进行打印查看。

编写应用代码方式:

既然是获取网络时间我们就需要等到入网成功之后才可以获取因为只有这样获取到的时间才是准确的也只有这样我们才能获取到准确的时间。

查找连上WIFI的判断我们定义一个全部变量来表示联网成功!

首先在 main.c文件中,定义一个 wifi_sta 变量,用来记录 wifi 连接状态,当模组连上机智云的服务器时,会返回WIFI_CON_M2M 的事件,断开时返回WIFI_DISCON_M2M,所以我们就在这两个地方添加标志位并且要引入外部变量,否则会报错,如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3nZo3s2e-1688801965975)(C:\Users\23206\AppData\Roaming\Typora\typora-user-images\image-20230708145640728.png)]
在这里插入图片描述

部分代码如下:

    case WIFI_CON_M2M:
            wifi_sta = 1;//连上网络修改标志位为1
            GIZWITS_LOG("wifi_sta = 1\n");
            break;
        case WIFI_DISCON_M2M:
            wifi_sta = 0;//断开网络修改标志位为0
            GIZWITS_LOG("wifi_sta = 0\n");
            break;
        case WIFI_RSSI:
            GIZWITS_LOG("RSSI %d\n", wifiData->rssi);
            break;
        case TRANSPARENT_DATA:
            GIZWITS_LOG("TRANSPARENT_DATA \n");
            //user handle , Fetch data from [data] , size is [len]
            break;
        case WIFI_NTP:
            GIZWITS_LOG("WIFI_NTP : [%d-%d-%d %02d:%02d:%02d][%d] \n",ptime->year,ptime->month,ptime->day,ptime->hour,ptime->minute,ptime->second,ptime->ntp);
            break;
        case MODULE_INFO:
            GIZWITS_LOG("MODULE INFO ...\n");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

获取时间的代码实现:

打印代码:

在这里插入图片描述

获取代码:


void userHandle(void)
{
	static uint32_t count_time = 0;
	count_time++;
	delay_nms(100);
	if(count_time %10==0)
	{
		if(wifi_sta==1)
		{
				gizwitsGetNTP();//每1秒调用一次网络时间 前提是连上网络之后	
		}
		else if(wifi_sta ==0)
		{
			printf("未连接到网络...\r\n");
		}
	}
	currentDataPoint.valuebeep = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_0);
	currentDataPoint.valueyzh  = GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_4);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

实现结果:

在这里插入图片描述

网络时间就是当前时间:2023年7月8日15点31分08秒 这个时间如果用于更新RTC实现并且实现掉电存储就十分准确了

至此:机智云网络获取时间已经完成。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/646690
推荐阅读
相关标签
  

闽ICP备14008679号