Взаимодействие прерываний с delay и между собой
- Войдите на сайт для отправки комментариев
Втр, 28/07/2015 - 13:00
Как-то не раз встречал информацию, что использование delay мешает аппаратным прерываниям (хотя, судя по документации, не должно http://arduino.ru/Reference/Delay ): то энкодер пропускает импульсы, то сигналы с IR-пульта не проходят и пр.
Понятно, что теоретически при правильном использовании прерыаний такие ситуации происходить не должны. Но раз происходят, значит, где-то прерывания используются неправильно, и, вероятно, такое использование достаточно распространено.
Опять же, кроме INT есть еще и PCINT. Как они взаимодействуют с delay и другими прерываниями?
Очень хотелось бы собрать некоторую информацию по данному поводу с целью определиться со статегией дальнейшего развития проекта.
Может отказаться от делей? И тогда никто не будет мешать.
andriano, в принципе delay() обычная программа, которая в while вызывает micros() и сверяет пройдённые тики с заданными. Но микрос() сам использует прерывание (Timer0_overflow), но главное во время своей работы глобально запрещает любые прерывания. Таким образом если какому-то невезучему прерыванию захочется выполнится, то сделать оно этого не сможет, и даже не встанет в очередь, как в случае если бы работало другое прерывание. Решение -не использовать функции ардуино, писать свои, где будут учтены все нюансы :)
PS Вспомнилось, что собственные функции компилятора avr-gcc _delay_ms и _delay_us работают просто на подсчёте тактов процессора, так что не должны вызывать подобных проблем :) Только не забыть сделать #include <avr/delay.h>
dimax, правильно ли я понял, что функция delay для Ардуино написана вредителями? Ну или теми, кто собирался таким варварским образом отучить начинающих программистов от использования delay?
В связи с этим все-таки остается два вопроса:
1. Если delay сделана именно так, то почему она так сделана. Тут недавно обсуждали, почему в Ардуино нарушена нормальная логика конструкторов объектов. Я высказал предположение, что для того, чтобы дать разработчику вклиниться в код до инициализации железа. То есть люое даже странное решение обычно имеет какие-то плюсы, ради которых оно и было выбрано. Поэтому хотелось бы именно таких предположений. Мне казалось, что delay идеально подходить для выпаолнения альтернативной работы, начиная с прерываний и заканчивая фоновыми процессами. А, гляди ж ты, все сделано наоборот, почему?
2. Чего следует избегать при обновременном применении INT и PCINT, чтобы исключить возможность потери какого-либо прерывания?
andriano, я ещё в первом сообщении немножко не прав был, прерывание всё равно должно выполнится, если в программе стоял запрет cli(). Как только запрет будет снят. У прерываний есть локальные флаги, в момент когда нужно сработать -ставится флаг, а по флагу уже выполняется прерывание. Соответственно можно инициировать запуск например того же прерывания INT записью флажка в соответсвующий регистр. Но вот отложенное прерывание как раз и может устроить глюк. Например если по прерыванию считываются какие-то дополнительные порты, данные в которых могли уже изменится. А если выросла очередь из прерываний, то первым выполняется прерывание с меньшим номером (номера в даташите можно посмотреть).
на первый вопрос компетентно вряд ли могу ответить. Из явного - delay() имеет не только недостатки, но и преимущество. Вот недостаток её конкурента _delay_ms в том, что эту функцию легко остановить прерыванием, а вернувшись из прерывания она начнёт досчитывать что ей осталось, не принимая в расчёт время, забранное прерыванием. А ардуиновский delay() такой проблемы не имеет. А по второму вопросу уже частично описал процесс, тут просто нужно так организовать работу, что бы учитывалась возможность задержки выполнения команд.
dimax, как останавливать и потом запускать работу прерываний??? полезная фича типо остановить библиотеку
интернет и 433 в какието ответственные моменты( в микрос()), а по их оканчанию запустить.
как останавливать и потом запускать работу прерываний???
Только это очень серьёзно. Надеюсь, Вы знаете, что делаете и зачем Вам это надо.
во время отключения прерывания счетчик micros(),millis() работает???
во время отключения прерывания счетчик micros(),millis() работает???
Попробуйте. Это лучший способ узнать.
во время отключения прерывания счетчик micros(),millis() работает???
Попробуйте. Это лучший способ узнать.
Классика: "И жопыт, сын ошибок трудных"))))
столкнулся с тем, что нужно экономить место в программе, у меня делеев было десятки и десятки, а связано, с тем, что запускается файл amr sim800C и нужно выждать например когда он закончится..
Решил сделать например так:
тоесть в функции вставлен еще и перезапуск таймера вочдога.
Покритикуйте, что может не так? Место заметно сэкономилось, а то уже 31кб флеша занято. Паузы у меня по 2-6 сек в основном. минимум 1кб уже сэкономил, буду и дальше оптимизировать сам скетч.
столкнулся с тем, что нужно экономить место в программе, у меня делеев было десятки и десятки, а связано, с тем, что запускается файл amr sim800C и нужно выждать например когда он закончится..
Решил сделать например так:
тоесть в функции вставлен еще и перезапуск таймера вочдога.
Покритикуйте, что может не так? Место заметно сэкономилось, а то уже 31кб флеша занято. Паузы у меня по 2-6 сек в основном. минимум 1кб уже сэкономил, буду и дальше оптимизировать сам скетч.
Раз просил критики, смотри: что будет, если в timeout передать 80000? Во-первых - будет переполнение, если на платформе, под которую компилируешь - unsigned int занимает два байта (это так под 328-ю мегу и мегу 2560). Во-вторых - будешь висеть в while, НЕ сбрасывая собаку - и она сработает. Кошерный код должен быть таким, ПРИМЕРНО:
По факту получаем - сброс собаки каждую секунду, пока крутится цикл. Это, ессно, наброски, сделанные на сонную голову.
прикольно:) как много я еще не знаю...
Но, интересный момент, в моем первом варианте если
unsigned
int
timeout то компилирует намного меньше чем если ставить
uint32_t timeout ..тут у меня пробелы, но стараюсь в разных вариантах проверять и делать выводы.
Есть классический приём чтения данных с serial, что то типа:
Логично, что время последовательного приёма байта в порт на порядок больше времени работы функции read(), которая за микросекунды забирает сразу целиковый байт из буфера, уменьшая счётчик, и если в буфере останется один единственный байт, а следующий будет в процессе приёма, то read() его быстро считает и последующий вызов available() уже вернёт 0. Соответственно строка (конанда и т.п.) будет считаться дочитанной и пойдёт дальше по коду в обработку (парсинг и т.п.), хотя на самом деле это не так. Есть основания подозревать что такое на самом деле происходит, особенно на малых скоростях Serial. Поправьте если я что то не правильно понимаю. И если так, то как с этим бороться?
зы. работаю на скорости 57600 с модемом SIM800, пробовал ставить _delay_us(200) после read(), вроде не легче.
запускается файл amr sim800C и нужно выждать например когда он закончится..
Если вдруг ещё актуально - намного эффектичней проверять от модема +CREC: 0
Чтобы считать "строку дочитанной", ее нужно снабжать терминатором и проверять его наличие. В качестве варианта можно предложить таймаут. Обычно в каждом конкретном случае можно выбрать из этих двух вариантов.
Чорт! Как я про таймаут не подумал то... действительно, спасибо за наводку. Поставил для начала 10 мс, будем наблюдать что из этого выйдет.