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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM