Прерывание
- Войдите на сайт для отправки комментариев
Пнд, 02/07/2012 - 18:44
Вот и я добрался до прерываний ! Объясните дураку , как в функцию прерывания засунуть таймер который считатет микросекунды с одной смены с LOW на HIGH до другой ! И вывести это время в эфир !
Смотрел много примеров ! Но от них сложновато оттолкнуться !!!(( Хотелось бы с самого начала )))
Прежде всего необходимо определиться с диапазоном, в котором будет изменяться количество подсчитываемых микросекунд:
0-16 или
10-2000 или
100-25000 или
1000-30000000 или
... ну и так далее.
А уж потом думать дальше.
Почему?
Потому что первый диапазон легко отслеживать на любом таймере с минимальными затратами, второй и третий - тоже на любом, но требуется чуть-чуть подумать (рассчитать необходимые коэффициенты). Четвертый реализуем только на таймере1 (если без извратов).
... ну и так далее.
Допустим обработка сигнала !!! он в диапазоне от 10 до 2000 ..???
Заводите две глобальные переменные (не забываем про модификатор volatile). Что-то типа raiseTime и prevRaiseTime.
В обработчике
В loop()
Проверяем, если raiseTime больше нуля и prevRaiseTime больше нуля (значит прерывание вызвалось минимум два раза). Выводим разницу raiseTime-prevRaiseTime и обнуляем их.
Следующий выводе произойдет когда опять прийдут "два тика". То есть выведется время межну "первым и вторым, третим и четвертым, пятым и шестым".
Если нужно между "первым и вторым, вторым и третьим, треитим и четвертым" - обнуляем только prevRaiseTime при выводе.
Но это все будет "чуток не точно" :) Особенно на микросекундных интервалах. Повыстить точность можно используя аппаратную фичу Capture. Но тут уже "просто для новичка не получится". Либо вчитыватся в даташит в раздел таймеров и фичи Capture, либо нагуглить книгу "Arduino Cookbook" Michael Margolis. Издательство O'REILYY Глава 18.8 "Measuring Pulses More Accurately"
Ну вы-бы хоть пару слов добавили к коду, что это "пример который заработал", пример который не заработал? Если есть проблемы, то "в чем проявляются".
Не беглый взгляд выглядить как вполне грамотная реализация кодом того что я описал словами.
Кроме одного "но" (хотя возможно вы этого и хотели): в строке 7-мь. Нужно не на CHANGE вешатся, а на RISING раз вы хотели "" с одной смены с LOW на HIGH до другой". CHANGE будет дергать обратботчик при любом изменении и LOW на HIGH, и с HIGH на LOW. То есть вы, фактически, начнете замерять длину самого импульса. Или паузу между импульсами, в зависимости от состояния в момент старта.
Не зная вашей схемы трудно сказать однозначно, но возможно нужна еще подтяжка. Если в каком-то ситуации ваш пин "никуда не подключен" просто висит в воздухе - он будет ловить случайный мусор из эфира. При абсолютно верном скетче.
Ну, еще, из второспенного: Я бы использовал не print, а println (иначе все же сольется в сериал мониторе). Ну и условие в строке 14 можно короче записать: if(prevRaiseTime & raiseTime)
В C/C++ любое значение переменной отличное от нуля воспринимается как "истина", поэтому сравнение с нулем - можно опустить (или оставить, по собственному вкусу. как лично вам код более понятным-красивым кажется)
Код поправил ! Но все равно в Сериал ни чего не идет ((
Ну еще можно & (битовый оператор) заменить на && (логический оператор). По идее тут и "битовый должен прокатить", но лучне не превыкать их путать.
ну а дальше - уже на подключение смотреть.
Например есть сильное подозрение что вы все это дело подключили на третий цифровой пин.
Почитайте http://arduino.ru/Reference/AttachInterrupt какой пин соотвествует нулевому прерыванию.
Почему происходит зависание программы при отправке символа "z" в порт?
Если строку 09 закомметировать, то все работает.
Это скетч абстрактный, написан для описания проблемы. В реале столкнулся с проблемой записи данных в порт, получаемых в обработчике прерывания
А реальный скетч не можете представить?
Прерывание INT0, к которому вы цепляете обработчик, "слушает" пин PD2 (или 2 в терминах Arduino). Этот же пин вы определяете как выход. Непоследовательно как-то...
Прерывание 0 слушает пин 2, так? Определив его как выход, я программно меняю его состояние на HIGH командой digitalWrite, что вызывает вызов обработчика. Чего тут непоследовательного? Реальный скетч картины не изменит. Прошу пояснить именно указанную проблему. Возможно, разобраться поможет еще тот факт, что добавление задержки в loop делает скетч работоспособным...
>Прерывание 0 слушает пин 2, так
А зачем же, тогда вы второй пин на OUTPUT включили?
Ну и прочитайте документацию на фунцию attachInterrupt внимательно. Особенно выделенный раздел "Замечание по использованию". Одно из двух "нельзя", вы все-таки сделали.
Когда начинает выполняться обработчик прерывания (любой) глобальные прерывания (все прерывания) временно запрещаются. Как только он отработает прерывания разрешаются опять. Для выполнения Serial.println("INT") нужны разрешенные глобальные прерываня, а они как раз запрещены так как выполняется обработчик прерывания. Поэтому программа зависает как только начинает выполняться обработчик. Вобщем Serial.print использовать в обработчике прерывания нельзя.
Кстати, не знаю, переключает-ли, внутри себя, attachInterrupt пин на вход. Но если не переключает, то в зависимости от схемы подключения, можно выпалить ногу, или весь камень. Если вы пину включенному на выход, начнете подавать импульсы без ограничения по току.
А вообще, как-то диже странно вы пользуете второй пин. Вы все-таки решите вы хотите его "как вход" или "как выход".
Если цель была "потестировать", то сделай второй на Input, а, к примеру пятый, на Output. Соедините эти два пина проводком (но после того как зальете скетч) и делайте свой digitalWrite(5,HIGH)
Вобщем Serial.print использовать в обработчике прерывания нельзя.
Вы не поверите, но именно это и написанно в документации :)
Просто хотелось что-бы человек сам нашел-прочитал. Глядишь и еще чего полезного узнает. Например про volatile. Оно тоже пригодится.
Понятно, спасибо. Но откровенно говоря, не могу понять, как же работает пример по приведенной ссылке:
Здесь используется прерывание 0, которое слушает пин 2. А где в программе вообще фигурирует этот пин...Тут ведь в 13-й пин digitalWrite идет...И еще. А почему здесь такая же логика - digitalWrite в пин, настроенным как OUTPUT, а вроде как все верно и никто не грозит сожжением камня? Простите за возможную наивность, но все мы же в любом случае были новичками и задавали неудобные вопросы :)
Понятно, спасибо. Но откровенно говоря, не могу понять, как же работает пример по приведенной ссылке:
[...]
Здесь используется прерывание 0, которое слушает пин 2. А где в программе вообще фигурирует этот пин..
Этот пин "фигурирует" не в программе, а в железе. Прерывание INT0 жестко связано с выводом PD2 микроконтроллера. Все, что вы можете сделать - либо использовать этот вывод в качестве обычного ввода/вывода, запретив (не инициализировав) прерывание INT0, либо написать обработчик этого прерывания, разрешить это прерывание и - слушать, слушать, слушать изменения сигналов на выводе PD2...
Есть еще третий вариант использования этой ноги, но о нем лучше пока не заикаться.
Хорошо. Где в приведенной программе происходит изменение состояния PD2? Вернее, в "железе"? Что здесь меняет состояние PD2?
Вот тот скетч, который не работает:
Задача - опрашивать датчик акселерометра с определенной частотой. Опрос реализуется в обработчике по таймеру. Программа виснет уже на выводе первого сообщения в порт (Initializing)
В программе не происходит изменение состояния PD2, это делает подключенная к этой ноге кнопка :) Любой пример состоит из программной и железной части, вторую, кажется, Вы проигнорировали.
В программе не происходит изменение состояния PD2, это делает подключенная к этой ноге кнопка :) Любой пример состоит из программной и железной части, вторую, кажется, Вы проигнорировали.
Спасибо, да, так и есть. А разве в этом случае не должно стоять инструкции pinMode(2, INPUT)?
Все входы по умолчанию настроены на вход. Поэтому эта инструкция излишна.
1) А вы можете в ручном режиме что-нибудь от акселерометра получить?
2) Сообщение "Testing device connections..." вы уже не получаете?
1) и 2) - да
Появляются буквы Ini.....и привет
1) А вы можете в ручном режиме что-нибудь от акселерометра получить?
2) Сообщение "Testing device connections..." вы уже не получаете?
Это вы о чем? Мы тут про прерывание... Если сообщение было давно, то хоть цитируйте...
1) А вы можете в ручном режиме что-нибудь от акселерометра получить?
2) Сообщение "Testing device connections..." вы уже не получаете?
Это вы о чем? Мы тут про прерывание... Если сообщение было давно, то хоть цитируйте...
Да о нем и речь..пост #17 посмотрите
Да о нем и речь..пост #17 посмотрите
А, понял. Здесь явно конфликт библиотек accel и serial - они один и тот же таймер используют. Иначе говоря, нужно обязательно дождаться окончания передачи прежде чем вызывать инициализацию. Или поменять их местами. Serial.Print просто запихивает данные в буфер передачи, то есть передача происходит асинхронно - в фоне. И вызов функции приема данных из прерывания может не прокатить... Лучше устанавливать флаг, а данные опрашивать в основном цикле.
Да о нем и речь..пост #17 посмотрите
А, понял. Здесь явно конфликт библиотек accel и serial - они один и тот же таймер используют. Иначе говоря, нужно обязательно дождаться окончания передачи прежде чем вызывать инициализацию. Или поменять их местами. Serial.Print просто запихивает данные в буфер передачи, то есть передача происходит асинхронно - в фоне. И вызов функции приема данных из прерывания может не прокатить... Лучше устанавливать флаг, а данные опрашивать в основном цикле.
Да о нем и речь..пост #17 посмотрите
А, понял. Здесь явно конфликт библиотек accel и serial - они один и тот же таймер используют. Иначе говоря, нужно обязательно дождаться окончания передачи прежде чем вызывать инициализацию. Или поменять их местами. Serial.Print просто запихивает данные в буфер передачи, то есть передача происходит асинхронно - в фоне. И вызов функции приема данных из прерывания может не прокатить... Лучше устанавливать флаг, а данные опрашивать в основном цикле.
Да о нем и речь..пост #17 посмотрите
А, понял. Здесь явно конфликт библиотек accel и serial - они один и тот же таймер используют. Иначе говоря, нужно обязательно дождаться окончания передачи прежде чем вызывать инициализацию. Или поменять их местами. Serial.Print просто запихивает данные в буфер передачи, то есть передача происходит асинхронно - в фоне. И вызов функции приема данных из прерывания может не прокатить... Лучше устанавливать флаг, а данные опрашивать в основном цикле.
Извините, канал глючил :(
у меня вот такой сигнал :
на осциле с антены ! подключаю к ардуине ну не как она не хочет принимать сигнал ( 11000 ) (((
Подскажите начинающему через какие процедуры можно arduino адаптировать к моей антене !\
Частота аля Rfid 125Khz. логический 0 длится от 140 до 180 мкс . Единица от 200 до 260 мкс.
Есть код написанный для парктроника, на для твоей частоты возможно его нужно будет корректировать и оптимизировать
В м чем ошибка :
2Marchcat : а можно поинтересоваться что за устройство вы собираете? Что оно должно делать?
оно должно логировать обмен данных ! для проверки правильности работы !!!
2leshak Можно както с вами связаться ( icq , skype. )
Диклаймер: все что будет ниже - сугубо мои домыслы. Просьба не обижатся если я "попал пальцем в небо".
Я понял что "оно должно логгировать". Вопрос был "что за устройство?". Какова область применения?
Выражусь по другому: у меня сложилось впечатление что речь идет о каком-то снифере автосигнализаций или работе с ключами для pegeot 308 и 4008 (машине примерно 4-ре месяца ;)
Если мое впечателние не ложное, то, даже если ваши помыслы "кристально чисты" и все это не более чем "исследовательский зуд" или вполне легальная работа с собственным автомобилем, не хотелось-бы что-бы подобные темы/контент были на этом сайте.
Сами понимаете - слишком уж велик соблазн, для неокрепших умов, начать изучение микроконтроллеров именно с этого подраздела :)
А есть еще и "другие умы".... из противоположного лагеря. И их внимание - тоже не особо нужно.
>2leshak Можно както с вами связаться ( icq , skype. )
Можете написать сюда
Но, к сведению:
2Leshak я ват отправил письмо !!!
Даже не знаю как сформулировать...
В общем, при нажатии кнопки или срабатывании энкодера в обработчике прерывания выставляется соответствующий флаг (какая кнопка нажата или в какую сторону повернут энкодер). Все, больше в этом обработчике ничего нет.
А вот дальше этот флаг надо немедленно передать в функцию X, которая что-то там делает - выводит нужное меню или выполняет действие, назначенное на кнопку.
Но ведь при завершении прерывания работа программы продолжается с того места, где было прерывание. И по loop до этой функции X когда еще доберемся - там и чтение десятка датчиков и прочее - задержка может быть до 2-х секунд.
А вызов этой функции прямо из обработчика будет являться неправильным, ведь пока функция не выполнится, прерывание будет считаться незавершенным, так?
Как можно по завершении прерывания максимально быстро передать управление функции X, а уж потом продолжить loop?
Ребят, помогите с проблемой. Выполняется прерывание по 3 pin через кнопку (с обвязкой через резистор). Как только в программе срабатывает реле(на 220В прибор включен) или в других розетках (параллельных на 220) вкл/выкл прибор выполняется прерываение без помощи кнопки. Почему? Заранее благодарен!
Кондёрчик 10 -100 нан повесьте на 3 пин... Не поможет- резистор привязки на 1 килоом поставьте...
Подскажите пожалуйста. Работаю с прерыванием. Функция delay() в основной прграме перестает работать. Что делать, как организовать контролируемые задержки в програме. Я уже и такое чудо пробовал while((millis() - oldTime)<=1000) {} так милис тоже не работает. И вообщем получается чтоб пользоваться этими функциями необходимо отключать прерывание функцией detachInterrupt(1); Или делать задержку какой то рутиной?
как организовать контролируемые задержки в програме.
никак - тебе этого не нужно будет делать, если ты поймёшь, что вместо
можно использовать
Это равносильно. Главное что милис как и дилай могут не работать когда задействованы прерывания. И это уже интересно. В каких случаях и почему? Конечно можно создать рутину, замерить ее время выполнения ардуиной а затем использовать как эталонную, но это конечно костыли. При том что прерывания тоже внесут коррекцию в скорость роботы рутины.
милис как и дилай могут не работать когда задействованы прерывания.
Кто Вам это сказал? И что Вы понимаете под выражением "задействованы прерывания"? Вы что в них безвылазно по часу сидите? Показыватке код, без кода - это болтовня в пользу бедных.
Только по возможности короткий код, который работает и демонстрирует проблему. А то тут часто проблема в каком-нибудь локальном преобразовании типа, а код как вывалят на тыщщу строк со всеми там опросами датчиков и выводами в эти ваши народные мониторинги. По возможности подготовьте короткий пример иллюстрирующий Вашу проблему.
Кто Вам это сказал?
та, это свидетели церкви Святого Цикла - фанатики.
Кто Вам это сказал? И что Вы понимаете под выражением "задействованы прерывания"? Вы что в них безвылазно по часу сидите? Показыватке код, без кода - это болтовня в пользу бедных.
Хуже не то что они вообще не работают а то что они как то странно то работают то нет, вообщем есть муха. Чтобы упростить приведу самый простой случай из того что я пробовал. Замечу у меня нет опыта в рабое с прерываниями на ардуине, так что не судите. Но не в этом суть.
Задача ставилась постоянно измерять напряжение на аналоговом входе. Поэтому додумался применить прерывания. Взял прерывание 1. И загнал на диджитал ножку 3 LOW и в инициацию прерывания тоже LOW чтоб все время срабатывала. К самой ножке ничего не подключал. Вот тривиальный скеч.
И все хороше работает, меряет напряжение и выводит на экран через секунду, пока на диджитал ножку 2 (это уже прерывание 0) не попадает сигнал от датчика Холла. Вот просто так стал крутить прибор случайно подключенный к ножке 2 и на экране все поползло как будто дилей вовсе нет. Перестает попадать сигнал, опять все хороше. Все остальные случаи просто производные от этого.
На этом форуме строго обязательно - http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii
Взял прерывание 1. И загнал на диджитал ножку 3 LOW и в инициацию прерывания тоже LOW чтоб все время срабатывала. К самой ножке ничего не подключал.
Ваша ножка работает антенной и ловит все помехи, какие мимо пролетают. Если Вы (вместо включения другой части схемы) просто поднесёте к ней палец, то тоже увидите много интересного.
Если Вам надо, чтобы она всегда была LOW, соедините её резистором в 1 килоом с землёй. Тoлько всё время срабатывать она всё равно не будет. Прерывание срабатывает при переходе из одного состояния в другое, а не "всё время".
Спасибо Евгений за замечания и советы. Нашел пример на Инте как войти в режим Free Running https://github.com/VinnieM-3/Arduino/blob/master/ADC_FreeRunning.ino. Прграма действительно работает и измеряет постоянно напряжение. Разбираюсь Пока мутновато, потому что все это как-то сложно организовано.
Когда завел на 3 ногу землю тоже все работает
Теперь сижу и думаю как лучше
delay & millis дуреют, когда не срабатывает прерывание от Timer0. Например, прерывания запрещены. А они запрещены, когда выполняется обработчик другого прерывания, если на входе мануально sei() не скажешь.