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



В предыдущей части занятия мы создали проект, настроили модуль RTC и начали готовить запрос на точное мировое время.

Вернёмся в функцию ntp_thread и занесём значение системного таймера в переменную, хранящую старое значение

 

Отправим запрос на NTP-сервер, так как кроме первого байта нам ничего в нём заполнять не нужно и очистим буфер

 

С данной функцией мы пока не закончили, мы ещё сюда вернёмся.

Теперь займёмся приёмом и перейдём в функцию обратного вызова ntp_receive_callback.

Объявим в ней две переменных структур даты и времени

 

Если нам что-то пришло, то попробуем принять пакет

 

Добавим локальную переменную для режима

 

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

 

Оставим в значении режима только младшие три бита, остальные очистим

 

Добавим ещё две локальных переменных для таймштампа и значения в секундах

 

Если режим четвёртый (сервер), то заберём старшую часть таймштампа из принятого буфера по 40-му адресу. Это старшая часть нашего времени. Младшая часть находится в следующих завершающих четырёх байтах, это дробная часть секунд, она нам не нужна.

Так как время в таймштампе хранится в перевёрнутом виде, то перевернём его обратно с ног на голову и присвоим переменной для секунд

 

 

Подключим глобальную переменную, а также периферию RTC

 

Вернёмся в функцию ntp_receive_callback и покажем на дисплее наши секунды

 

Добавим ещё 2 локальные переменные и структуру для хранения полей времени

 

Добавим два макроса для типов смещения секунд и для часового пояса

 

Добавим локальную переменную в нашу функцию ntp_receive_callback

 

Разложим наше значение в секундах по полям структуры, применив специальную функцию из библиотеки time.h, перед этим скорректировав временную зону и узнав по самому старшему биту, какой формат секунд у нас пришел, то есть какой из двух типов смещения

 

Из структуры tim1 перепишем значения в наши структуры модуля RTC

 

А теперь опять сохраним значение системных квантов но уже в другую переменную, которая хранит новое значение системных квантов

 

А теперь нам надо передать данное значение в функцию ntp_thread. И, конечно же, ничего больше не приходит в голову. как воспользоваться очередью, тем более она у нас пустует.

 

 

Перейдём в файл main.c и переименуем идентификатор нашей очереди

osMessageQId timeout_Queue;

Также переименуем данный идентификатор и в создании очереди в main()

osMessageQDef(timeout_Queue, QUEUE_SIZE, uint16_t);

timeout_Queue = osMessageCreate(osMessageQ(timeout_Queue), NULL);

В файле ntp.c подключим наш идентификатор

 

Вернёмся в нашу функцию ntp_receive_callback и, если у нас превышен таймаут, то пошлём символическую единичку в очередь

 

Примем нашу единичку в функции ntp_thread, в которой сначала добавим локальную переменную

 

Подождём немного, это будет первый таймаут

 

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

А теперь примем значение из очереди, если оно там, конечно есть

 

Добавим локальную переменную и обнулим её

 

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

Примем значение из очереди и присвоим его нашей переменной

 

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

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

 

У нас получится тогда общая задержка — одна минута так как первую задержку мы всё равно ждём, а если неудачный случай, то только 20 секунд.

Потом мы второй таймаут увеличим. Сейчас мы его сделали небольшим, чтобы дождаться повторного запроса и ответа в удачном случае.

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

Вот как-то так.

Наконец-то соберём наш проект и проверим работу нашего кода на практике.

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

Затем мы даже при удачном случае получим пакет примерно через 60 секунд, если конечно нам придёт единичка в очереди

И так, если всё нормально, то мы будем запрашивать и получать пакеты через 60 секунд

Мы проверили, что наш код работает правильно, все пакеты запрашиваются и получаются.

Значение нашего таймера на дисплее у нас уменьшено в 10 раз, так как мы обновляем значение времени раз в 10 милисекунд в функции netconn_thread.

Теперь давайте увеличим задержку между запросами, сделаем её хотя бы час, а то сервер может и разозлиться

 

Таким образом, в данном уроке мы научились работать с протоколом NTP, используя стек протоколов LWIP и интерфейс NETCONN, с помощью чего мы теперь можем получать точное мировое время и использовать его значение в своих нуждах. Мы его использовали в данном уроке для синхронизации времени модуля RTC.

Всем спасибо за внимание!

 

 

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

 

Исходный код

 

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

 

 

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

 

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

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

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

*