Проблема с отображением времени 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-значный номер. Как мне избавиться от числа и продолжать отображать время до тех пор, пока оно не будет обновлено с использованием более нового значения. Я приложил изображения дисплея.
@Akshayk420, 👍0
Обсуждение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
- LILYGO TTGO T-Display не может обнаружить акселерометр, гироскоп и датчик температуры MPU 6050
- Как отображать переменные на 0,96-дюймовом OLED-дисплее с библиотекой u8glib?
- NodeMCU с RFID RC522 и LCD-модулем интерфейса I2C вместе
- Путаница между SPI и I2C для SSD1306 OLED
- Как подключить MPU9250 к NodeMCU с помощью SPI или I2C Slave?
- Запуск 7-контактного OLED-дисплея с 4 контактами (I2C)
- Ведомое устройство Arduino с двумя мастерами, использующими одну и ту же шину I2C?
- Не удалось выделить SSD1306 при добавлении константы
В более общем плане вам следует свести свой код к минимальному, полному и проверяемому примеру., @Mark Smith
Отредактировано. Теперь он компилируется., @Akshayk420