На предыдущем уроке мы реализовали работу с модулем RTC и организовали отображение данных о дате/времени на TFT-дисплее.
Для этого достаточно определить только mac-адрес нашего сетевого интерфейса:
Для того, чтобы потом можно было где-то использовать полученный IP-адрес, заведем соответствующий массив char - currentIP.
Инициализируем (в функции setup) сетевой интерфейс следующим образом:
Сразу после инициализации - зафиксируем полученный IP-адрес в массиве currentIP (выведем его на дисплей в соответствующей функции (myDisplay()).
Визуальным подтверждением того, что вы задействовали сетевой интерфейс будет задействованная световая индикация работы сетевого модуля рядом с LAN-разъемом на плате (6 зеленых светодиодов, которые в предыдущем уроке скромно "молчали").
Для фиксации времени последней синхронизации часов с сервером заведем другой массив: lastNTPsync[].
Дополнительно в наш проект введем файл common - в нем будем определять функции, которые могут понадобиться в дальнейшем. На сегодняшнем "уроке" такой функцией станет time2str, с помощью которой текущее время и дату преобразуем в соответствующий символьный массив.
Теперь перейдем непосредственно к корректировке времени.
В приведенном коде присутствует и другая функция (sendNTPpacket), с помощью которой отправляется UDP-пакет данных к серверу.
Выделенная жирным шрифтом строчка - собственно то, ради чего все и было сделано - "подводка" модуля часов, имеющегося на плате.
Собственно, на этом план урока полностью выполнен. В результате вы должны на своей плате видеть что-то типа (IP-адрес будет отличаться от того, что виден на экране: 192.168.1.xxx, 192.168.0.xxx или другой, в зависимости от того, как настроена ваша сеть):
Полный скетч можно скачать по ссылке.
Продолжение следует...
Некоторые из вас могут остаться недовольны точностью хода часов, реализованных на DS1370 (заметно "убегают" или "отстают"), но это не является проблемой, ведь в нашей плате iBoard Pro "на борту" имеется полноценный сетевой интерфейс на базе Wiznet W5100 - сегодня мы реализуем синхронизацию времени с помощью NTP-сервера.
Для этого необходимо следующее:
На дисплее отображается (сверху-вниз): время, дата, IP-адрес, время последней синхронизации |
- "Завести" сетевой интерфейс (чтобы устройство правильно зарегистрировалось в домашней сети и получило IP-адрес)
- Отправить UDP-запрос к NTP-серверу
- Получить UDP-ответ и преобразовать его в удобный формат
- "Подвести" модуль часов на DS1307
Собственно, план работ понятен. Приступим.
Мы продолжим развивать тот скетч (iBoardPro) из предыдущего урока - добавим в наш проект дополнительный файл ntp.
Сетевой интерфейс
В основном файле нам необходимо добавить подключение библиотек, необходимых для работы с сетевым интерфейсом и протоколом UDP:
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>Поскольку все ntp-сервера возвращают время GMT - обязательно нужно ввести свой часовой пояс (если вы, конечно, не находитесь на Гринвичском меридиане). Дополнительно введем константу, значение которой (в миллисекундах) будет определять период синхронизации времени с сервером и определим переменную, в которой будем остлеживать, пора ли производить синхронизацию:
#define NTPtimeSync 600000 // 10 минут
#define TimeOffset 4 // часовой пояс - GMT +4 (Москва)
unsigned long nextNTPtime = 0;Так же необходимо выбрать сервер, с которым будет производиться синхронизация. Обычно выбирают тот, что "поближе" и "постабильнее", чтобы часы показывали время, наиболее близкое к истинному. Но поскольку мы реализуем "бытовой" прибор - можно выбрать любой:
IPAddress timeServer(195, 13, 1, 153); // ntp2.belbone.be NTP serverВ нашем уроке мы реализуем вариант, когда наше устройство автоматически должно получить IP-адрес от роутера (DHCP).
Для этого достаточно определить только mac-адрес нашего сетевого интерфейса:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEA };Вы можете выбрать произвольный mac-адрес, главное, чтобы он не совпадал ни с каким другим mac-адресом в вашей домашней сети.
Для того, чтобы потом можно было где-то использовать полученный IP-адрес, заведем соответствующий массив char - currentIP.
Инициализируем (в функции setup) сетевой интерфейс следующим образом:
if (Ethernet.begin(mac) == 0) {В случае неудачи - в последовательный интерфейс выведем соответствующее сообщение.
Serial.println("Failed to configure Ethernet using DHCP");
}
Сразу после инициализации - зафиксируем полученный IP-адрес в массиве currentIP (выведем его на дисплей в соответствующей функции (myDisplay()).
Визуальным подтверждением того, что вы задействовали сетевой интерфейс будет задействованная световая индикация работы сетевого модуля рядом с LAN-разъемом на плате (6 зеленых светодиодов, которые в предыдущем уроке скромно "молчали").
Для фиксации времени последней синхронизации часов с сервером заведем другой массив: lastNTPsync[].
Дополнительно в наш проект введем файл common - в нем будем определять функции, которые могут понадобиться в дальнейшем. На сегодняшнем "уроке" такой функцией станет time2str, с помощью которой текущее время и дату преобразуем в соответствующий символьный массив.
Теперь перейдем непосредственно к корректировке времени.
NTP
Создадим функцию, которую будем вызывать в каждом цикле loop(), но сделаем ее таким образом, чтобы она отрабатывала только по истечении заданного периода синхронизации (NTPtimeSync):void ntpRTCupdate() {
if(millis() > nextNTPtime) {
Udp.begin(localPort);
sendNTPpacket(timeServer); // send an NTP packet to a time server
// wait to see if a reply is available
delay(200);
if ( Udp.parsePacket() ) {
// 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;
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
// subtract seventy years:
// calculate Unix time:
unsigned long epoch = secsSince1900 - seventyYears;
// print Unix time:
// введем корректировку для часового пояса
epoch = epoch + (TimeOffset * 3600L);
// скорректируем RTC
RTC.adjust(DateTime(epoch));
time2str(RTC.now(), lastNTPsync);
nextNTPtime = millis()+NTPtimeSync;
}
Udp.stop();
}
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address)
{
// 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();
}
В приведенном коде присутствует и другая функция (sendNTPpacket), с помощью которой отправляется UDP-пакет данных к серверу.
Выделенная жирным шрифтом строчка - собственно то, ради чего все и было сделано - "подводка" модуля часов, имеющегося на плате.
Результат 2 урока
Осталось поправить функцию myDisplay(), чтобы вывести важные для нас параметры на экран:void myDisplay() {Тут мы удалили лишние вызовы функций для вывода времени и даты и добавили вывод новых параметров.
// время
time2display(70, 0, false, 255, 255, 255);
// дата
date2display(0, 50, true, 255, 255, 0, BigFont);
// выведем текущий IP-адрес
myGLCD.setColor(255, 255, 255); // белый
myGLCD.setFont(BigFont);
myGLCD.print(currentIP, 50, 80);
// и время последней синхронизации с NTP-сервером
myGLCD.setColor(0, 255, 255); // голубой
myGLCD.print(lastNTPsync, 20, 100);
}
Собственно, на этом план урока полностью выполнен. В результате вы должны на своей плате видеть что-то типа (IP-адрес будет отличаться от того, что виден на экране: 192.168.1.xxx, 192.168.0.xxx или другой, в зависимости от того, как настроена ваша сеть):
Полный скетч можно скачать по ссылке.
Продолжение следует...
>введем файл common
ОтветитьУдалитьи где его взять?
display_temperature_with_SNMP_and_pressure.ino: In function 'void ntpRTCupdate()':
display_temperature_with_SNMP_and_pressure:630: error: 'time2str' was not declared in this scope
При воспроизведении данного примера на плате Iteaduino IBoard Pro (ATmega 2560) с установленной батарейкой не работает RTC, вместо даты/времени на секунду вспыхивают рандомные цифры в строке времени и плата уходит в ребут. Без батарейки всё работает как надо.
ОтветитьУдалитьАналогично на других примерах с RTC, с батарейкой выводится NO RTC, без батарейки часы работают.
Глюк моего экземпляра платы или можно вылечить?