Обработка прерываний
- Войдите на сайт для отправки комментариев
Чт, 14/02/2013 - 06:45
Доброго времени суток.
Изучаю обработку прерываний Arduino и наткнулся на некоторые интересные эффекты. Плата - Spider Dagu, клон Mega, но с разъемами для сервоприводов, чип AVR Mega 1280. Для прерывания ипользую кнопку на порту D2, соответствующую interrupt(0).
1. Пытаюсь бороться с дребезгом кнопки при прерывании. Процедура, вызываемая по прерыванию:
void mov(){ detachInterrupt(0); delay(2000); Serial.println("interrupt"); attachInterrupt(0, mov, FALLING); }
двухсекундная задержка установлена для наглядности. проблема в том, что внутри этой процедуры delay не работает. с чем это связано?
2. Если прерывание возникает в момент вывода данных в serial, контроллер виснет наглухо. как с этим бороться?
Не внимательно читаете (или не читаете) описания функций, attachInterrupt() - где написано:
Замечание по использованию
Внутри функции обработки прерывания не работает delay(), значения возвращаемые millis() не изменяются. Возможна потеря данный передаваемых по последовательному соединению (Serial data) в момент выполнения функциии обработки прерывания. Переменные, изменяемые в функции, должным быть объявлены как volatile.
Блин, этож надо так! Одним шагом на две грабли из трех!
А какие в этом случае есть приемы ввода точной задержки и борьбы с дребезгом? запуск свободного таймера или аасемблерный цикл с "nop"?
А какие в этом случае есть приемы ввода точной задержки и борьбы с дребезгом? запуск свободного таймера или аасемблерный цикл с "nop"?
Необходимо стремиться "задерживать" вне обработчика прерывания.
Ибо пока вы находитесь в одном обработчике прерывания, другие прерывания не могут выполняться. Ждут выхода из текущего обработчика прерывания. В результате запаздывают с исполнением, а то и вовсе пропускаются.
Согласен, но другого способа бороться с дребезгом кнопки, вызывающей прерывание, я пока не вижу... понятно, что опрашивать кнопки правильнее в loop(), либо бороться с этим явлением на уровне схемы, но в качестве учебной задачи это было бы интересно.
В ISR устанавливаем флаг: FALLINGFRONT=1 (и больше ничего не делаем)
в loop при каждом проходе проверяем:
Хотя нет - при таком варианте будем реагировать как на дребезг при отпускании кнопки, так и на дребезг при ее нажатии. Ниспадающие фронты и там и там есть.
loop-часть следует сделать так:
alexxkr, используйте флаг в прерывании а обнулять его будете в loop. Только не забудьте объявить флаг как volatile
В ISR устанавливаем флаг: FALLINGFRONT=1 (и больше ничего не делаем)
по этой теме надо выкурить соответствующий мануал, ибо сейчас даже не понял, о чем речь. ну нуб я :)
alexxkr, используйте флаг в прерывании а обнулять его будете в loop. Только не забудьте объявить флаг как volatile
а зачем? ведь как я понял, в любом случае прерывания не срабатывают внутри функции прерывания, а значит мы все равно вернемся в loop() и сбросим флаг?
а теперь тупой вопрос. внутри процедуры прерывания случайно нет ограничения на использование do..while?
а то при включении в процедуру кода с этим циклом плата на прерывании виснет наглухо:
здесь X и Y объявляются глобально и вычисляются в loop():
эта процедура должна перемещать ногу на трех сервах из исходной точки с координатами (X,Y) в случайную (xf, yf)
процедура leg, собственно, и занимается перемещением ноги , работает корректно и из loop() вызывается без проблем.
В ISR устанавливаем флаг: FALLINGFRONT=1 (и больше ничего не делаем)
по этой теме надо выкурить соответствующий мануал, ибо сейчас даже не понял, о чем речь. ну нуб я :)
alexxkr, используйте флаг в прерывании а обнулять его будете в loop. Только не забудьте объявить флаг как volatile
а зачем? ведь как я понял, в любом случае прерывания не срабатывают внутри функции прерывания, а значит мы все равно вернемся в loop() и сбросим флаг?
ISR - это Interrupt Service Routine или обработчик прерывания по-русски. В вашем случае - это та функция, имя которой вы указали в операторе инициализации прерывания в setup'е. то есть mov.
И я, и nestandart говорим о переменной-флаге, а не об аппаратном флаге, который - действительно - предотвращает запуск обработки новых прерываний, если не завершилась обработка текущего прерывания. моя переменная-флаг - это FALLINGFRONT. Вы устанавливаете ее (его) в 1, чтобы основная программа могла узнать, что вызывалось ваше прерывание. Тогда в loop-е вы можете проверить (программный) флаг и - если он взведен - выполнить необходимы е действия ВНЕ ISR, то есть не внося неразберихи в систему обработки прерываний.
а теперь тупой вопрос. внутри процедуры прерывания случайно нет ограничения на использование do..while?
жесткого ограничения нет, но к чему приводит медлительность в ISR, вы раз за разом убеждаетесь.
Спасибо за пояснение по поводу ISR.
Мысль по поводу программного флага от netstandart я так и понял. А вот теперь, похоже, дошло, что при достаточно длительной процедуре, выполняемой по флагу, можно не бояться дребезга кнопки на прерывании.
а по поводу кода процедуры есть мысли? что там может быть такого криминального, что ложит плату?
а по поводу кода процедуры есть мысли? что там может быть такого криминального, что ложит плату?
Вы можете сказать, сколько миллисекунд занимает выполнение тех операций, которые вы напихали в функцию mov() (т.е.в ISR)?
процедура leg, собственно, и занимается перемещением ноги , работает корректно и из loop() вызывается без проблем.
А, собственно, где вы привели код функции leg()?
задержка на выполнение тупого кода получается на глаз меньше полсекунды, заметно по остановке ноги.
а что, есть ограничение на время выполнения ISR?
тут привожу весь скетч. без прерывания он вращает ногой по кругу. отладочные участки кода не вычищал, выкладываю последнюю версию.
исходя из того, что ногой все-таки он крутит как надо, думаю leg написан более-менее сносно.
т.е. leg() это не то, что стоит в mov(). Уже хорошо. Причина зацикливания в mov() (и подвисания микроконтроллера) в том, что моделируемый в do {} while() процесс является расходящимся при том условии его окончания, которое вы прописали. Оперируя реалиями сегодняшнего дня, у вас получилась модель того астероида, который пройдет сегодня в 23 часа с копейками в 27000 километров от Земли. А должен получиться тот камень, который грохнулся в Челябинске...
Если вы вынесете код, используемый в mov(), в обычную функцию и поиграетесь различными граничными условиями, то можете - как и я - выяснить, что минимальное условие, при котором ваш цикл начинает завершаться, это "dx>6". Это, так сказать, тот минимальный радиус вашей "Земли" при котором тело попадает-таки в нее (по крайней мере, при моих начальных координатах X и Y - 1 и что-то около полутора)
за ошибку в алгоритме - спасибо, буду разбираться.
только всвязи с этим возникает другой вопрос.
немного раньше у меня вместо всего кода процедуры была заглушка с выводом в Serial слова "interrupt" для визуального контроля прерывания. оно выводилось по 1-3 раза. отсюда началсь борьба с дребезгом.
дальше появился этот цикл do..while, в нем был вывод значений координат. после этого я не видел на первого "interrupt", ни хоть какого-то вывода изнутри цикла. это явление мне уже непонятно...
потом где-то на этом форуме я увидел информацию, что Serial.print() с прерываниями несовместим и я его на всякий случай удалил, хоть и не помогло.
p.s. опыты с переносом кода в тело loop() смогу продолжить только в понедельник. к сожалению.
спасибо, алгоритм действительно был кривой. перенес в loop() и допилил.
В симуляторе код работает идеально
По факту одновременно можно получить
Иринка, пишете яснее. В окне симулятора видно, что там точно так же выводится "Нет клюитча" :)
Так чего нужно от скетча и в чем проблема?
Дребезг контактов у нее и залетные на пин помехи.
Нет ключа -- на 2 пине ардуино 1
Есть ключ -- на 2 пине ардуино 0
Нет ключа -- на 2 пине ардуино 1
Переход с 0 на 1 (извлечение ключа) контролирую функцией
attachInterrupt(0, cliuch, RISING);
Всё подключила, вставляю ключ, извлекаю ключ и раз через раз в порт вмето одной записи
Net cliucha
могу получить по две записи
Net cliucha
Net cliucha
Т.е. функция cliuch срабатывает неодин раз.
Иринка, слушайте sadman41
То, что дребезг контактов, это я поняла, поставила конденсатор, но не считаю это правильным вариантом
То, что дребезг контактов, это я поняла, поставила конденсатор, но не считаю это правильным вариантом
погуглите "антидребезг" - вы смышленая. думаю сама справитесь :)
Конденсатор тоже не считает существование кислородной жизни правильным вариантом....
Поставьте триггер Шмитта, сделайте санационную задержку, откажитесь от прерываний - всё в ваших руках.
Спасибо
загнать в прерывание работу с String, да еще от туда позвать функцию, да еще в которорой работа с Serial ....
в прерывание выставить флаг, остальная обработка в loop...
мне так каааца :))
delay(2000);
Serial
.println(
"interrupt"
);
Тут все подробно описано почему не работают в прерывании http://robotosha.ru/arduino/arduino-interrupts.html
xDriver верно предложил реализовать.
Спасибо. Прочитала. Поняла.