我正在尝试与使用WiFiShield发送UDP数据包的NTP服务器联系,以同步Arduino Uno上的时间。我已经花了几个小时阅读不同的教程和论坛,但没有成功。与我的代码无关,http://arduino.cc/en/Tutorial/UdpNTPClient的示例也不起作用。我没有回应。使用wireshark之​​后,我什至不确定Arduino是否甚至发送了数据包。

我试过的

  • 将Arduino IDE 1.0.3与IDE 1.0.5的WiFi库一起使用(因为WiFiUdp在1.0.3中不存在)或使用Arduino IDE 1.0.5
  • 使用IDE 1.0.5随附的固件升级WiFiShield的固件。但是,我无法检查它是否成功或之前安装了哪个固件版本。
  • 其他示例(例如SimpleWebServerWiFi)正在运行。
  • 使用相同的WiFi在笔记本电脑上设置ntp服务器并联系该服务器。
  • 更改目标服务器,检查http://tf.nist.gov/tf-cgi/servers.cgi的可用性
  • 使用wireshark(本地服务器)或wireshark +本地arp欺骗检查Arduino发送/接收的数据包,以通过wireshark(公共(public)服务器)路由流量,但在两种情况下我都无法检测到任何数据包。
  • 检查definition of the NTP,但创建数据包看起来不错。
  • 增加响应的等待时间。

  • 为了让您放心,我将代码更改为不每10秒请求一次时间,但是它似乎始终都没有发送请求...

    有小费吗?

    来自http://arduino.cc/en/Tutorial/UdpNTPClient的代码:
    /*
    
     Udp NTP Client
    
     Get the time from a Network Time Protocol (NTP) time server
     Demonstrates use of UDP sendPacket and ReceivePacket
     For more on NTP time servers and the messages needed to communicate with them,
     see http://en.wikipedia.org/wiki/Network_Time_Protocol
    
     created 4 Sep 2010
     by Michael Margolis
     modified 9 Apr 2012
     by Tom Igoe
    
     This code is in the public domain.
    
     */
    
    #include <SPI.h>
    #include <WiFi.h>
    #include <WiFiUdp.h>
    
    int status = WL_IDLE_STATUS;
    char ssid[] = "mynetwork";  //  your network SSID (name)
    char pass[] = "mypassword";       // your network password
    int keyIndex = 0;            // your network key Index number (needed only for WEP)
    
    unsigned int localPort = 2390;      // local port to listen for UDP packets
    
    IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
    
    const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
    
    byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
    
    // A UDP instance to let us send and receive packets over UDP
    WiFiUDP Udp;
    
    void setup()
    {
      // Open serial communications and wait for port to open:
      Serial.begin(9600);
      while (!Serial) {
        ; // wait for serial port to connect. Needed for Leonardo only
      }
    
      // check for the presence of the shield:
      if (WiFi.status() == WL_NO_SHIELD) {
        Serial.println("WiFi shield not present");
        // don't continue:
        while(true);
      }
    
    
      // attempt to connect to Wifi network:
      while ( status != WL_CONNECTED) {
        Serial.print("Attempting to connect to SSID: ");
        Serial.println(ssid);
        // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
        status = WiFi.begin(ssid, pass);
    
        // wait 10 seconds for connection:
        delay(10000);
      }
    
      Serial.println("Connected to wifi");
      printWifiStatus();
    
      Serial.println("\nStarting connection to server...");
      Udp.begin(localPort);
    }
    
    void loop()
    {
      sendNTPpacket(timeServer); // send an NTP packet to a time server
        // wait to see if a reply is available
      delay(1000);
      Serial.println( Udp.parsePacket() );
      if ( Udp.parsePacket() ) {
        Serial.println("packet received");
        // We've received a packet, read the data from it
        Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer
    
        //the timestamp starts at byte 40 of the received packet and is four bytes,
        // or two words, long. First, esxtract the two words:
    
        unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
        unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
        // combine the four bytes (two words) into a long integer
        // this is NTP time (seconds since Jan 1 1900):
        unsigned long secsSince1900 = highWord << 16 | lowWord;
        Serial.print("Seconds since Jan 1 1900 = " );
        Serial.println(secsSince1900);
    
        // now convert NTP time into everyday time:
        Serial.print("Unix time = ");
        // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
        const unsigned long seventyYears = 2208988800UL;
        // subtract seventy years:
        unsigned long epoch = secsSince1900 - seventyYears;
        // print Unix time:
        Serial.println(epoch);
    
    
        // print the hour, minute and second:
        Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
        Serial.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs per day)
        Serial.print(':');
        if ( ((epoch % 3600) / 60) < 10 ) {
          // In the first 10 minutes of each hour, we'll want a leading '0'
          Serial.print('0');
        }
        Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
        Serial.print(':');
        if ( (epoch % 60) < 10 ) {
          // In the first 10 seconds of each minute, we'll want a leading '0'
          Serial.print('0');
        }
        Serial.println(epoch %60); // print the second
      }
      // wait ten seconds before asking for the time again
      delay(10000);
    }
    
    // send an NTP request to the time server at the given address
    unsigned long sendNTPpacket(IPAddress& address)
    {
      //Serial.println("1");
      // set all bytes in the buffer to 0
      memset(packetBuffer, 0, NTP_PACKET_SIZE);
      // Initialize values needed to form NTP request
      // (see URL above for details on the packets)
      //Serial.println("2");
      packetBuffer[0] = 0b11100011;   // LI, Version, Mode
      packetBuffer[1] = 0;     // Stratum, or type of clock
      packetBuffer[2] = 6;     // Polling Interval
      packetBuffer[3] = 0xEC;  // Peer Clock Precision
      // 8 bytes of zero for Root Delay & Root Dispersion
      packetBuffer[12]  = 49;
      packetBuffer[13]  = 0x4E;
      packetBuffer[14]  = 49;
      packetBuffer[15]  = 52;
    
      //Serial.println("3");
    
      // all NTP fields have been given values, now
      // you can send a packet requesting a timestamp:
      Udp.beginPacket(address, 123); //NTP requests are to port 123
      //Serial.println("4");
      Udp.write(packetBuffer,NTP_PACKET_SIZE);
      //Serial.println("5");
      Udp.endPacket();
      //Serial.println("6");
    }
    
    
    void printWifiStatus() {
      // print the SSID of the network you're attached to:
      Serial.print("SSID: ");
      Serial.println(WiFi.SSID());
    
      // print your WiFi shield's IP address:
      IPAddress ip = WiFi.localIP();
      Serial.print("IP Address: ");
      Serial.println(ip);
    
      // print the received signal strength:
      long rssi = WiFi.RSSI();
      Serial.print("signal strength (RSSI):");
      Serial.print(rssi);
      Serial.println(" dBm");
    }
    

    最佳答案

    尝试

    memset(packetBuffer, 0, NTP_PACKET_SIZE);
    packetBuffer[0] = 0b00011011; //  (0x1B) for NTPv3
    // or
    // packetBuffer[0] = 0b00100011;` (0x23) for NTPv4
    

    并且不要修改请求结构的其余部分。 NTP将使用此最小请求设置来响应客户端。

    编辑:
    localPort = 2390应该是“ntp-port”(123)吗?要么
    甚至是8888,如此处所述:“Network Time Protocol (NTP) Client”。 注意:链接
    看起来与您的链接几乎相同,但并不相同。指定的端口不同。

    代码是否超出了setup()范围?
    ...
    // check for the presence of the shield:
    if (WiFi.status() == WL_NO_SHIELD) {
      Serial.println("WiFi shield not present");
      // don't continue:
      while(true);
    }
    ...
    

    对我来说看起来很奇怪。 “不要继续”被实施为忙于“待在这里”。

    关于c++ - WiFiShield正在发送NTP请求数据包,但无响应,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21049912/

    10-11 20:49