• stm32 同步NTP服务器的时间


    https://blog.csdn.net/haidscs/article/details/102733130

    首先找一个可用的ntp服务器,这里以阿里的ntp服务器为例:ntp1.aliyun.com。

    把域名的ip解析出来:

    因为ntp服务器是udp协议,ip:120.25.115.20 端口号:123,格式是接收48个字节,第一个字节以0xa3(版本4) 、0x1b, (版本3)、0x13(版本2) 、0x0b(版本1),返回的数据中带有时间。

    ntp协议的报文格式:

    NTP报文格式如上图所示,它的字段含义参考如下:

    LI 闰秒标识器,占用2个bit
    VN 版本号,占用3个bits,表示NTP的版本号,现在为3
    Mode 模式,占用3个bits,表示模式
    stratum(层),占用8个bits
    Poll 测试间隔,占用8个bits,表示连续信息之间的最大间隔
    Precision 精度,占用8个bits,,表示本地时钟精度
    Root Delay根时延,占用8个bits,表示在主参考源之间往返的总共时延
    Root Dispersion根离散,占用8个bits,表示在主参考源有关的名义错误
    Reference Identifier参考时钟标识符,占用8个bits,用来标识特殊的参考源    
    参考时间戳,64bits时间戳,本地时钟被修改的最新时间。
    原始时间戳,客户端发送的时间,64bits。
    接受时间戳,服务端接受到的时间,64bits。
    传送时间戳,服务端送出应答的时间,64bits。
    认证符(可选项) 

    转化举例:

    把十六进制数转换十进制数,再减去1900-1970的时间差(2208988800秒)。0xE15C2D5B->3780914523 -2208988800=1571925723 时间转化工具出来 。补充:有些服务器需要加上北京时间差(东八区的时区 【8*60*60】)

    以上是在Windows上验证。

    下面以stm32获取ntp服务器的时间

    #define NTP_TIMESTAMP_DELTA 2208988800ull

    #define DEV_LAN_NTP_UDP_REV_BUFF_MAX      200
    u8      rbuf[DEV_LAN_UDP_REV_BUFF_MAX+1]={0};
    u16     rlen=0;
    static struct udp_pcb            *lwip_ntp_udp_pcb=0;
    static unsigned char            *lwip_ntp_udp_rev_buff=0;
    static unsigned short            lwip_ntp_udp_rev_buff_max=0;
    static unsigned short            *lwip_ntp_udp_rev_len=0; 

    //发送

    err_t lwip_ntp_udp_ip_send(unsigned char *data, unsigned long len, unsigned char *send_ip, unsigned short send_port)

    {
        struct pbuf *send_pbuf;
        unsigned long i=0;
        struct ip_addr sip;
        err_t  err=0;
        
        IP4_ADDR(&sip, send_ip[0], send_ip[1], send_ip[2], send_ip[3]);
        if(lwip_ntp_udp_pcb == NULL)
          return -1;
        for (i=0; i<len; i+=200)
        {
            send_pbuf = pbuf_alloc(PBUF_RAW,200, PBUF_REF);
            if (send_pbuf !=NULL)
            {
                send_pbuf->payload = (void*)&data[i];
                if (i+200<=len) send_pbuf->tot_len = 200;
                else send_pbuf->tot_len=len%200;
                err=udp_sendto(lwip_ntp_udp_pcb, send_pbuf, &sip, send_port);
                pbuf_free(send_pbuf); 
                if (err!=0) break;                    
            }
        }
        return err;
    }

    //接收

    void lwip_ntp_udp_rev(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
    {
        struct pbuf *q=0;
        
        if (p !=NULL)
        {
             lwip_ntp_udp_rev_addr = *addr;
             lwip_ntp_udp_rev_port = port; 
             
             for (q=p; q!=NULL; q=q->next)
             {
                 if ((q->tot_len+*lwip_ntp_udp_rev_len)<=lwip_ntp_udp_rev_buff_max)
                 {
                     if (q->tot_len>=1472) 
                     {
                         memcpy(&lwip_ntp_udp_rev_buff[*lwip_ntp_udp_rev_len],q->payload,1472);
                         *lwip_ntp_udp_rev_len+=1472;
                     }
                     else 
                     {
                         memcpy(&lwip_ntp_udp_rev_buff[*lwip_ntp_udp_rev_len],q->payload,q->tot_len);
                         *lwip_ntp_udp_rev_len+=q->tot_len;                    
                     }
                 }
                 else break;
             }     
             pbuf_free(p);
        }
        else
        {
            udp_remove(upcb);
        }
    }

    //创立udp连接

    err_t lwip_ntp_udp_connect_init(unsigned short src_port)
    {
         err_t err=0;
         struct ip_addr rmtipaddr;
         lwip_ntp_udp_close();
         
         lwip_ntp_udp_pcb = udp_new();
         if (lwip_ntp_udp_pcb)
         {
            IP4_ADDR(&rmtipaddr,120,25,115,20);//将点分10进制IP转为4字节变量,因为IP控制块里面通过32位存储IP地址。
            err = udp_bind(lwip_ntp_udp_pcb, IP_ADDR_ANY, src_port);//绑定本地的ip和端口
            //err=udp_connect(lwip_ntp_udp_pcb,&rmtipaddr,123);   // udp连接,NTP使用的是UDP和123端口          
            udp_recv(lwip_ntp_udp_pcb, lwip_ntp_udp_rev, NULL);
         }
         return err;
    }
    void lwip_ntp_udp_rev_init(unsigned char *rev_buff, unsigned short rev_buff_max, unsigned short *rev_len)
    {
        *rev_len=0;
        lwip_ntp_udp_rev_buff=rev_buff;
        lwip_ntp_udp_rev_buff_max=rev_buff_max;
        lwip_ntp_udp_rev_len=rev_len;
    }
    void lwip_ntp_udp_close(void)
    {
        udp_remove(lwip_ntp_udp_pcb);
    }

    void main()
    {
        u8 buuf[48] = {0x1b};
        u8 ip[4] ={120,25,115,20};   
        u32 NtpTime = 0;

        lwip_ntp_udp_connect_init(666);//创建连接
        lwip_ntp_udp_rev_init(rbuf,DEV_LAN_UDP_REV_BUFF_MAX,&rlen);//分配内存
        lwip_ntp_udp_ip_send(buuf,48,ip,123);//向addr的123端口发送报文,NTP使用的是UDP和123端口

        if(rlen>0)
        {
            NtpTime = rbuf[0]<<24 | rbuf[1]<<16 | rbuf[2]<<8 | rbuf[3];
            NtpTime -= NTP_TIMESTAMP_DELTA;
        }
        while(1);
    }

  • 相关阅读:
    sqlmap使用教程-安装教程
    SQL注入攻击总结
    mysql 创建函数失败解决办法,版本 8.0.26
    【VUE3.0体验】axios引入以及property的替代
    异化的房价周期
    vue使用websoket
    spring依赖注入方式及springBoot如何解决循环依赖
    范型的正确使用
    mysql GROUP_CONCAT使用
    Mybatis-MySQL 中使用IFNUL
  • 原文地址:https://www.cnblogs.com/qinlongqiang/p/13744309.html
Copyright © 2020-2023  润新知