Проблема с отображением времени Ntp на oled с использованием библиотеки U8G2.

Итак, у меня есть этот код, чтобы получить время ntp и отобразить его на последовательном порту. Но я хочу отобразить его на 1,30-дюймовом I2C-OLED с контроллером SH1106, используя библиотеку U8G2. Единственная проблема в том, что я не знаю правильного синтаксиса. Я пробовал

Serial.print((epoch  % 86400L) / 3600); // распечатываем час (86400 соответствует секундам
per day)
int ho = ((epoch  % 86400L) / 3600+9);
itoa(ho,hours,10);
u8g2.clearBuffer();         // очищаем внутреннюю память
u8g2.setFont(u8g2_font_ncenB14_tr); // выбираем подходящий шрифт
u8g2.drawStr(0,20,hours);

а также

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

Это мой код

//Это код для отображения времени ntp с помощью 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";     // SSID вашей сети (имя)
char pass[] = "123456";     // ваш сетевой пароль

//Разница часовых поясов UTC в Индии +5:30
char HH = 5;
char MM = 30;

unsigned int localPort = 2390;      // локальный порт для прослушивания UDP-пакетов

//* Не закрепляйте IP-адрес жестко, иначе мы не получим преимуществ пула.
//* Вместо этого ищем IP-адрес по имени хоста */

//IP-адрес timeServer(129, 6, 15, 28); // time.nist.gov NTP-сервер

IPAddress timeServerIP; // адрес NTP-сервера time.nist.gov

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

const int NTP_PACKET_SIZE = 48; // Метка времени NTP находится в первых 48 байтах
// сообщения

byte packetBuffer[ NTP_PACKET_SIZE]; //буфер для хранения входящих и исходящих
//пакеты

// Экземпляр UDP, позволяющий отправлять и получать пакеты по UDP
WiFiUDP udp;


                              //НАСТРАИВАТЬ



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

// Начинаем с подключения к сети Wi-Fi
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());
}


// Отправляем запрос NTP на сервер времени по указанному адресу

unsigned long sendNTPpacket(IPAddress& address)
{
Serial.println("sending NTP packet...");
// устанавливаем все байты в буфере в 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);

// Инициализируем значения, необходимые для формирования NTP-запроса
// (подробную информацию о пакетах см. в URL-адресе выше)
packetBuffer[0] = 0b11100011;   // LI, Версия, Режим
packetBuffer[1] = 0;     // Stratum, или тип часов
packetBuffer[2] = 6;     // Интервал опроса
packetBuffer[3] = 0xEC;  // Точность равноправных часов
// 8 байтов нуля для Root Delay & Дисперсия корней
packetBuffer[12]  = 49;
packetBuffer[13]  = 0x4E;
packetBuffer[14]  = 49;
packetBuffer[15]  = 52;

// теперь всем полям NTP присвоены значения
// вы можете отправить пакет с запросом отметки времени:

udp.beginPacket(address, 123); //NTP-запросы идут на порт 123
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();

u8g2.begin();
}
                              //ПЕТЛЯ

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

// получаем случайный сервер из пула
WiFi.hostByName(ntpServerName, timeServerIP); 

sendNTPpacket(timeServerIP); 

// отправляем NTP-пакет на сервер времени
// ждем, доступен ли ответ
delay(1000);

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

// Мы получили пакет, читаем из него данные
udp.read(packetBuffer, NTP_PACKET_SIZE); // читаем пакет в буфер
//метка времени начинается с 40-го байта полученного пакета и составляет четыре байта,
// или два слова, длинные. Сначала извлеките два слова:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);


// объединяем четыре байта (два слова) в длинное целое число
// это время NTP (в секундах с 1 января 1900 года):
unsigned long secsSince1900 = highWord << 16 | lowWord;
Serial.print("Seconds since Jan 1 1900 = " );
Serial.println(secsSince1900);

// теперь преобразуем время NTP в повседневное время:
Serial.print("Unix time = ");
// Время Unix начинается 1 января 1970 года. В секундах это 2208988800:
const unsigned long seventyYears = 2208988800UL;
// вычитаем семьдесят лет:
unsigned long epoch = secsSince1900 - seventyYears;
// распечатываем Unix-время:
Serial.println(epoch);


// распечатываем час, минуту и секунду:
minutes = ((epoch % 3600) / 60);
minutes = minutes + MM; //Добавить часовой пояс UTC

hours = (epoch  % 86400L) / 3600;    
if(minutes > 59)
{      
hours = hours + HH + 1; //Добавить часовой пояс UTC
minutes = minutes - 60;
}
else
{
hours = hours + HH;
}

Serial.print("The UTC time is ");       // UTC — время по Гринвичу //Меридиан (GMT)

Serial.print(hours,DEC); // распечатываем час (86400 соответствует секундам в день)
Serial.print(':');


if ( minutes < 10 ) {
// В первые 10 минут каждого часа нам нужен ведущий '0'
Serial.print('0');
}    
Serial.print(minutes,DEC); // распечатываем минуту (3600 соответствует секундам в минуту)
Serial.print(':');

seconds = (epoch % 60);
if ( seconds < 10 ) {
// В первые 10 секунд каждой минуты нам нужен ведущий '0'
Serial.print('0');
}
Serial.println(seconds,DEC); // печатаем второй
}
// подождем десять секунд, прежде чем снова запросить время
delay(10000);
}

Добавление второго блока кода (печатного) к основному коду дает мне правильное время на oled-экране, но только тогда, когда ntp получает пакет. В противном случае это какой-то 10-значный номер. Как мне избавиться от числа и продолжать отображать время до тех пор, пока оно не будет обновлено с использованием более нового значения. Я приложил изображения дисплея.

Точное время

10-значное значение

, 👍0

Обсуждение

В более общем плане вам следует свести свой код к минимальному, полному и проверяемому примеру., @Mark Smith

Отредактировано. Теперь он компилируется., @Akshayk420


1 ответ


1

РЕДАКТИРОВАТЬ: Я проверяю, доступ в Интернет работает нормально. Проблема в сервере.

Ваш скетч хорошо работает (после некоторого рефакторинга) с моим локальным NTP-сервером локальной сети и ntp.shoa.cl, но не с time.nist.gov, который есть в вашем скетче.

Похоже, что на самом NTP-сервере time.nist.gov возникли проблемы. Отчеты ntpdate:

> 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

так что это может объяснить сбой вашего кода.

В любом случае, я провел рефакторинг вашего кода перед тестированием, прежде чем задержки станут источником всевозможных проблем. Первый тест проходит нормально.

Я изменяю только loop; все остальное то же самое. Я сделал его конечным автоматом с тремя состояниями: idle, вы читаете, чтобы отправить UDP-пакет; чтение, вы пытаетесь прочитать ответ; и ожидание, когда вы ничего не делаете в течение 10 секунд.

Я также перенес всю печать в новую функцию processPacket, чтобы loop был коротким и легко читаемым.

Никогда не используйте задержку(). Используйте приведенную здесь схему для ожидания с помощью millis().

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

    switch(status) {
    case idle:
        // получаем случайный сервер из пула
        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;

    // Мы получили пакет, читаем из него данные
    udp.read(packetBuffer, NTP_PACKET_SIZE); // читаем пакет в буфер
    //метка времени начинается с 40-го байта полученного пакета и составляет четыре байта,
    // или два слова, длинные. Сначала извлеките два слова:
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);


    // объединяем четыре байта (два слова) в длинное целое число
    // это время NTP (в секундах с 1 января 1900 года):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    Serial.print("Seconds since Jan 1 1900 = ");
    Serial.println(secsSince1900);

    // теперь преобразуем время NTP в повседневное время:
    Serial.print("Unix time = ");
    // Время Unix начинается 1 января 1970 года. В секундах это 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // вычитаем семьдесят лет:
    unsigned long epoch = secsSince1900 - seventyYears;
    // распечатываем Unix-время:
    Serial.println(epoch);
    // распечатываем час, минуту и секунду:
    minutes = ((epoch % 3600) / 60);
    minutes = minutes + MM; //Добавить часовой пояс UTC
    hours = (epoch  % 86400L) / 3600;
    if(minutes > 59) {
        hours = hours + HH + 1; //Добавить часовой пояс UTC
        minutes = minutes - 60;
    } else {
        hours = hours + HH;
    }
    Serial.print("The UTC time is ");       // UTC — время по Гринвичу //Меридиан (GMT)
    Serial.print(hours,DEC); // распечатываем час (86400 соответствует секундам в день)
    Serial.print(':');
    if(minutes < 10) {
    // В первые 10 минут каждого часа нам нужен ведущий '0'
        Serial.print('0');
    }
    Serial.print(minutes,DEC); // распечатываем минуту (3600 соответствует секундам в минуту)
    Serial.print(':');
    seconds = (epoch % 60);
    if(seconds < 10) {
        // В первые 10 секунд каждой минуты нам нужен ведущий '0'
        Serial.print('0');
    }
    Serial.println(seconds,DEC); // печатаем второй
    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());     
  }

И вот результат:

,

Спасибо за ответ. Не могли бы вы также показать мне, как мне отобразить его на oled с помощью библиотеки u8g2?? Я пытался { u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.первая страница(); делать { u8g2.setCursor(0, 20); u8g2.print(часы,ДЕКАБРЬ); u8g2.drawStr(25, 17,":"); u8g2.setCursor(33, 20); u8g2.print(минуты,ДЕКАБРЬ); } в то время как ( u8g2.nextPage() ); }но там написано, что часы не были объявлены в этой области, @Akshayk420