Example sketches for the new Arduino IDE for ESP8266

Moderator: igrr

User avatar
By Edwin Hilario
#27569 Hello everyone, I hope this is the right place to post this.

I'm trying to synchronize two boards I have with the help of a NTP server. By using NTP I want to get them synchronized no matter which board was powered first.

At the end of the setup I perform a time request. Then I use the "fractional" part of the NTP packet to get the milliseconds of the actual time. Finally, I use a delay(1000-(milliseconds I got)) to get the board synchronized with the NTP server.
In the loop I have a timer so I can measure the error with my oscilloscope.

I was expecting an error between boards of 10-20ms. However after many tests, that error varies a lot, I get errors of more than 150ms sometimes.

Is there something I'm doing wrong? What can do to improve this?

Code: Select all//#include <NTP.h>
#include <ESP8266WiFi.h>
//#include <WiFi.h>
#include <WiFiUdp.h>

const char* ssid = "";
const char* password = "";

bool startWiFi(void);

unsigned int localPort = 2390;      // local port to listen for UDP packets
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

unsigned long previousMillis = 0;        // will store last time LED was updated
int ledState = LOW;             // ledState used to set the LED

const long interval = 100;           // interval at which to blink (milliseconds)

int count=0; //
int turn=2;   //

WiFiUDP Udp;

void setup() {
   pinMode(2, OUTPUT);
   
  Serial.begin(115200);
  Serial.println();
  while (!startWiFi()){delay(1500);}
 
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Connected to wifi");
 
  Udp.begin(localPort);

  unsigned long wait= get_ms();
 while (wait>=999)
 wait= get_ms();
 
  delay(1000-wait); 
}

void loop() { 
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

    count++;
  if (count>9)
  count=0;

if (count==turn)
{
  digitalWrite(2,HIGH);
  }
  else
  digitalWrite(2,LOW);
}
}

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

unsigned long get_ms()
{
  unsigned long read_ms=0;
  IPAddress timeServerIP;
  WiFi.hostByName("pool.ntp.org", timeServerIP);

  sendNTPpacket(timeServerIP); // send an NTP packet to a time server
  // wait to see if a reply is available
   
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1001) {
    int tam = Udp.parsePacket();
    if (tam >= NTP_PACKET_SIZE) {
    //  Serial.println("Receive NTP Response");
    Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
     
    //  unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); //this is for hours,min,seconds etc. I don't need that.
    // unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);

      unsigned long otherHighword = word(packetBuffer[44], packetBuffer[45]);
     
      unsigned long otherLowWord = word(packetBuffer[46], packetBuffer[47]);
      unsigned long fractional = otherHighword << 16 | otherLowWord;
      float read_msF =(float)fractional*2.3283064365387E-07; // fractional*(1000/2^32) to get milliseconds.
     
       //read_ms=word(packetBuffer[44], packetBuffer[45])>>6;
      // Serial.print("ms: short ");Serial.println(read_ms);
      read_ms=(word)(read_msF);
      //Serial.print("ms: real ");Serial.println(read_ms);
     
    }
}
return read_ms;
  }


bool startWiFi(void)
{
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print("."); 
  }
  Serial.println("");
  Serial.println("WiFi connected");
 }

User avatar
By Touliloup
#27780 I guess that you wouldn't get any closer by passing through the network... I guess depending on the traffic, the time of processing from the NTP server.
You can see some example on youtube of several esp8266 making a chain to turn on a led through the wifi network, the delay between 2 board vary greatly in the response time.
Maybe the two board could first synchronize with each other without use of the home wifi network so you'll avoid any network latency or UDP server latency. Communicating with each other directly might be faster.

Why do you need a perfect synchronization? If it's to synchronize some light effect you should maybe use the emitted light (if the board can reach each other) to synchronize them?
User avatar
By schufti
#27806 Hi,
the problem is most likely the irregular delay outside the loop() by the WiFi. Timing smoothes extremly if you disable the WiFi by WiFi.mode(WIFI_OFF); as long as it is turned on, it randomly delays the "outside loop" thus giving a (big) jitter to your way of switching via millis().
e.g.: if you want to give 1 second pulses with "if (millis()%1000 ==0)" this will fail every 3-4 second. If you increase the "window" by if (millis()%1000<10) the chance of missing a second is down to 1 out of appr. 30 If you disable WiFi, the first condition doesn't fail once (be aware that the esp8266 is so fast that an empty loop could trigger if(millis()%1000==0) triple!).
rgds,
schufti