0

So I have this code to get ntp time and display it on serial port. But I want to display it on a 1.30 inch I2C oled with a SH1106 controller using the U8G2 library. The only problem is I don't know the correct syntax. I have tried

Serial.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs 
per day)
int ho = ((epoch  % 86400L) / 3600+9);
itoa(ho,hours,10);
u8g2.clearBuffer();         // clear the internal memory
u8g2.setFont(u8g2_font_ncenB14_tr); // choose a suitable font
u8g2.drawStr(0,20,hours);

and also

{
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.firstPage();
do {
u8g2.setCursor(0, 20);
u8g2.print(hours,DEC);
u8g2.setCursor(33, 20);
u8g2.print(minutes,DEC);
} 
while ( u8g2.nextPage() );
}

This is my code

//This is a code to display ntp time using Nodemcu

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

char ssid[] = "123456";     //  your network SSID (name)
char pass[] = "123456";     // your network password

//Your UTC Time Zone Differance  India +5:30
char HH = 5;
char MM = 30;

unsigned int localPort = 2390;      // local port to listen for UDP packets

//* Don't hardwire the IP address or we won't get the benefits of the pool.
//* Lookup the IP address for the host name instead */

//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server

IPAddress timeServerIP; // time.nist.gov NTP server address

const char* ntpServerName = "time.nist.gov";

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;


                              //SETUP



void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println();

// We start by connecting to a WiFi network
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pass);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");

Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

Serial.println("Starting UDP");
udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(udp.localPort());
}


//  Send an NTP request to the time server at the given address

unsigned long sendNTPpacket(IPAddress& address)
{
Serial.println("sending NTP packet...");
// 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)
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;

// 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
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();

u8g2.begin();
}
                              //LOOP

void loop()
{
char hours;
char minutes;
char seconds;

// get a random server from the pool
WiFi.hostByName(ntpServerName, timeServerIP); 

sendNTPpacket(timeServerIP); 

// send an NTP packet to a time server
// wait to see if a reply is available
delay(1000);

int cb = udp.parsePacket();
if (!cb) {
Serial.println("no packet yet");
}
else {
Serial.print("packet received, length=");
Serial.println(cb);

// 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:
minutes = ((epoch % 3600) / 60);
minutes = minutes + MM; //Add UTC Time Zone

hours = (epoch  % 86400L) / 3600;    
if(minutes > 59)
{      
hours = hours + HH + 1; //Add UTC Time Zone  
minutes = minutes - 60;
}
else
{
hours = hours + HH;
}

Serial.print("The UTC time is ");       // UTC is the time at Greenwich //Meridian (GMT)

Serial.print(hours,DEC); // print the hour (86400 equals secs per day)
Serial.print(':');


if ( minutes < 10 ) {
// In the first 10 minutes of each hour, we'll want a leading '0'
Serial.print('0');
}    
Serial.print(minutes,DEC); // print the minute (3600 equals secs per minute)
Serial.print(':');

seconds = (epoch % 60);
if ( seconds < 10 ) {
// In the first 10 seconds of each minute, we'll want a leading '0'
Serial.print('0');
}
Serial.println(seconds,DEC); // print the second
}
// wait ten seconds before asking for the time again
delay(10000);
}

Adding the second block of code (print one) to the main code gives me correct time on the oled screen but only when the ntp receives a packet. Otherwise its some 10 digit number. How do I get rid of the number and keep displaying the time till it is update with a valid newer value. I have attached images of display.

Correct time

10 digit value

4
  • 2
    Code has many sintax errors, none like the ones you describe. Try again: compile the same code you posted, and edit your question to include the actual error message
    – user31481
    Commented Feb 11, 2018 at 8:26
  • More generally, you should reduce your code to a minimal, complete, verifiable example example.
    – Mark Smith
    Commented Feb 11, 2018 at 14:37
  • Edited. It compiles now.
    – Akshayk420
    Commented Feb 11, 2018 at 14:37
  • 1
    The title of your question and most of the first part as nothing to do with your problem (only receive one UDP packet). Please, edit your question to deleted the non related parts (u8g2) and correct your title
    – user31481
    Commented Feb 11, 2018 at 15:49

1 Answer 1

1

EDIT: I checkout Internet access is working OK. Problem is the server.

Your sketch works well (after some refactoring) against my local LAN NTP server and ntp.shoa.cl, but not against time.nist.gov, the one in your sketch.

It looks like the NTP server time.nist.gov itself is having problems. ntpdate reports:

> look@gear ~/Downloads/mover $ ntpdate -q time.nist.gov server
> 129.6.15.28, stratum 0, offset 0.000000, delay 0.00000 11 Feb 13:11:05 ntpdate[5855]: no server suitable for synchronization found

so that may explain that your code fails.

Anyway, I refactored your code before testing before delays are source of all kind of problems. I run OK at the first test.

I only modify loop; everything else is the same. I made it a state machine with three states: idle, your are reading to send an UDP packet; reading, you are trying to read the answer; and waiting, where you spend 10 seconds doing nothing.

I also move all printing to a new processPacket function, to keep loop short and easy to read.

Never use delay(). Use the scheme provide here to wait using millis().

void loop() {
    enum st {idle, reading, waiting};
    static st status;
    static unsigned long prev = 0;
    unsigned long now = millis();

    switch(status) {
    case idle:
        // get a random server from the pool
        WiFi.hostByName(ntpServerName, timeServerIP);

        sendNTPpacket(timeServerIP);
        status = reading;
        prev = now;
        break;

    case reading:
        if(now - prev > 1000L) {
            int cb = udp.parsePacket();

            if(cb) {
                status = idle;
                Serial.print("packet received, length=");
                Serial.println(cb);
                processPacket();
            } else {
                Serial.println("no packet yet");
            }

            prev = now;
        }

        break;

    case waiting:
        if(now - prev > 10000L) {
            status = idle;
            prev = now;
        }
    }
}

void processPacket()
{
    char hours;
    char minutes;
    char seconds;

    // 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:
    minutes = ((epoch % 3600) / 60);
    minutes = minutes + MM; //Add UTC Time Zone
    hours = (epoch  % 86400L) / 3600;
    if(minutes > 59) {
        hours = hours + HH + 1; //Add UTC Time Zone
        minutes = minutes - 60;
    } else {
        hours = hours + HH;
    }
    Serial.print("The UTC time is ");       // UTC is the time at Greenwich //Meridian (GMT)
    Serial.print(hours,DEC); // print the hour (86400 equals secs per day)
    Serial.print(':');
    if(minutes < 10) {
    // In the first 10 minutes of each hour, we'll want a leading '0'
        Serial.print('0');
    }
    Serial.print(minutes,DEC); // print the minute (3600 equals secs per minute)
    Serial.print(':');
    seconds = (epoch % 60);
    if(seconds < 10) {
        // In the first 10 seconds of each minute, we'll want a leading '0'
        Serial.print('0');
    }
    Serial.println(seconds,DEC); // print the second
    u8g2.setFont(u8g2_font_ncenB14_tr); 
    u8g2.firstPage(); 
    do { 
       u8g2.setCursor(0, 20); 
       u8g2.print(hours,DEC); 
       u8g2.drawStr(25, 17,":"); 
       u8g2.setCursor(33, 20); 
       u8g2.print(minutes,DEC); 
       } 
    while(u8g2.nextPage());     
  }

And this is the output:

enter image description here

2
  • Thanks for the feedback. Can you please also show me how do I display it on the oled using u8g2 lib?? I tried { u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.firstPage(); do { u8g2.setCursor(0, 20); u8g2.print(hours,DEC); u8g2.drawStr(25, 17,":"); u8g2.setCursor(33, 20); u8g2.print(minutes,DEC); } while ( u8g2.nextPage() ); }but it says hours was not declared in this scope
    – Akshayk420
    Commented Feb 12, 2018 at 5:32
  • @Akshayk420. Put it at the end of processPacket(). I edited the answer to include that.
    – user31481
    Commented Feb 12, 2018 at 7:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.