STM Урок 130. LAN8742A. LWIP. NETCONN. NTP. Узнаём точное время. Часть 1

 

 

 

Продолжаем работу с сетью LAN, библиотекой стека протоколов LWIP, её интерфейсом NETCON.

Сегодня мы ещё раз поработаем с протоколом транспортного уровня, так сказать, закрепим практически лишний раз наши знания данного протокола, но только целью сегодняшнего занятия мы поставим себе задачу — получить точное время с одного из серверов точного времени по протоколу NTP (Network Time Protocol), который по модели OSI является уже протоколом прикладного уровня и несёт в себе уже осознанную полезную нагрузку. С протоколами такого уровня мы уже много раз встречались. Поэтому, думаю, будет не тяжело. Тем более с протоколом NTP мы работали и не раз, причём работали также с использованием контроллера STM32 в уроке 83, поэтому изучать нам его уже не придётся, мы будем уже пользоваться накопленными знаниями и использовать данный протокол в нашем проекте. Мы будем использовать внутренний часовой модуль RTC нашего контроллера STM32F746, и мы не будем устанавливать сами время для данного модуля, а произведём синхронизацию его показаний с мировым временем, которое мы и получим благодаря протоколу NTP. Тем более были многочисленные просьбы поработать с модулем RTC. Поэтому, думаю, урок будет для многих весьма полезным.

Что ж, приступим. Начнём сразу с проекта, который будет сделан из проекта прошлого занятия с именем LAN8742_WEBSOCKET_NETCONN и назван будет, соответственно, LAN8742_NTP_CLIENT_NETCONN.

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

Теперь откроем наш проект в Cube MX и отключим сначала библиотеку mbedtls

Отключим также генератор случайных чисел

Включим модуль RTC

Перейдём в Configuration и в разделе LWIP отключим HTTPD

В разделе FREERTOS немного увеличим приоритет задачи вывода строк на дисплей

А в настройках RTC изменим формат данных

 

Прежде чем генерировать проект, немного подправим код в файлах библиотек DMA2D, чтобы две строки в main.c на нас не ругались.

Для этого откроем файл stm32f7xx_hal_dma2d.h по пути «C:\Users\Имя вашего пользователя\STM32Cube\Repository\STM32Cube_FW_F7_V1.12.0\Drivers\STM32F7xx_HAL_Driver\Inc» и закомментируем вот здесь четыре строки

 

 

 

И здесь тоже закомментируем четыре строки

 

 

Сохраним файл, сгенерируем проект для System Workbench и откроем его там. Установим уровень оптимизации в 1, уберём при наличии отладочные настройки и теперь неизвестных компилятору строк в файле main.c не будет. Сами строки будут, но они будут уже известными.

Для начала удалим вот эти строки

#include «mbedtls/sha1.h»

#include «mbedtls/base64.h»

Затем вот эти

char guid_str[] = {«258EAFA5-E914-47DA-95CA-C5AB0DC85B11»};

unsigned char hash[20] = {0};

osThreadId ThreadTCPHandle;

Удалим вот эти массивы, хотя в статье прошлого урока они вроде бы удалены, но в проекте, который я выложил, они почему-то остались

char str1[60];

char str_buf[1000]={'\0'};

В функции main() изменим шапку

TFT_DisplayString(0, 10, (uint8_t *)"NTP Client", CENTER_MODE);

Удалим вместе с телами функции StrSort, tcp_send и http_thread.

Функцию tcp_thread переименуем в netconn_thread и удалим из неё всё тело.

В функции задачи по умолчанию StartDefaultTask удалим инициализацию LWIP, иначе теперь он у нас инициализируется дважды

/* USER CODE BEGIN 5 */

MX_LWIP_Init();

Вместо этого мы установим цвет текста

 

В следующей строке изменим имя задачи и её функции

sys_thread_new("netconn_thread", netconn_thread, NULL, DEFAULT_THREAD_STACKSIZE, osPriorityNormal);

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

 

А в теле самой функции TaskStringOut установим заданный размер шрифта из очереди

 

А затем не забудем установить также из очереди и координату x

TFT_DisplayString(qstruct->x_pos, qstruct->y_pos, (uint8_t *)str_out, LEFT_MODE);

В функции netconn_thread добавим указатель на данную структуру

 

Далее добавим переменные для даты и времени

 

Создадим два файла для библиотеки NTP — ntp.h и ntp.c в соответствующих папках Inc и Src проекта в дереве проектов, чтобы они сразу и подключились в наш проект.

Данные файлы первоначально будут иметь следующее содержание

ntp.h:

 

ntp.c:

 

Подключим нашу библиотеку также и в main.c

 

В файле ntp.c создадим функцию для задачи отправки пакетов NTP-серверу

 

Создадим на данную функцию прототип в заголовочном файле, перейдём в файл main.c и добавим глобальный счётчик

 

В функции netconn_thread создадим нашу задачу

Здесь же добавим бесконечный цикл с задержкой

 

Узнаем время, правда не мировое, а у нашего модуля RTC, занеся его в наши соответствующие структуры

 

Затем отобразим значение нашего счётчика, а также дату и время из структуры на дисплее, и по окончанию цикла увеличим счётчик на 1

 

Соберём код, прошьём контроллер и посмотрим результат на дисплее

Счётчик отлично инкрементируется, часы ходят, правда пока ещё не синхронизируются, но это только дело времени.

Перейдём теперь в файл ntp.c в функцию ntp_thread и добавим в неё некоторые переменные и структуры

 

Создадим структуру для соединения по протоколу UDP с функцией обратного вызова

 

Теперь создадим прототип функции обратного вызова в этом же файле

 

И также в самом низу файла добавим данную функцию, в которой сразу добавим переменную, указатель и массив

 

Вернёмся пока в функцию ntp_thread и уложим адрес сервера NTP в структуру

 

Как и где найти адрес сервера, я рассказывал в уроке 83, а также вы можете использовать и этот — у меня с ним проблем не было.

Далее, при успешно создании структуры, свяжем её с нашим локальным портом, выбрав любой пришедший в голову

 

При успешной связи с портом, мы пытаемся соединиться с сервером NTP, здесь уже используется порт 123, а если связь не с портом не удалась, то уничтожаем нашу структуру соединения

 

При успешном соединении с сервером создадим бесконечный цикл, в котором создадим структуру буфера и выделим под неё память 48 байт, сколько именно требуется для пакета NTP

 

Далее нам надо будет что-то отправить серверу, для этого создадим глобальную структуру

 

Это стандартная структура, пакета NTP, также мы здесь применили выравнивание полей.

Возвращаемся в нашу функцию ntp_thread и при успешном создании структуры буфера добавим переменную-указатель на такую структуру, который приравняем к буферу, который будем отправлять на сервер

 

Обнулим все поля структуры

 

В первый байт занесём версию протокола и режим клиента

 

Если вдруг нам за какое-то определённое время сервер не пришлёт ответ, то нам нужно будет послать запрос повторно, а если сервер ответит за это время, то таймаут будет уже другой. Его обычно рассчитывают по точности своих часов. Если они например сбиваются за сутки, то запрашиваем раз в сутки. Если сбиваются за час, то запрашиваем раз в час и т.д. Пока мы данные таймауты настроим поменьше, не ждать же нам часами. Только вот как же нам всё это организовать?

Есть на этот счёт специальная функция в LWIP, но она мне не понравилась. Сделал всё по-своему.

Добавим две глобальные переменные в ntp.c

 

Одна из них будет хранить старое значение системного таймера, а вторая — новая, вот по разнице между их значениями мы и будем следить за таймаутами.

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

 

Предыдущий урок Программирование МК STM32 Следующая часть

 

 

Отладочную плату можно приобрести здесь 32F746G-DISCOVERY

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM LAN8742A. LWIP. NETCONN. NTP. Узнаём точное время

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

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

*