Вопрос по прерываниям
- Войдите на сайт для отправки комментариев
Сб, 06/02/2016 - 21:33
Подаю сигнал на INT0. Настраиваю прерывание на фронт импульса - все работает.
EIMSK = (1<<INT0); EICRA=(1<<ISC01);
Подаю сигнал на INT1. Настраиваю прерывание на фронт импульса - все работает.
EIMSK = (1<<INT1); EICRA=(1<<ISC11);
Вопрос. Как настроить прерывание INT0 по фронту, а INT1 по спаду импульса. При этом INT0 и INT1 соединены между собой. Что прописать в регистр EICRA?
EIMSK = (1<<INT0) | (1<<INT1);// разрешение прерываний INT0 и INT1
Опять вы что-то мудрите :) Один бит ICS01 -это спад импульса. Что бы был подъём нужны оба бита. Вот всё вместе:
EICRA=(1<<ICS01)|(1<<ICS00)|(1<<ICS11);
EIMSK=(1<<INT1)|(1<<INT0);
Спасибо.
Необходимо измерить скважность прямоугольных импульсов. Входную частоту подаем на входы INT0 и INT1. INT0 настроен на срабатывание по фронту импульса. INT1 настроен на срабатывание по спаду импульса. Таймер 1 считает количество тактовых импульсов генератора до значения 4000, а затем сбрасывается и считается количество переполнений. По фронту импульса мы считаем значение переменной : t_start. По спаду импульса мы считаем значение переменной : t_stop. В переменной : t_imp - мы получаем значение суммарного времени длительности импульса. Зная t_imp и длительность импульса + длительность паузы мы можем найти скважность.
Переодически длительность импульса t_imp. становится на значение кратное 4000 больше. Вероятно это связано с тем, что приоритет внешних прерываний выше, чем приорител таймера 1. Допустим сработало INT1 , а после этого прерывание по таймеру. В прерывании INT1 мы считываем значение количества переполнений таймера 1, но поскольку переполнение таймера 1 наступило, а прерывание еще нет - мы теряем 1 импульс переполнения таймера 1.
Как можно обойти данную ситуацию?
Дальше вопрос по прерываниям.
Допустим я подаю внешний сигнал на INT0 как прерывание с самым высоким приоритетом. Если никакого прерывания в этот момент не исполняется то мы переходим сразу к выполнению INT0. Если выполняется другое прерывание, то INT0 начнет выполняться только после завершения текущего прерывания.
Как мне сделать так, чтобы прерывание по INT0 выполнялось только при отсутствии выполнения в данный момент другого прерывания? А если выполняется другое прерывание (например прерывание от таймера 0), то игнорировать прерывание INT0? Есть ли какой нибудь флаг для этих целей?
Вроде ж у AVR нет приоритета прерываний? (ошибся, приоритет есть у ожидающих в очереди прерываний). Если во время срабатывания прерывания уже обрабатывается другое прерывание - только выставляется флаг сработавшего прерывания и оно ждёт, пока не завершится первое. И уже потом обработается второе, после чего флаг сбросится. То есть, в порядке очереди.
UPD: А, понял. Вы хотите, чтобы прерывание INT0 вообще не обрабатывалось, даже после завершения другого прерывания. Тогда вариант: в конце обработчика уже выполняющегося прерывания проверять флаг прерывания INT0. И если он выставлен - сбрасывать его.
Вроде ж у AVR нет приоритета прерываний? (ошибся, приоритет есть у ожидающих в очереди прерываний). Если во время срабатывания прерывания уже обрабатывается другое прерывание - только выставляется флаг сработавшего прерывания и оно ждёт, пока не завершится первое. И уже потом обработается второе, после чего флаг сбросится. То есть, в порядке очереди.
UPD: А, понял. Вы хотите, чтобы прерывание INT0 вообще не обрабатывалось, даже после завершения другого прерывания. Тогда вариант: в конце обработчика уже выполняющегося прерывания проверять флаг прерывания INT0. И если он выставлен - сбрасывать его.
спасибо за ответ.
Да я имел ввиду именно очерередь в ожидании.
У меня немного другой случай. У меня INT0 вызывается приходом внешнего сигнала. (Если сейчас никакого другого прерывания не выполняется). Если другое прерывание уже выполняется - то прерывание по INT0 не должно обрабатываться. Доступа к текущему прерыванию у меня нет.(например:текущее прерывание по таймеру 0 который считает время. И остановить Таймер 0 мне не нужно.)
Мне надо в обработчик прерываний INT0 вставить проверку, что прерывание по таймеру 0 (в момент подачи сигнала на INT0) в данный момент не выполняется.
Или я чего-то не пойму, или лыжи не едут... У Вас же есть обработчик прерывания от таймера? Почему Вы не хотите в нём проверять и сбрасывать флаг INTF0?
Доступа к текущему прерыванию у меня нет.(например:текущее прерывание по таймеру 0 который считает время. И остановить Таймер 0 мне не нужно.)
В смысле нет доступа? Обработчик прерывания таймера есть, в котором выполняется некий код. В нём и делайте проверку в самом конце, ничего останавливать не нужно.
Вот такой код пока имею. У меня прерывание по INT0 иногда срабатывает на 10 тактов позднее или раньше чем надо. Есть подозрение что переход на прерывание INT0 задерживается из за выполнения какого нибудь другого прерывания.
Вот такой код пока имею. У меня прерывание по INT0 иногда срабатывает на 10 тактов позднее или раньше чем надо.
Ну позднее понятно - ждёт очереди, если выполняется другое прерывание (от таймера). А как оно может быть раньше?
Есть подозрение что переход на прерывание INT0 задерживается из за выполнения какого нибудь другого прерывания.
Ну у Вас только от таймера другое прерывание, больше ведь нет.
Вот в обработчик прерывания от таймера добавил проверку флага прерывания INT0. Должно быть как Вы и хотели: в самом конце обработчика таймера проверяется, не пришло ли прерывание по INT0. Если пришло - то флаг сбрасывается, соответственно после выхода из обработчика таймера - МК не должен будет перейти в обработчик INT0.
Serial тоже на прерываниях, насколько я знаю, и millis() скорее всего не без этого. И чего там в lcd. надо посмотреть.
Прерываний до хрена может быть. Мне кажется, подход надо другой, если задержки не избежать, то данные фильтровать надо. Мне лень код сейчас писать, но что-то типа медианного фильтра. Если автору известно, что прерывание запоздало на 10 тактов, то легко отбросить данные которые не вписываются в предсказаные.
Всем спасибо попробую , что получится.
По поводу того, что прерывание приходит раньше или позже. У меня фронт и спад количества импульсов приходит на INT0. Если прерывание попадает на фронт импульса - то длительность уменьшается на время выполнения выхода из прерывания (обычно 10 тактов). Если попадает на спад импульса - то длительность увеличивается.
По поводу фильтрации это отдельная тема. В том то и дело, что я не знаю насколько тактов произойдет запаздывание. Обычно это от 2 до 10 тактов каждое десятое измерение. Но бывает и запаздывание на 100 тактов примерно раз в минуту.
Предсказания не нужно, это не как у мп3. Я не правильно обрисовал, медианный фильтр работает по мажоритарной системе, те значения которых больше всего- правильные. Остальные можно отбросить. Логика простая, если значения все одинаковые, то выбросив 50% ничего не изменится, а вот если в тех 50% отбрасываемых будут сильно крывые данные, то они не смогут испортить последующее усреднение результата.
http://learn.linksprite.com/programming-languages/c/median-filtering-method-for-pcduinoarduino-2/
Предсказания не нужно, это не как у мп3. Я не правильно обрисовал, медианный фильтр работает по мажоритарной системе, те значения которых больше всего- правильные. Остальные можно отбросить. Логика простая, если значения все одинаковые, то выбросив 50% ничего не изменится, а вот если в тех 50% отбрасываемых будут сильно крывые данные, то они не смогут испортить последующее усреднение результата.
http://learn.linksprite.com/programming-languages/c/median-filtering-method-for-pcduinoarduino-2/
Этот вариант пока не прокатит. Допустим у меня сейчас есть частота 20.004123 гц. Поскольку я подаю ее с кварца. И для этого случая я могу применить фильтр. Теперь представим, что у меня не кварц а ГУН. и мне надо поймать секундное изменение частоты между 20.004123 и 20.004122. В данном случае ваш метод не подходит.
Поменял код.
Данные частоты которые были до исправления кода.
f =20.004123 Hz
f =20.004138 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004127 Hz
f =20.004119 Hz
f =20.004123 Hz
f =20.004117 Hz
f =20.004119 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004133 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004081 Hz
f =20.004024 Hz
f =20.004127 Hz
f =20.004121 Hz
f =20.004119 Hz
f =20.004121 Hz
f =20.004129 Hz
f =20.004123 Hz
f =20.004123 Hz
После добавления кода.
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004129 Hz
f =20.004133 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004127 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004131 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004137 Hz
f =20.004129 Hz
f =20.004123 Hz
f =20.004133 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004123 Hz
f =20.004114 Hz
f =20.004123 Hz
f =20.004129 Hz
Результат стал лучше но все равно есть выбросы.
Для точного измерения не надо было связываться с прерываниями вообще. Делается в хардваре, через инпут каптюре (ICP). Есть библиотека здесь. http://interface.khm.de/index.php/lab/interfaces-advanced/frequency-measurement-library/
Для точного измерения не надо было связываться с прерываниями вообще. Делается в хардваре, через инпут каптюре (ICP). Есть библиотека здесь. http://interface.khm.de/index.php/lab/interfaces-advanced/frequency-measurement-library/
По данной библиотеке результат гораздо хуже моего. (Смотря по вашей ссылке рис COM 43 порта) При частоте 100 гц Точность измерения составляет 1 такт от 160000. У меня порядка 1 такта на 1600000. По крайней мере у меня в 10 раз лучше.
Есть подозрение что переход на прерывание INT0 задерживается из за выполнения какого нибудь другого прерывания.
Конечно. Таймер0 отключали? Он строчит прерывания каждые 4 µS для всяких миллисов и микросов
Конечно. Таймер0 отключали? Он строчит прерывания каждые 4 µS для всяких миллисов и микросов
Думаю что ошибку исправил. Потестирую.
У меня был код:
Заменил его на такой код:
Все заработало.
Никакой таймер 0 при этом не отключал. Вероятнее всего это было из за того, что вызывая
я обращался к Таймеру 0 в цикле Loop. Убрал это обращение и все заработало. Сейчас точность плюс - минус 2 такта от 16000000.
Возможно ли неисправность была была вызвана этим?
ovf_tic1=16796534 , tik_int_0 =21 n. f =20.004127 Hz
ovf_tic1=16796533 , tik_int_0 =21 n. f =20.004129 Hz
ovf_tic1=16796531 , tik_int_0 =21 n. f =20.004129 Hz
ovf_tic1=16796534 , tik_int_0 =21 n. f =20.004127 Hz
ovf_tic1=16796533 , tik_int_0 =21 n. f =20.004129 Hz
ovf_tic1=16796535 , tik_int_0 =21 n. f =20.004123 Hz
ovf_tic1=16796534 , tik_int_0 =21 n. f =20.004127 Hz
ovf_tic1=16796535 , tik_int_0 =21 n. f =20.004123 Hz
ovf_tic1=16796532 , tik_int_0 =21 n. f =20.004129 Hz
ovf_tic1=16796533 , tik_int_0 =21 n. f =20.004129 Hz
ovf_tic1=16796533 , tik_int_0 =21 n. f =20.004129 Hz
ovf_tic1=16796535 , tik_int_0 =21 n. f =20.004123 Hz
ovf_tic1=16796534 , tik_int_0 =21 n. f =20.004127 Hz
ovf_tic1=16796532 , tik_int_0 =21 n. f =20.004129 Hz
ovf_tic1=16796532 , tik_int_0 =21 n. f =20.004129 Hz
ovf_tic1=16796534 , tik_int_0 =21 n. f =20.004127 Hz
ovf_tic1=16796533 , tik_int_0 =21 n. f =20.004129 Hz
ovf_tic1=16796533 , tik_int_0 =21 n. f =20.004129 Hz
Привет всем.
Подскажите,пожалуйста,можно ли подключать два прерывания на один пин - одно по спаду импульса, другое- по фронту, например:
attachInterrupt (0,start,FALLING);
attachInterrupt (0,stop,RISING);
Заранее благодарю за ответы.
Привет всем.
Подскажите,пожалуйста,можно ли подключать два прерывания на один пин - одно по спаду импульса, другое- по фронту, например:
attachInterrupt (0,start,FALLING);
attachInterrupt (0,stop,RISING);
Заранее благодарю за ответы.
Ответ кроется в исходниках attachInterrupt:
Если по исходникам неясно, то дополню: ответ на поставленный вопрос - нет.
attachInterrupt (0,start,FALLING);
attachInterrupt (0,stop,RISING);
Если длительность пульса не слишком короткая, и частота не супер, то поставив прерывание на CHANGE, потом внутри самой функции можно проверить уровень пина, высокий - был фронт, низкий - спад.
Два _обработчика_ одного прерывания на одном пине (по разным фронтам сигнала) подключаются так
если вы успеваете между струйками дождя (выполнить работу до смены фронта сигнала).
Спасибо большое за советы! Я после первого ответа долго раздумывал и решил попробовать в функциях обработки каждого прерывания само прерывание отключать и включать второе, а во втором - отключать второе и включать первое. Таким образом получилось мерять длительность импульса на входе прерывания (как в последнем ответе). Так что все получилось.
Еще раз спасибо за советы и удачной вам работы!
Timur Shapoval, длительность импульса можно измерять в одном прерывании, без всех этих лишних манипуляций. Помимо того есть специальная функция pulsein() для измерения длительности импульса.
Timur Shapoval, длительность импульса можно измерять в одном прерывании, без всех этих лишних манипуляций. Помимо того есть специальная функция pulsein() для измерения длительности импульса.
Спасибо за замечание. Если честно, я с pulseln () и начал, но она надолго останавливала программу - я логировал каждый шаг печатью, и так и не смог её победить. Поэтому решил попробовать прерываниями. Тем более, у меня заранее не известно, когда прилетит импульс, и сколько будет длиться (импульс бензинового впрыска автомобиля).
Однако, если есть где почитать поподробнее о применении этой функции, или кусочек рабочего кода, буду очень признателен.