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