Использовать timer0, не влияя на millis() и micros().
Я пишу библиотеку, которой требуется ISR для выключения светодиода через некоторое время после его включения. Поскольку все дело в том, чтобы включать и выключать светодиод, нет необходимости быть очень точным. С другой стороны, я хотел бы использовать эту библиотеку в программе, где timer1 и timer2 выдаются на другие (более важные) задачи, а также мне нужны millis()
и micros( )
функции. Наконец, я использую микроконтроллер ATmega328P, который имеет только 3 таймера (и я не могу легко заменить его другим).
Поэтому мне было интересно, могу ли я подключить ISR к timer0, не затрагивая вышеупомянутые функции Arduino, и – если это можно сделать – каковы будут ограничения такого ISR (например, я полагаю, что не могу использовать все таймеры). /режимы прерывания...), а также недостатки или побочные эффекты использования этого таймера в библиотеке, отличной от Arduino, и функциях Arduino millis()
и micros()
.
Заранее спасибо за любой ответ!
@noearchimede, 👍4
Обсуждение4 ответа
Лучший ответ:
Поэтому мне было интересно, могу ли я подключить ISR к timer0, не затрагивая вышеуказанные функции Arduino,
Да. Несколько способов, в зависимости от вашего уровня комфорта:
Вы можете объявить стандартный OVF Arduino Timer0 «слабым» и написать свой собственный, куда вы можете вставить свой ISR. Но вы должны обрабатывать взаимодействие между переменными, связанными с millis() / micros().
Вы можете изменить стандартный OVF Arduino Timer0, чтобы вставить свой собственный ISR.
И – если это возможно – каковы будут ограничения такого ISR (например, я не могу использовать все режимы таймера/прерывания...)
Стандартный ISR будет выглядеть следующим образом:
ISR(TIM0_OVF_vect) { ... timer0_fract = f; timer0_millis = m; timer0_overflow_count++; //insert your isr here _mytmr0_isrptr(); }
Где _mytmr0_isrptr() – указатель на функцию вашего собственного обработчика ISR.
Проще всего использовать прерывания сравнения вывода. Вы можете заставить его вести себя как виртуальный таймер и делать множество других вещей.
Очевидно, что вы можете придумать множество других способов, и это только отправная точка.
Что это за прерывания? Как я могу их использовать? –
Timer0 имеет три связанных с ним прерывания: переполнение и сравнение канала A и канала B. Прерывание переполнения уже используется функциями синхронизации millis() и micros(), как показано ранее.
Прерывания канала сравнения A/B не используются. И это обсуждение касается их использования для целей синхронизации.
Общий идеал показан в сообщении блога Использование резервных каналов сравнения выходных данных в качестве таймеров — коллекция.
Здесь задача сложнее, чем здесь, но основной идеал тот же. Сделать то, что вы хотели, здесь гораздо проще.
Если вы все еще не можете понять это, я могу предоставить вам фрагменты кода, чтобы вы могли начать работу.
Извините, я не понял третий вариант... Что это за прерывания? Как я могу их использовать?, @noearchimede
Спасибо, теперь понял! Я реализовал это в своей библиотеке, и это работает., @noearchimede
Я рад, что у вас есть решение, которое работает для вас. Ключевым моментом здесь является признание того, что сравнение выходных данных по сути является таймером: он генерирует прерывание при совпадении, в отличие от таймеров, которые делают это при переполнении или нижнем уровне., @dannyf
Как только вы поймете, что можете сделать много виртуальных таймеров из выходных каналов сравнения. для большинства mcus это означает от 2x до 8x виртуальных таймеров на аппаратный таймер., @dannyf
Прерывание может иметь только одну процедуру обработки прерывания. Единственный способ сделать что-то еще, используя прерывание, которое уже обрабатывается в другом месте, — изменить этот существующий обработчик прерывания, чтобы он также вызывал ваш код. Не то, что практично для библиотеки.
Я не вижу никакого практического способа сделать это, кроме как изменить всю систему millis()
в основном API, чтобы разрешить перехват функций обратного вызова, что было бы действительно хорошей возможностью (chipKIT имеет аналогичную систему с прерыванием Core Timer на PIC32) и отправить ее обратно в Arduino для включения в основное ядро, что, конечно же, установит базовую версию для совместимости вашей библиотеки.
И нет никакого способа переопределить ISR системы Millis без изменения файлов API, верно?, @noearchimede
Правильный. Если вы определите второй ISR, вы получите конфликты векторов. Вам просто нужно будет выбрать другое прерывание для использования. Некоторые библиотеки предоставляют макросы #define
и т. д., чтобы выбрать, с каким таймером запускать., @Majenko
Поэтому мне было интересно, могу ли я подключить ISR к timer0, не затрагивая вышеуказанные функции Arduino...
Нет, потому что эти функции используют уже подключенное прерывание.
это не должно быть очень точным...
Просто проверьте текущее время (например, используя миллисы
или микросекунды
) в основном цикле.
главный цикл программы иногда довольно длинный (например, иногда приходится выполнять другие циклы)...
Реструктурируйте так, чтобы этого не было. Вы можете использовать концепцию конечного автомата, чтобы делать что-то время от времени, не застревая во внутренних циклах на долгое время
Это невозможно с прерыванием TIMER0_OVF, но есть также прерывания TIMER0_COMPA/TIMER0_COMPB, и их можно использовать бесплатно. Единственным недостатком является то, что AnalogWrite на соответствующих контактах сдвигает время, когда происходит прерывание., @KIIV
@KIIV Итак, используя timer0_compx, я больше не мог использовать AnalogWrite для соответствующего вывода?, @noearchimede
@noearchimede Вы можете. Просто интервал будет двигаться в соответствии с этим. Но если вам не нужно точное время, это не будет проблемой. Наверняка вы можете проверить все значения ШИМ, чтобы убедиться, что он работает каждый раз., @KIIV
@KIIV Я только что написал новую версию своей библиотеки, используя TIMER0_COMPA, и она работает именно так, как я хотел. Могу я попросить вас написать полный ответ с вашими предложениями, чтобы я мог пометить вопрос как отвеченный?, @noearchimede
@noearchimede Это уже здесь, в ответе dannyf (третий вариант), @KIIV
@KIIV Вчера я не понял его третий вариант, поэтому забыл его, но теперь мне все ясно. Спасибо Вам и всем ответившим!, @noearchimede
Я думаю, что первое решение, предложенное ответом dannyf, неверно, поскольку ISR в AVR GCC нельзя определить как слабую функцию (почему).
Я думаю, что лучшим решением будет добавить функции-обработчики (хуки AKA) с помощью указателя функции на Timer0 ISR внутри исходного файла core wired.c, поставляемого с ядром Arduino, и назначить последний (прикрепить) этот указатель функции к любой желаемой функции. в другой библиотеке/классе или в основном коде приложения.
Подробнее об этом трюке в этой статье здесь .
- Arduino Мигает двумя светодиодами без задержки (количество повторений)
- Сброс Arduino с помощью ПО (каждый день)
- Как запустить 4 светодиода последовательно на основе кнопочного входа?
- Нужен сигнал ШИМ частотой 10 кГц от контактов 3 и 11 с использованием таймера 2.
- Нельзя использовать millis() вместо задержки
- Использование millis() и micros() внутри процедуры прерывания
- Как сделать очень долгую функцию delay(), несколько часов
- Разница между «time_t» и «DateTime»
Почему вы считаете, что вам нужно использовать прерывание для такой упрощенной и некритичной по времени операции?, @Majenko
На самом деле я в настоящее время использую функцию «checkLed()», и она отлично работает. Но 1) основной цикл программы иногда довольно длинный (например, иногда он должен выполнять другие циклы), и мне было бы проще, если бы мне не нужно было заботиться об отключении светодиода (что не критично по времени, но вполне важно), 2) теперь меня вообще очень интересует этот вопрос ;), @noearchimede
Справедливо. TBH Я только что написал подпрограмму, которая делает именно это, но на другом MCU, который имеет другую структуру таймера (он управляет светодиодами TX и RX для индикации активности USB - функции прерывания RX и TX включают светодиоды, таймер включает их через 50 мс), поэтому я понимаю необходимость., @Majenko
Связано: *[Atmel/Arduino: ISR(TIMER0_OVF_vect) не будет компилироваться («сначала определено» в __vector_16)](https://stackoverflow.com/questions/46573550)* (предоставление собственного обработчика для Timer0 и по-прежнему использовать среде Ардуино)., @Peter Mortensen