• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Вопрос Программный RTC на Ардуино_8266

zzav

New member
Прошу дать совет, как правильно решить задачу отсчета времени(RTC) в Ардуино для ESP8266. Внешние RTC (DS3231 и пр.) не рассматриваем, только программно.
Самым разумным и простым в общем случае видится использование таймера, выдающего "тики" с определенной частотой, и подсчет этих "тиков" набором счетчиков, какие душе угодно (арифметика на уровне "плюс единичка и сравнение"). При этом без дополнительных вычислительных усилий можно получать "события"(флаги) с желаемой периодичностью. Казалось бы, в Ардуино для 8266 есть такие таймеры (библиотека Ticker, реализованная через os_timer SDK), все бы хорошо, но, видимо, при "тяжелых" приоритетных операциях (например, подключении к WiFi) эти программные таймеры "уходят"(и сильно!) по времени. Есть ещё "какой-то" hw_timer, но доступа к нему из Ардуино нет; кроме того, многие его вообще не рекомендуют использовать. Кстати, это так?
Остается только возможность использовать вполне точные micros(), millis() , напрямую связанные с недоступными приоритетными счетчиками. Но здесь при необходимости формирования "событий" приходится все время обращаться к этим функциям (polling) и анализировать (постоянно выполняя операции с 32-битной арифметики) прошедшие интервалы. Тяжело и непродуктивно как-то...
Как поступить в данном случае - ESP8266 и Arduino Core (на основе SDK 1.5.3)? Спасибо, если кто откликнется...
 

pvvx

Активный участник сообщества
Казалось бы, в Ардуино для 8266 есть такие таймеры (библиотека Ticker, реализованная через os_timer SDK), все бы хорошо, но, видимо, при "тяжелых" приоритетных операциях (например, подключении к WiFi) эти программные таймеры "уходят"(и сильно!) по времени.
Требуется отключение sleep режима у WiFi Station в NONE. Иначе SDK останавливает ВСЕ счетчики, таймеры и CPU на паузы между приемами baecon, включая millis.
Если не используется WiFi (отключен совсем своей командой), то многие аппаратные счетчики, включая 64-битный счетчик микросекунд не работают.
В итого - Делать ничего не надо, кроме как отключить sleep у WiFi.
 
Последнее редактирование:
  • Like
Реакции: zzav

zzav

New member
Делать ничего не надо, кроме как отключить sleep у WiFi.
Спасибо за ответ и практический совет. Но...получил тот же отрицательный результат.
Именно, несмотря на WiFi.setSleepMode(WIFI_NONE_SLEEP) (последующая проверка WiFi.getSleepMode() дает =0), после принудительного отключения WiFi.setAutoConnect(false); WiFi.setAutoReconnect(false); WiFi.disconnect(), а затем включения WiFi.setSleepMode(WIFI_NONE_SLEEP); WiFi.setPhyMode(WIFI_PHY_MODE_11B); WiFi.mode(WIFI_STA) счетчики уходят на 1...1.2 секунды. Причем изменение 8-битных счетчиков(полей структуры) производится внутри "прерывания" от ticker, так что остальной код программы вряд ли может быть причиной.
Код:
void tick_100ms_job(void)   
{
 
  new100ms = true;
  if(++t.sec10th == 10)
  {
  t.sec10th=0;
  new1sec=true;
  if (++t.second == 60)  
  {
  t.second=0;
  new1min=true;
  if (++t.minute == 60)
  {
  t.minute=0;
  UpdTimebyHour(&t,1);
  new1hour=true;
   
  }
  }  
  }
}
При этом millis() выдает последовательные точные значения...
Я правильно реализовываю Ваш совет?
 

tretyakov_sa

Moderator
Команда форума
Прошу дать совет, как правильно решить задачу отсчета времени(RTC) в Ардуино для ESP8266. Внешние RTC (DS3231 и пр.) не рассматриваем, только программно.
Что в итоге хотите получить? Вам просто нужно текущее время или что?
 

zzav

New member
Что в итоге хотите получить? Вам просто нужно текущее время или что?
Хочу элементарного - получать "тики" с заданной периодичностью, но не "уходящие" от реального точного времени.
В связи с этим и был изначальный вопрос: где в Ардуино 8266 взять такой опорный таймер? Программные таймеры os_timers "уходят" от реального времени при нагрузке (и совет отключить WiFi SLEEP, к сожалению, ничего не дает). А постоянно анализировать точно считающий millis() для формирования "тиков" - расходовать всю выч.мощность практически вхолостую. Я правильно понимаю ситуацию с 8266(и его SDK)? Или есть ещё какой-то механизм, которого я не вижу?
 

Сергей_Ф

Moderator
Команда форума
zzav, на вопрос @tretyakov_sa Вы так и не ответили. Для чего? Вполне возможно, что Ваша конечная цель достижима другими средствами. Миллис, тоже не совсем точен, вообще то.
 

zzav

New member
zzav, на вопрос @tretyakov_sa Вы так и не ответили. Для чего? Вполне возможно, что Ваша конечная цель достижима другими средствами. Миллис, тоже не совсем точен, вообще то.
То что любую цель всегда можно как-то достичь, это несомненно...
Вопрос был о подходе в принципе к обработке интервалов, привязанных к реальному времени, в текущей среде Ардуино8266.
Ну, хорошо, пусть, например, "хочу дрыгать ножкой контроллера раз в 100ms, причем эти 100ms-моменты должны совпадать с соответствующими моментами реального(мирового) времени. Первичная/периодическая (но не постоянная!) синхронизация с образцовыми часами (по NTP и т.п.) выполняется". Понятно объяснил?
 

Сергей_Ф

Moderator
Команда форума
хочу дрыгать ножкой контроллера раз в 100ms, причем эти 100ms-моменты должны совпадать с соответствующими моментами реального(мирового) времени.
100% не получится с абсолютно любым устройством. Условия некорректные. Точность не определена. NTP не даст точность даже 100мс. Так что о точности с мировым временем говорить вообще не приходится.
И опять Вы говорите не что Вы хотите сделать, а как Вы хотите что-то реализовать.
Вот почитайте, может что то подойдет.
 
Последнее редактирование:

zzav

New member
100% не получится с абсолютно любым устройством. Условия некорректные. Точность не определена. NTP не даст точность даже 100мс. Так что о точности с мировым временем говорить вообще не приходится.
И опять Вы говорите не что Вы хотите сделать, а как Вы хотите что-то реализовать.
Вот почитайте, может что то подойдет.
Именно! Ну, теперь и Вы уловили, что не "что", а КАК? КАК люди делают, когда в их распоряжении нет аппаратных таймеров, а есть лишь последовательно суммирующие счетчики "типа миллис". Кстати, точности в +-100ms можно без особых усилий достичь и на текущем Ардуино8266, синхронизируясь по NTP даже примерно раз в час, лишь учитывая задержку прохождения ntp-пакета, и не используя сложную статистическую математику, реализованную в NTP-сервисах.
Ладно, вопрос закрываем....Спасибо.
 

pvvx

Активный участник сообщества
Спасибо за ответ и практический совет. Но...получил тот же отрицательный результат.
Действия производятся до инициализации (в ардуино setup())? Или в цикле? Т.е. сбой прерывания по времени происходит уже в основном цикле программы или при первом старте WiFi в инициализации?
При пуске WiFi, до общей инициализации SDK, счетчик микросекунд отключен, программный таймер тоже отключен.
Во время работы, при переинициализации WiFi сбоев не должно быть, если установлено WiFi.setSleepMode(WIFI_NONE_SLEEP);
Тут порекомендовать нечего, кроме как обращаться к 64-х битному счетчику микросекунд, запускаемому с момента первой инициализации WiFi для корректировки счета пропущенных прерываний (а аппратные ли они у вас?).
Он отсчитывает время от момента старта WiFi и обычно не меняется, т.к. используется для AP при передаче TSF счетчика (синхронизация WiFi). Т.е. фактически является аппаратным 64-х битным счетчиком времени в us со старта модуля.
Код:
// #define MAC_TIMER64BIT_COUNT_ADDR 0x3ff21048
//===============================================================================
// get_mac_time() = get_tsf_ap() - TSF AP
//-------------------------------------------------------------------------------
uint64 ICACHE_FLASH_ATTR get_mac_time(void)
{
union {
volatile uint32 dw[2];
uint64 dd;
}ux;
volatile uint32 * ptr = (volatile uint32 *)MAC_TIMER64BIT_COUNT_ADDR;
ux.dw[0] = ptr[0];
ux.dw[1] = ptr[1];
if(ux.dw[1] != ptr[1]) {
ux.dw[0] = ptr[0];
ux.dw[1] = ptr[1];
}
return ux.dd;
}
В общем случае ваши часы должны выглядеть как значение этого счетчика + смещение (время старта в микросекундах к примеру от 01.01.2000.. года) и дальнейшему переводу в часы, минуты и секунды. Прибавку лучше взять стандартную, от NTP– тогда можно взять стандартные готовые исходники перевода данного счетчика в текущее, хоть Московское время... И никаких прерываний не требуется.
Для передачи на Web страницу времени от старта какого-то события, проще использовать запомненный SNTP счетчик, а на странице - javascript, переводящий его разницу от текущего и выводу в любимом формате пользователю (день, месяц, год или в его системе год, день,... - это решит java сама стандартными функциями в зависимости от того, на какой планете находится пользователь и учтет все поправки, с форматом вывода) ...
 
Последнее редактирование:

zzav

New member
pvvx, спасибо. Ситуацию с таймингом в текущей Ардуино8266 я, судя по комментариям, понял. Непонятную задержку при подключении к WiFi пока устранить не удалось. Ну, да ладно... Ещё раз спасибо за участие.
 
Сверху Снизу