Иногда NTP возвращает неправильное время
У меня есть Uno с Wi-Fi-экраном CC3000, и я пытаюсь использовать библиотеку sntp.h, чтобы получить время NTP. Я экспериментировал с модифицированной версией кода ntpTest из библиотеки, которая считывает время каждую минуту. В последовательном мониторе я вижу правильное время БОЛЬШИНСТВО времени. Однако через случайные промежутки времени время будет отображаться на 3 часа и 14 минут раньше текущего времени MST.
Конструктор клиента SNTP выглядит следующим образом:
sntp mysntp = sntp(NULL,"time.nist.gov", (short)(-7 * 60),(short)(-7 * 60), true);
Время будет отображаться правильно в течение двух-десяти минут, а затем один раз отобразится одно из ошибочных значений времени, а затем вернется к правильному времени.
ИЗМЕНИТЬ Вот урезанный код из примера Adafruit CC3000 WIFI Shield ntpTest. Обратите внимание: единственная причина, по которой я так часто находил время, заключалась в том, что я просто учился тому, как это работает, и я заметил это странное поведение. В мои намерения не входило создание приложения, которое в конечном итоге могло бы обращаться к серверам NTP чаще одного раза в день.
/****************************************** ********
Это пример Adafruit CC3000 Wifi Breakout & Щит
Разработан специально для работы с продуктами Adafruit WiFi:
----> https://www.adafruit.com/products/1469
Adafruit инвестирует время и ресурсы, предоставляя этот открытый исходный код.
пожалуйста, поддержите Adafruit и оборудование с открытым исходным кодом, купив
продукция от Adafruit!
Автор Кевин Таунсенд и amp; Лимор Фрид & Рик Лесняк из Adafruit Industries.
Лицензия BSD, весь текст выше должен быть включен в любое распространение.
************************************************* **/
/*
В этом примере выполняется проверка клиента SNTP (Simple Network Time Protocol):
* Инициализация
* Сканирование SSID
* Точка доступа
* Распечатка DHCP
* Синхронизация времени SNTP
* Извлечение и печать информации о текущем времени и дате.
*/
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
//#include "utility/NetTime.h"
#include <string.h>
#include "utility/debug.h"
#include "sntp.h"
// Это контакты прерывания и управления
#define ADAFRUIT_CC3000_IRQ 3 // ДОЛЖЕН быть контактом прерывания!
// Это могут быть любые два контакта
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS 10
// Используем аппаратный SPI для остальных контактов
// В UNO SCK = 13, MISO = 12 и MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
SPI_CLOCK_DIVIDER); // вы можете изменить эту тактовую частоту, но DI
#define WLAN_SSID "CompsciWifi" // не может быть длиннее 32 символов!
#define WLAN_PASS "005276DA"
// Безопасность может быть WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA или WLAN_SEC_WPA2.
#define WLAN_SECURITY WLAN_SEC_WPA2
//Аргументы конструктора клиента SNTP:
// 1 - URL основного сетевого сервера времени (может быть NULL)
// 2 - URL вторичного сетевого сервера времени (также может быть NULL)
// 3 — локальное смещение UTC в минутах (восточное время США — UTC — 5:00).
// 4 — локальное смещение UTC в минутах для летнего времени (восточное летнее время США — UTC — 4:00).
// 5 - Включить настройку летнего времени (пока не реализовано)
//
//sntp mysntp = sntp(NULL, "time.nist.gov", (short)(-7 * 60), (short)(-7 * 60), true);
sntp mysntp = sntp(NULL, "time-a.timefreq.bldrdoc.gov", (short)(-7 * 60), (short)(-7 * 60), true);
// Тип SNTP_Timestamp — это 64-битное время NTP. Старшие 32-битные разряды — это секунды, прошедшие с 01.01.1900.
// Младшие 32-битные значения составляют доли секунды
SNTP_Timestamp_t now;
// Тип NetTime_t содержит время NTP, разбитое на человекоориентированные значения:
// uint16_t миллис; ///< Миллисекунды после второго (0..999)
// uint8_t сек; ///< Секунды после минуты (0..59)
// uint8_t мин; ///< Минуты после часа (0..59)
// uint8_t час; ///< Часов с полуночи (0..23)
// uint8_t mday; ///< День месяца (1..31)
// uint8_t мон; ///< Месяцы с января (0..11)
// uint16_t год; ///< Год.
// uint8_t wday; ///< Дней с воскресенья (0..6)
// uint8_t yday; ///< Дней с 1 января (0..365)
// bool isdst; ///< Флаг перехода на летнее время, в настоящее время не поддерживается.
NetTime_t timeExtract;
#define pF(string_pointer) (reinterpret_cast<const __FlashStringHelper *>(pgm_read_word(string_pointer)))
const prog_char janStr[] PROGMEM = "January";
const prog_char febStr[] PROGMEM = "February";
const prog_char marStr[] PROGMEM = "March";
const prog_char aprStr[] PROGMEM = "April";
const prog_char mayStr[] PROGMEM = "May";
const prog_char junStr[] PROGMEM = "June";
const prog_char julStr[] PROGMEM = "July";
const prog_char augStr[] PROGMEM = "August";
const prog_char sepStr[] PROGMEM = "September";
const prog_char octStr[] PROGMEM = "October";
const prog_char novStr[] PROGMEM = "November";
const prog_char decStr[] PROGMEM = "December";
PROGMEM const char* const monthStrs[] = { janStr, febStr, marStr, aprStr, mayStr, junStr,
julStr, augStr, sepStr, octStr, novStr, decStr};
const prog_char sunStr[] PROGMEM = "Sunday";
const prog_char monStr[] PROGMEM = "Monday";
const prog_char tueStr[] PROGMEM = "Tuesday";
const prog_char wedStr[] PROGMEM = "Wednesday";
const prog_char thuStr[] PROGMEM = "Thursday";
const prog_char friStr[] PROGMEM = "Friday";
const prog_char satStr[] PROGMEM = "Saturday";
PROGMEM const char* const dayStrs[] = { sunStr, monStr, tueStr, wedStr,
thuStr, friStr, satStr};
/**************************************************************************/
/*!
@brief Sets up the HW and the CC3000 module (called automatically
on startup)
*/
/**************************************************************************/
void setup(void)
{
Serial.begin(115200);
Serial.println(F("Hello, CC3000!\n"));
//Serial.print("Свободная оперативная память: "); Serial.println(getFreeRam(), DEC);
/* Initialise the module */
Serial.println(F("\nInitialising the CC3000 ..."));
if (!cc3000.begin())
{
Serial.println(F("Unable to initialise the CC3000! Check your wiring?"));
while(1);
}
/* Optional: Update the Mac Address to a known value */
/*
uint8_t macAddress[6] = { 0x08, 0x00, 0x28, 0x01, 0x79, 0xB7 };
if (!cc3000.setMacAddress(macAddress))
{
Serial.println(F("Failed trying to update the MAC address"));
while(1);
}
*/
/* Delete any old connection data on the module */
Serial.println(F("\nDeleting old connection profiles"));
if (!cc3000.deleteProfiles()) {
Serial.println(F("Failed!"));
while(1);
}
/* Attempt to connect to an access point */
char *ssid = WLAN_SSID; /* Max 32 chars */
Serial.print(F("\nAttempting to connect to ")); Serial.println(ssid);
/* NOTE: Secure connections are not available in 'Tiny' mode! */
if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
Serial.println(F("Failed!"));
while(1);
}
Serial.println(F("Connected!"));
/* Wait for DHCP to complete */
Serial.println(F("Request DHCP"));
while (!cc3000.checkDHCP())
{
delay(100); // Задача: добавить тайм-аут DHCP!
}
/*Serial.println(F("UpdateNTPTime"));
if (mysntp.UpdateNTPTime())
{
Serial.println(F("Current local time is:"));
mysntp.ExtractNTPTime(mysntp.NTPGetTime(&now, true), &timeExtract);*/
/*Serial.print(timeExtract.hour); Serial.print(F(":")); Serial.print(timeExtract.min); Serial.print(F(":"));Serial.print(timeExtract.sec); Serial.print(F("."));Serial.println(timeExtract.millis);
Serial.print(pF(&dayStrs[timeExtract.wday])); Serial.print(F(", ")); Serial.print(pF(&monthStrs[timeExtract.mon])); Serial.print(F(" ")); Serial.print(timeExtract.mday); Serial.print(F(", "));Serial.println(timeExtract.year);
Serial.println(timeExtract.yday + 1);
}
/* You need to make sure to clean up after yourself or the CC3000 can freak out */
/* the next time you try to connect ... */
/*Serial.println(F("\n\nClosing the connection"));
cc3000.disconnect(); */
mysntp.UpdateNTPTime();
mysntp.ExtractNTPTime(mysntp.NTPGetTime(&now, true), &timeExtract);
Serial.print(pF(&dayStrs[timeExtract.wday])); Serial.print(F(", ")); Serial.print(pF(&monthStrs[timeExtract.mon])); Serial.print(F(" ")); Serial.print(timeExtract.mday); Serial.print(F(", "));Serial.println(timeExtract.year);
}
void loop(void)
{
mysntp.UpdateNTPTime();
mysntp.ExtractNTPTime(mysntp.NTPGetTime(&now, true), &timeExtract);
Serial.print(timeExtract.hour); Serial.print(F(":")); Serial.print(timeExtract.min);
delay(60000);
Serial.println();
}
@techkilljoy, 👍1
Обсуждение1 ответ
Обновленный тестовый набросок NTP предполагает, что связь с сервером NTP не прервется, но поскольку протокол NTP основан на UDP, ответный пакет может быть потерян. Возможным исправлением обновленного наброска является проверка возвращаемого значения из UpdateNTPTime()
.
void loop(void)
{
if (mysntp.UpdateNTPTime()) {
mysntp.ExtractNTPTime(mysntp.NTPGetTime(&now, true), &timeExtract);
Serial.print(timeExtract.hour);
Serial.print(F(":"));
Serial.println(timeExtract.min);
delay(60000);
Serial.println();
}
}
Ура!
- Как установить RTC в ES32 с помощью NTP-сервера?
- Циклы выходят из строя через ~ 5 минут при выполнении двух вызовов API каждые 10 секунд с использованием клиента WiFi.
- Как подключиться к Arduino с помощью WiFi?
- Как справиться с rollover millis()?
- Как получить текущее время и дату в Arduino без внешнего источника?
- Преобразование в Unix Timestamp и обратно
- ESP8266 не подключается к Wi-Fi
- В чем разница между вариантами RF (wifi, xbee, NRF24L01)
Попытайтесь выяснить, повреждены ли данные или произошло математическое переполнение. 3 часа 14 минут — не такое интересное число, как четыре часа 15 минут, но все же может быть интригующим. Вы уверены, что интервалы действительно случайны? Было бы здорово, если бы вы могли каким-то образом отслеживать данные непосредственно с экрана Wi-Fi (или еще лучше, если бы вы могли настроить поддельный сервер, чтобы он неоднократно циклически проходил одни и те же моменты времени и смотрел, повторяется ли это. Но реальным решением может стать тщательная проверка всей цепочки операций., @Chris Stratton
Вот что я предлагаю вам сделать: сделайте копию своего кода и постепенно удаляйте любой код, не связанный напрямую с вашей проблемой sntp. Есть два возможных результата: либо проблема исчезнет, и в этом случае нужно найти минимальное изменение, чтобы проблема исчезла. Если проблема не исчезнет, опубликуйте оставшийся код здесь - я ожидаю, что у вас останется около 10-20 строк (если вы зайдете так далеко)., @AMADANON Inc.
PS — вам, вероятно, не следует слишком часто опрашивать серверы времени — если ваше устройство не выключится, вам следует держать локальные часы. NTP предназначен для предотвращения смещения ваших часов, а не для того, чтобы избавить вас от необходимости держать локальные часы. Я бы не ожидал, что Arduino потребуется опрашивать NTP более одного раза в день. Сохранив локальные часы, вы также можете проверить, выключены ли часы — они не должны смещаться на 3 часа между опросами., @AMADANON Inc.
@AMADANON-inc Я думаю, что код уже довольно минимален, но я попробую удалить все, что смогу, и посмотреть, что произойдет. Я согласен, что конечный продукт должен использовать NTP по назначению. Это был просто странный феномен, который я наблюдал, изучая использование Wi-Fi-экрана. Это заставило меня забеспокоиться, что я, должно быть, упускаю что-то важное, когда в конечном итоге буду использовать NTP для исправления отклонения времени., @techkilljoy
@ChrisStratton это звучит немного выше моих навыков. Возможно, было бы неплохо попробовать, но сначала я попробую исключить другие возможности. Спасибо за понимание., @techkilljoy
@techkilljoy, как только у вас будет минимальный код, опубликуйте его здесь, чтобы мы могли попытаться воспроизвести проблему. Обычно в подобных случаях возникает небольшая проблема с кодом; когда вы работаете над кодом, часто трудно понять, что именно не так., @AMADANON Inc.
@AMADANON-inc, извините за задержку, вызванную праздниками, но вот урезанный код, указанный под строкой РЕДАКТИРОВАНИЯ выше., @techkilljoy
Возможно, будет проще начать с создания минимального приложения NTP и подтверждения его работы. Используйте только библиотеку NTP и образец эскиза или пример из библиотеки NTP. Начните с чего-то максимально простого или заведомо хорошего., @dlu