Прерывания Arduino для ввода с кнопки

У меня на печатной плате 6 кнопок, и я хотел бы использовать прерывания на всех них, но они не соответствуют прерываниям, указанным в спецификациях.

Правда ли, что вы не можете выбирать произвольные контакты для использования в качестве прерываний на платах Arduino (в частности, на Mega 2560)? Если нет, то я немного грустный - какие-нибудь прагматичные обходные пути?

Ответы (4)

Вы можете сделать то, что предложил Маженко, но все, что нужно, это диод на кнопку, чтобы сделать линию ИЛИ. Я предполагаю, что кнопки нормально открыты и связаны между землей и подтягивающим резистором. Линия OR является дополнением к отдельным линиям кнопок, которые все еще необходимо подключить к контактам процессора. Однако преимущество заключается в том, что линия OR становится низкой при нажатии любой из кнопок. Это можно использовать, чтобы разбудить процессор или вызвать прерывание, которое затем должно просмотреть другие строки, чтобы увидеть, какие кнопки действительно нажаты.

Другой способ — вообще не использовать прерывания кнопок. Просто сканируйте строки кнопок каждые несколько мс. Грубое эмпирическое правило заключается в том, что 50 мс или меньше воспринимаются пользователем-человеком как мгновенные. Другими словами, если вы нажимаете кнопку, и все, что она делает, задерживается на 50 мс, вам все равно кажется, что это происходит мгновенно.

Если цель состоит в том, чтобы сэкономить энергию, вы можете активно выполнять верхнюю сторону подтягиваний. Держите их на низком уровне большую часть времени, чтобы не было тока, даже если нажата кнопка. Включите подтяжки примерно на 10 мкс перед выборкой кнопок, затем снова выключите их. Это можно сделать с помощью короткой процедуры, когда процессор просыпается каждые 10 мс, например, когда ничего не происходит. Средняя мощность будет низкой, так как он будет включен только на несколько десятков мкс каждые несколько десятков мс.

Здоровья Олин! Да, мотивация - очевидная задержка. Когда я нажимаю кнопку, я рисую несколько пикселей на ЖК-дисплее. Пока идет перерисовка, довольно легко снова нажать кнопку и проигнорировать ее. Интересная идея с энергопотреблением!

Надеюсь, я не опоздал с этим "черным магическим" решением :)

Прежде всего, чтобы прояснить ситуацию, то, что вам нужно, возможно и несложно достичь, но все же есть хорошие новости и плохие новости. Плохая новость заключается в том, что ваш выбор не может быть полностью произвольным, а хорошая новость заключается в том, что вы можете выбрать один из дополнительных 24 контактов (те, которые отмечены PCINTx в спецификации, от PCINT0 до PCINT23).

Плохая новость заключается в том, что поначалу кое-что из следующего может показаться немного туманным (дело в том, что вы не так уж экспериментировали с микроконтроллерами), но хорошая новость заключается в том, что вы будете иметь гораздо лучшее представление о том, с чем имеете дело. как только вы закончите работу :)

Несколько основ по этому вопросу, которые вы, вероятно, уже знаете или слышали: PCINTx означает «INterrupt по изменению вывода», и если он включен, на определенном выводе будет вызываться прерывание каждый раз, когда состояние на этом выводе изменяется (от высокого к низкому/от низкого к высокому).

Во-вторых, ваш подход должен выглядеть примерно так:

  1. включить прерывание смены контакта на 6 выводах, которые вам нужны
  2. включить глобальные прерывания
  3. когда вызывается прерывание, проверьте состояние вашего входа, чтобы определить изменение и сохранить состояние кнопки

Вам понадобится таблица данных, так что вот ярлык: http://www.atmel.com/dyn/resources/prod_documents/doc2549.PDF :)

для шага 1: см. регистр PCICR на стр. 115. Это регистр управления прерыванием смены контакта, а также регистры PCMSK2, PCMSK1, PCMSK0, чтобы точно указать, какие контакты включены для этой специальной функции.

для шага 2: я уверен, что вы знаете, как это сделать, так как вы разместили этот вопрос :) - если не вызовите: sei()

для шага 3: Это сложная часть. У вас есть 3 вектора прерывания (или вы можете назвать их обратными вызовами) по одному для каждого порта (каждый порт имеет 8 контактов). Если несколько выводов sam-порта установлены как триггеры (из регистров маски PCMSKx на шаге 1), будет вызван один и тот же обратный вызов, поэтому обязательно проверьте регистр PINx, чтобы точно увидеть, какой из них изменился.

Вот и все :) еще кое-что: это также применимо для ArduinoUno (atMega328p). Это очень полезная функция — если учесть энергопотребление, то можно удерживать контроллер в спящем режиме и выполнять пробуждение по прерыванию. Я использовал эту функцию для чтения входных данных с RC-приемника, и вы можете получить действительно хорошие тайминги (управляемые прерываниями, так что черт возьми: P)

Вот ссылка с БОЛЬШОЙ ИНФОРМАЦИЕЙ по этому вопросу, вероятно, нужно было начать отсюда: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=71109

Я сам всегда предпочитаю программное решение вместо аппаратного решения, оно обычно более гибкое, и в большинстве случаев предоставляемые результаты дешевле и быстрее, чем аппаратные изменения (также менее грязные) :). Но имейте в виду, что все, что является аппаратным, НАМНОГО НАМНОГО быстрее (таким образом оправдывает затраты, беспорядок и отсутствие гибкости). Однако в данном случае я не думаю, что вам нужна такая скорость, так что выбирайте SW :)

Надеюсь, я не опоздал, но на всякий случай надеюсь, что это будет полезно, может быть, в другой день :) Вы можете найти хорошую реализацию того, что, как я считаю, вам нужно по второй ссылке (тот, что от avrfreaks)

Это ссылка, которую я взял из другого потока на stackexchange, довольно хорошо резюмирует всю идею http://www.me.ucsb.edu/~me170c/Code/How_to_Enable_Interrupts_on_ANY_pin.pdf

Привет, Дэн

О, круто! Я буду работать над этим подходом как можно скорее! Чур!

Вы можете подключить все свои кнопки через вентиль ИЛИ (для активного-высокого уровня) или вентиль И (для активного-низкого уровня) к выводу прерывания, а также к обычным контактам без прерывания, чтобы при нажатии любой кнопки прерывание срабатывает.

После того, как это прерывание было запущено, вы можете проверить другие входы, чтобы определить, какая кнопка вызвала прерывание.

Вы можете (если вы работаете с активным низким уровнем) использовать несколько диодов для вентиля ИЛИ (проводное ИЛИ) - (спасибо, Олин).

Простая диодная логика

В этом случае ЛЮБОЙ сигнал становится низким, когда какой-либо переключатель замкнут вместе с линией IN этого переключателя, и остается низким, пока все переключатели не будут разомкнуты. Невозможно сказать, замкнут ли переключатель, когда он уже замкнут.

Если вы хотите еще больше усложнить и еще больше повысить удобство использования системы, вы можете реализовать «уведомление об изменении» на всех коммутаторах. По сути, это то, что находится внутри AVR для запуска прерывания, но нет причин, по которым вы не могли бы реализовать это снаружи и использовать вывод прерывания в качестве вывода уведомления об изменении.

Это имело бы большое преимущество, заключающееся в том, что он запускал бы импульс на выводе прерывания и, следовательно, прерывание, когда любой из входов меняет состояние — будь то с высокого на низкий или с низкого на высокий — так что вы можете знать, когда любой количество кнопок было нажато или отпущено - и он также будет обрабатывать комбинации кнопок - нажмите одну, и вы получите пульс; нажмите секунду, и вы получите еще один импульс; отпустите первый, и вы получите третий импульс.

Уведомление об изменении использует 2 триггера D-типа и вентиль XOR на каждый вход, и все они связаны вместе большим вентилем ИЛИ. Он также нуждается в некоторой форме тактового сигнала - чем медленнее часы, тем шире импульсы. Да, это громоздко с отдельными чипами, но оно того стоит из-за дополнительных преимуществ, которые он вам дает.

В качестве примера схемы вы можете посмотреть на схему уведомления об изменении входа PIC — страница 7 этого документа :

Изменить схему уведомления

Вы можете игнорировать вентиль AND — это просто для того, чтобы разрешить включение/отключение уведомления об изменении для каждого вывода. Линии ----|> Cисходят от часов, о которых я упоминал выше.

Я не знаю о Mega, но на UNO у вас есть 2 контакта прерывания - контакты 2 и 3. Все остальные требуют опроса.

Вау, этот дизайн уведомлений об изменениях потрясающий!

Да, это правда. Это аппаратные прерывания, и поэтому они привязаны к определенным контактам. На Mega 2560 это контакты 2, 3, 18, 19, 20 и 21, как указано в спецификациях.

Если вы хотите сохранить контакты прерывания или иметь больше кнопок, вы можете воспользоваться советом Маженко или Олина. Это требует от вас перенастройки вашей схемы, и в этом случае вы можете сделать самую простую перенастройку из всех — просто направить провода кнопок на правильные контакты.

Спасибо за подтверждение ограничения. Думаю, я втайне надеялся, что кто-нибудь скажет, что вы можете использовать <черную магию>, чтобы переназначить прерывание на (другие) контакты...