Синхронизация времени с NTP на ESP32 с помощью ESP-IDF


В данной статье мы научимся использовать модуль LwIP SNTP на плате ESP32 и функции работы со временем для получения времени с интернет-серверов с помощью ESP-IDF. SNTP (Simple Network Time Protocol), также известный как «Простой сетевой протокол времени», — это протокол, используемый для получения текущего времени и даты. Библиотека LwIP SNTP, доступная в esp-idf, помогает получать текущее время и синхронизировать таймер ESP32 с NTP-сервером. Это очень полезно в приложениях для регистрации данных, где необходимо записывать значения данных вместе с правильными метками времени через определенный интервал времени.

Синхронизация времени с NTP на ESP32 с помощью ESP-IDF

Также на нашем сайте вы можете посмотреть статью про интернет часы на ESP32 с получением времени по протоколу NTP (с помощью Arduino IDE).

API ESP32 для работы с SNTP с помощью ESP-IDF

Теперь давайте обсудим API библиотеки LwIP SNTP, предоставляемые ESP-IDF для получения текущего времени.

Это заголовочный файл, необходимый для подключения библиотеки:

Функция gettimeofday обычно используется для доступа к текущей метке времени. Аналогично, функция settimeofday используется для установки времени. Именно эта функция используется библиотекой LwIP для установки текущего времени при получении ответа от NTP-сервера.

Однако стандартная библиотека C предоставляет еще несколько функций, связанных со временем. Некоторые из них перечислены ниже:

Функция sntp_get_sync_status() используется для получения статуса времени. Если время синхронизировано, она возвращает ответ SNTP_SYNC_RETURN_COMPLETED. Если статус сброшен, она возвращает SNTP_SYC_STATUS_RESET. Кроме того, если происходит плавная синхронизация времени, она возвращает ответ SNTP_SYNC_STATUS_IN_PROGRESS.

Функция sntp_set_sync_status() используется для установки статуса синхронизации времени. Она принимает один параметр — 'sync_status', обозначающий статус синхронизации времени.

Далее у нас есть функция sntp_get_sync_mode() . Она используется для получения режима синхронизации времени. Эта функция возвращает ответ SNTP_SYNC_MODE_IMMED, если синхронизация настроена на немедленное обновление времени. В противном случае она возвращает ответ SNTP_SYNC_MODE_SMOOTH, если включено плавное обновление времени.

Функция sntp_set_sync_mode() используется для установки режима синхронизации времени. Она принимает один параметр 'sync_mode', который обозначает режим синхронизации. Режим может быть либо SNTP_SYNC_MODE_IMMED, либо SNTP_SYNC_MODE_SMOOTH. При выборе режима SNTP_SYNC_MODE_IMMED системное время обновляется сразу после получения от SNTP-сервера. При выборе режима SNTP_SYNC_MODE_SMOOTH устанавливается плавное обновление времени. В этом случае для уведомления о времени используется функция adjtime.

Функция sntp_set_time_sync_notification_cb() используется для установки функции обратного вызова для уведомления о синхронизации времени. Она принимает один параметр — функцию обратного вызова.

Пример ESP-IDF для работы с SNTP

В этом разделе мы создадим и протестируем пример, используя API LwIP SNTP, как описано ранее. Мы будем использовать пример SNTP, предоставленный ESP-IDF. На примере мы покажем, как получить текущее время с помощью SNTP.

Создание примера проекта

Откройте VS Code и перейдите в менюView > Command Palette («Вид» > «Палитра команд»). Введите в строке поиска ESP-IDF: New Project и нажмите Enter.

Укажите название проекта и каталог. Мы назвали наш проект «ESP_IDF_SNTP». Для платы ESP-IDF мы выбрали опцию custom board («Пользовательская плата»). В качестве целевой платформы ESP-IDF мы выбрали модуль ESP32. Нажмите кнопку ‘Choose Template’ («Выбрать шаблон»), чтобы продолжить.

Создание нового проекта с помощью ESP-IDF

В разделе Extension («Расширение») выберите опцию ESP-IDF:

Выбор опции ESP-IDF в разделе Extension («Расширение»)

На вкладке Protocols («Протоколы») мы щелкнем по пункту «sntp». Затем нажмем ‘Create project using template sntp’ («Создать проект, используя шаблон sntp»).

Создание проекта в ESP-IDF с использованием шаблона sntp

Вы получите уведомление о создании проекта. Чтобы открыть проект в новом окне, нажмите «Да».

Это откроет созданный нами проект ESP_IDF_SNTP во вкладке «Проводник». Внутри папки проекта находится несколько папок. Это справедливо для всех проектов, которые вы будете создавать с помощью ESP-IDF Explorer.

Редактор конфигурации ESP-IDF SDK

Для начала перейдем в меню menuconfig. Щелкните значок, показанный ниже. Откроется редактор конфигурации ESP-IDF SDK.

Иконка для открытия menuconfig в ESP-IDF

Прокрутите вниз и откройте Example Connection Configuration (пример конфигурации подключения). Здесь нам нужно указать SSID и пароль нашей сети Wi-Fi. Это необходимо, потому что в примере с SNTP при первой загрузке ESP32 подключается к интернету и использует SNTP для получения текущего времени. Мы укажем параметры подключения. Также есть возможность подключения через интерфейс Ethernet.

Далее прокрутите вниз до раздела Example Configuration («Пример конфигурации») и выберите метод синхронизации времени. В этом примере представлены три метода синхронизации времени.

  1. Обновление времени сразу после получения: это метод, выбранный по умолчанию. В этом случае время обновляется немедленно после получения от SNTP-сервера.
  2. Обновление времени с помощью плавного метода (adjtime): в этом методе функция adjtime используется для уведомления о времени.
  3. Пользовательская реализация: в этом методе встроенная синхронизация времени не используется.

Мы используем опцию ‘Update Time immediately when received’ («Обновлять время сразу после получения»).

Включение функции обновления времени сразу после получения

Далее перейдите к настройкам, специфичным для ESP32 (ESP32-specific). Убедитесь, что для параметра “Timers used for gettimeofday function” («Таймеры, используемые для функции gettimeofday») выбрана опция “RTC and high-resolution timer” («RTC и таймер высокого разрешения») или «RTC». Это гарантирует, что после синхронизации с SNTP-сервером отсчет времени будет выполняться с помощью этих таймеров. Когда плата ESP32 находится в режиме глубокого сна, для отслеживания времени будет использоваться встроенный таймер RTC. Аналогично, таймер высокого разрешения FRC1 обеспечит точность времени до микросекунд, пока плата находится в активном режиме.

Выбор таймера высокого разрешения для функции gettimeofday

Пример кода ESP-IDF для работы с SNTP

Перейдём к файлу main.c. В папке main находится исходный код, поэтому файл main.c будет расположен именно там.

Теперь перейдите в файл main > sntp_example_main.c  и откройте его.

Ниже приведён код, который вы увидите в исходном коде. Этот пример кода демонстрирует синхронизацию платы ESP32 с SNTP-сервером для получения текущего времени. После первоначальной загрузки плата ESP32 подключается к Wi-Fi, синхронизируется с SNTP-сервером и получает текущее время. Затем плата ESP32 переходит в режим глубокого сна. В это время таймер RTC отслеживает текущее время. После пробуждения ESP32 выводит текущее время, не подключаясь к Wi-Fi.

Как работает код?

Для начала мы подключим необходимые библиотеки, включая библиотеки FreeRTOS для генерации задержек и создания задач, sys/time.h и esp_sntp.h для доступа ко времени, esp_log.h для отладки и вывода информационных логов, esp_sleep.h для перевода платы ESP32 в режим глубокого сна и т.д.

Этот код использует информационное логирование. Функция логирования принимает два аргумента. Первый аргумент — это тег, а второй — отформатированная строка. Поэтому эта глобальная переменная будет полезна при вызове функций ESP_LOGI(). Здесь «example» — это тег, который будет использоваться при логировании.

Далее, есть переменная boot_count, которая хранит количество перезагрузок ESP32. Для хранения этой статической целочисленной переменной в памяти RTC используется RTC_DATA_ATTR. Это гарантирует, что значение счетчика загрузок сохранится, пока плата ESP32 переходит в глубокий сон, а затем просыпается.

Если пользователь выбрал пользовательский метод синхронизации времени, то будет выполнен следующий код. Здесь вызывается функция sntp_sync_time(). Функция sntp_sync_time() используется для обновления системного времени. Она принимает один параметр 'tv', который представляет собой время, полученное от SNTP-сервера. Внутри этой функции вызывается функция settimeofday(). Эта функция находится в заголовочном файле sys/time.h. Она принимает два параметра. Первый параметр — это тип данных timeval, в данном случае 'tv'. Второй параметр — это тип данных часового пояса, в данном случае NULL. В этот момент терминал выводит сообщение «Время синхронизировано из пользовательского кода». Наконец, функция sntp_set_sync_status() используется для установки статуса синхронизации времени как SNTP_SYNC_STATUS_COMPLETED.

Функция time_sync_notification_cb() выводит сообщение “Notification of a time synchronization event” («Уведомление о событии синхронизации времени»).

Внутри функции app_main() сначала после каждого сброса увеличивается счетчик загрузок. Счетчик загрузок выводится в терминал.

Затем создаётся структура времени с именем timeinfo. Она содержит информацию о времени, например, количество часов/минут/секунд. Функция localtime_r(&now, &timeinfo) преобразует время в секундах с начала эпохи в местное время.

Если корректное время еще не установлено, вызывается функция obtain_time(), которая получает время с SNTP-сервера. Переменная 'now' теперь содержит текущее время.

Для синхронизации времени, если пользователь выбрал метод плавной синхронизации, будет выполнен следующий код. Здесь к текущему системному времени добавляется ошибка в 500 мс. Это сделано для проверки функции adjtime.

Далее, с помощью следующих строк кода устанавливается часовой пояс на восточное стандартное время. Текущее время в Нью-Йорке будет выведено в терминал.

Аналогичным образом, после установки часового пояса на китайское стандартное время, на экране терминала отображается текущее время в Шанхае.

Если режим синхронизации времени установлен на SNTP_SYNC_MODE_SMOOTH, что означает выбор метода плавной синхронизации обновления, то выполняются следующие строки кода.

В данном случае, если статус синхронизации времени равен SNTP_SYNC_STATUS_IN_PROGRESS, что означает, что синхронизация времени все еще выполняется, вызывается функция adjtime(). Эта функция принимает два параметра, как показано ниже:

Затем плата ESP32 переходит в режим глубокого сна на 10 секунд, используя функцию esp_deep_sleep().

obtain_time()

Функция obtain_time() отвечает за получение текущего времени после синхронизации ESP32 с SNTP-сервером.

Во-первых, раздел NVS по умолчанию инициализируется с помощью функции nvs_flash_init(). Затем с помощью функции esp_netif_init() инициализируется lwIP. После этого с помощью функции esp_event_loop_create_default() создается цикл событий по умолчанию.

Далее плата ESP32 подключается к сети Wi-Fi, учетные данные которой были указаны пользователем в menuconfig. Затем вызывается функция initialize_sntp() для инициализации SNTP-сервера.

Затем мы ждем несколько мгновений, пока установится системное время. Это проверяется путем получения статуса синхронизации SNTP с помощью функции sntp_get_sync_status() и проверки, находится ли статус в состоянии SNTP_SYNC_STATUS_RESET и сохраняется ли количество повторных попыток. После этого функция localtime_r(&now, &timeinfo) преобразует время в секундах с начала эпохи в местное время. Затем ESP32 отключается от сети.

initialize_sntp()

Функция initialze_sntp() инициализирует SNTP-сервер и запускает синхронизацию.

Следующие три функции запускают синхронизацию ESP32 с SNTP. Здесь «pool.ntp.org» — это обычно используемый SNTP-сервер.

Если пользователь выбрал плавный режим синхронизации времени, будет выполнен следующий код. Функция sntp_set_sync_mode() установит режим синхронизации времени как SNTP_SYNC_MODE_SMOOTH. В этом случае устанавливается плавное обновление времени. Для уведомления о времени в этом случае используется функция adjtime.

Компиляция скетча

Для прошивки микросхемы введите следующую команду в последовательном терминале. Не забудьте заменить COM-порт на тот, через который подключена ваша плата.

Ввод команды для компиляции скетча

После успешной прошивки кода можно просмотреть все информационные логи. При первом включении ESP32 можно увидеть текущую дату и время в Нью-Йорке, а также в Шанхае. Затем плата ESP32 переходит в режим глубокого сна на 10 секунд.

Проверка в терминале получения времени и даты

Через 10 секунд плата ESP32 активируется и записывает текущую метку времени для Нью-Йорка и Шанхая. Кроме того, выводится счетчик перезагрузок, обозначающий количество перезапусков платы ESP32.

Проверка в терминале повторного получения времени и даты

(Проголосуй первым!)
Загрузка...
25 просмотров

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *