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

Таймеры

ART_HA

Member
Замена 1000 на 100 в Ticker.cpp дала прекрасный результат. (y)
Но когда я попытался выкрутиться путем включения измененного мною Ticker.cpp в каталог с исходником с соответствующим #include "Ticker.cpp" я получил ошибку компилятора, хотя вроде как такое должно бы работать. Или все-такое вообще нельзя делать?
 

aZholtikov

Active member
Замена 1000 на 100 в Ticker.cpp дала прекрасный результат. (y)
Но когда я попытался выкрутиться путем включения измененного мною Ticker.cpp в каталог с исходником с соответствующим #include "Ticker.cpp" я получил ошибку компилятора, хотя вроде как такое должно бы работать. Или все-такое вообще нельзя делать?
Вызывает ошибку #include "Ticker.cpp". Нужно #include "Ticker.h".
 

ART_HA

Member
А как я тогда подставлю измененный файл без вмешательства в APPDATA?
Мне же нужно как то указать, где он находится.
Ошибку дает вот такую:
exit status 1
Ошибка компиляции для платы NodeMCU-32S.

PS. Ба! Так Ticker.h и Ticker.cpp это на Си++ точно такая же пара, как Ticker.h и Ticker.c на Си?
 

aZholtikov

Active member
А как я тогда подставлю измененный файл без вмешательства в APPDATA?
Мне же нужно как то указать, где он находится.
Создаем в папке lib (или где там Arduino IDE библиотеки держит) папку ART_HA_Ticket (например). Копируем в нее Ticker.h и Ticker.cpp. Переименовываем в ART_HA_Ticker.h и ART_HA_Ticker.cpp (например). Правим их как надо (меняем код + как минимум в ART_HA_Ticker.cpp изменяем #include "Ticker.h" на #include "ART_HA_Ticker.h").
В программе изменяем #include "Ticker.h" на #include "ART_HA_Ticker.h".
Фсё.
 

ART_HA

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

ART_HA

Member
Как ни странно, всё получилось. Сделал отсчеты таймера по 10 мкс. Работает уверенно. :)
 

ART_HA

Member
Создаем в папке
Появилась небольшая проблема.
У меня сейчас аппаратным прерыванием №1 запускается однократный таймер, который после истечения заданного времени запускает прерывание №2, которое снова запускает этот таймер на другое заданное время, по истечении которого прерыванием №3 заканчивается вся операция, вызванная аппаратным прерыванием №1.
Но из-за не очень высокой стабильности частоты запуска аппаратного прерывания №1 существует риск, что это прерывание произойдет во время исполнения обработчика прерывания №2 или №3. Насколько я понимаю, аппаратное прерывание №1 приоритетнее программных №2 и №3, но недопустимо, чтобы после исполнения вызванной им цепочки прерываний, программа вернулась в обработчик прерванного им прерывания №2 или №3.
Существует ли в ESP32 возможность сброса возможного хода исполнения прерываний №2 и №3 аппаратным прерыванием №1?
 

aZholtikov

Active member
Существует ли в ESP32 возможность сброса возможного хода исполнения прерываний №2 и №3 аппаратным прерыванием №1?
Вопрос интересный... Надо посмотреть...
Но как я раньше говорил - "баловство" с таймерами больше подходит для ESP8266. Для ESP32 намного лучше (ИМХО) использовать FreeRTOS.
 

pvvx

Активный участник сообщества
Как ни странно, всё получилось. Сделал отсчеты таймера по 10 мкс. Работает уверенно. :)
Если в это время выполняется delay(N); и не работает WiFi.
Существует ли в ESP32 возможность сброса возможного хода исполнения прерываний №2 и №3 аппаратным прерыванием №1?
Возможно всё, т.к. прерывания программные, вызывающиеся по таблице от одного таймера в отдельном цикле опроса событий. которому надо отдавать управление.
Но сделать это можно только как через ... гланды... - Перегружать регистры CPU из стека...
В Arduino обработка программных таймеров наверняка вынесена в загружаемую часть кода - процедура из ROM не используется. Но они аналогичны + мелкие поправки. Там и покопайтесь.
 

pvvx

Активный участник сообщества
Если prescaler таймера установлен на 16, тогда пределы работы таймера 0.2..1677721.4 us. Максимальный делитель у таймера 0x007fffff.
Т.е. один шаг = 0.2 us.
Менее 2us при 160MHz CPU - перегрузка системы по WDT.
Код:
#define XS_TO_RTC_TIMER_TICKS(t, prescaler, period)    \
     (((t) > (0xFFFFFFFF/(APB_CLK_FREQ >> prescaler))) ?    \
      (((t) >> 2) * ((APB_CLK_FREQ >> prescaler)/(period>>2)) + ((t) & 0x3) * ((APB_CLK_FREQ >> prescaler)/period))  :    \
      (((t) * (APB_CLK_FREQ >> prescaler)) / period))

#if ((APB_CLK_FREQ>>4)%1000000)
     TIMERx_LOAD = XS_TO_RTC_TIMER_TICKS(us, 4, 1000000);
#else
     TIMERx_LOAD = us * (APB_CLK_FREQ>>4)/1000000; // = us * 5
#endif
APB_CLK_FREQ = 80000000
 

ART_HA

Member
Если в это время выполняется delay(N); и не работает WiFi.
WiFi в этом режиме не запускается, а delay(N) в программе нет вообще.
К таймеру претензий нет.
Есть претензии к тому, что у таймера ESP32 нет аппаратного выхода, поэтому его приходится обеспечивать через прерывание по таймеру, отсюда и проблема.
 

pvvx

Активный участник сообщества
Есть претензии к тому, что у таймера ESP32 нет аппаратного выхода, поэтому его приходится обеспечивать через прерывание по таймеру, отсюда и проблема.
Как вы писали проблема в приоритетах у ваших таймеров.
И задержки у вас большие - десятки мс?
Почему вы не можете создать хоть десять программных таймеров, а используете NMI?
Из 2016 года:
ets_timer_arm_new - это управление программным таймером на основе аппаратного. _new по причине что у аппаратного таймера переключают делитель на счет в us. У ROM-BIOS ets_timer_arm() и расчет идет на другой делитель в аппаратном таймере.
Процедуры ets_timer_arm добавляют в связный список новый программный таймер и вычисляет задержку до срабатывания следующего программного таймера и записывают её в регистр счета аппаратного таймера. Когда будет работать процедура ets_run(), то она определит срабатывание alarm у аппаратного таймера и вызовет код вашего программного таймера... Это упрощенно.
 

pvvx

Активный участник сообщества
Назначенный код программных таймеров (ets_timer_setfn()) выполняется последовательно. И если какие-то проблемы - всегда можно временно отменить любые другие прерывания (ets_intr_lock(), ets_intr_unlock()).
Процедура любого программного таймера может отменить выполнение другого - ets_timer_disarm().
Как переназначено название функций и параметров к ним в Arduino - это ищите сами. Они базовые, т.к. имеют часть кода в ROM чипа.
 

ART_HA

Member
Мне не нужно отменять аппаратное или программное прерывания, мне нужно аппаратным прерыванием аварийно закончить работу обработчика программного прерывания. А еще лучше и обработчика самого себя тоже. :)
 

pvvx

Активный участник сообщества
Мне не нужно отменять аппаратное или программное прерывания, мне нужно аппаратным прерыванием аварийно закончить работу обработчика программного прерывания. А еще лучше и обработчика самого себя тоже. :)
Оно и есть -> ets_timer_disarm(x) останавливает назначенный x софт-таймер и запрещает вызов его кода.
А в параметрах запуска ets_timer_arm[_new](x, период, тип) - тип задает однократное или постоянное срабатывание.
И ваши вопросы и проблемы не понятны. Сами себя путаете используя NMI прерывание и какие-то кривые Arduino таймеры.
PS: когда-то, 2016г, на этих таймерах делал управление переключением направления ModBus RS-485 и вычислением задержек - всё Ok. Беда только с WiFi драйверами, запрещающими все прерывания на долгий срок. Но это происходит не часто...
 

pvvx

Активный участник сообщества
И уж если используете NMI прерывание - то для ESP8266 оно должно выполняться не более 1 us. Иначе происходит нарушение таймингов WiFi. Это потом даже описано в документации...
А в Arduino вы не можете обеспечить такое исполнение из-за C++ и прочих бяк.
 

pvvx

Активный участник сообщества
Короче - вы выбрали плохой алгоритм работы и даже не описали его. B итоге мучаетесь с Arduino.
Имеющиеся в системе ESP8266 софт-таймеры позволяют выводить на GPIO любые сигналы со средним джиттером в 150 us из-за работы WiFi, если подработать его дрова.
 

ART_HA

Member
Для понимая приведу упрощенный пример.
На вход аппаратного прерывания ESP32 подаются короткие импульсы частотой 1 кГц, в ответ на которые ESP32 вырабатывает импульс заданной длительности, например 0,75 мсек.
Это называется одновибратор.
И тут случается проблема: в серии поступающих импульсов появляется периодическая помеха частотой 2 кГц.
Что произойдет в этом случае с нашим ESP32?
 

ART_HA

Member
Вопрос интересный... Надо посмотреть...
Есть идея при поступлении сигнала на вход аппаратного прерывания запускать еще один таймер - для контроля периода входных импульсов.
Но как остановить работу первого прерывания при обнаружении недопустимого повышения частоты входящих сигналов?
 
Сверху Снизу