• Система автоматизации с открытым исходным кодом на базе 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 пока устранить не удалось. Ну, да ладно... Ещё раз спасибо за участие.
 
Сверху Снизу