Подключение кнопки к микроконтроллеру



Кнопка и микроконтроллер
Кнопку к микроконтроллеру можно подключить двумя основными способами, с подтяжкой линии порта к высокому логическому уровню или низкому через резистор, как показано на картинке ниже.
Я обычно использую первый вариант подключения, можно конечно использовать внутренние подтягивающие резисторы на входах PORTB, но мне еще не доводилось применять такой способ.
Подключение кнопки к МК
В простейшем варианте микроконтроллер все время опрашивает одну или несколько кнопок, при нажатии которых выполняет соответствующую подпрограмму и снова возвращается на опрос кнопок. Подпрограмма обычно выполняется очень быстро, естественно за это время можно не успеть отжать кнопку, вследствие чего подпрограмма выполнится многократно. Чтобы этого не происходило после обнаружения нажатой кнопки необходимо добавить проверку отжатого состояния, но и в этом случае из-за явления дребезга контактов выполнение подпрограммы может начаться до отжатия кнопки. Поэтому после обнаружения нажатой кнопки необходимо добавить временную задержку в 5-20 мс. Проверка отжатого состояния будет многократно выполняться через заданный интервал времени. После обнаружения отжатия выполниться соответствующая подпрограмма, после чего опрос кнопок будет продолжен, но и здесь дребезг после отжатия может еще продолжаться, поэтому можно добавить паузу также перед опросом нажатого состояния кнопки. Я обычно этого не делаю, достаточно паузы во время опроса отжатого состояния кнопки. В итоге у нас получается примерно такой код:

Бывает нужно, чтобы кнопка имела две функции, на короткое и длительное нажатие. В этом случае во время опроса отжатого состояния необходимо добавить таймер времени. После обнаружения нажатого состояния записываем в дополнительный регистр число и уходим на паузу, после возврата декрементируем значение регистра и снова опрашиваем кнопку на предмет отжатого состояния. Этот цикл продолжается до тех пор, пока не отожмется кнопка или значение регистра не станет равным нулю. При обнаружении отжатого состояния до обнуления регистра, выполняется подпрограмма program1, при обнулении выполнится подпрограмма program2. Например, необходимо задать продолжительность длительного нажатия в 1 секунду, а пауза равна 10 мс, тогда в регистр счетчика надо записать число 100.

А если удерживать кнопку в течении 3 секунд, тогда подпрограмма program2 выполнится несколько раз, чтобы избежать этого в конце этой подпрограммы перед возвратом или после возврата нужно добавить опрос отжатого состояния кнопки. Ниже представлен код программы, где кнопка knp1 имеет 2 функции:

Возможно такое что, кнопка knp1используется внутри самой подпрограммы program2, в этом случае перед ее опросом внутри подпрограммы вначале также следует дождаться отжатия кнопки.

Иногда необходимо чтобы при однократном нажатии кнопки, подпрограмма выполнилась один раз, а при удерживании выполнялась многократно, например, ускоренное приращение числа на цифровом табло. Такую функцию можно реализовать очень просто, необходимо лишь исключить опрос отжатого состояния кнопки. Но здесь имеются свои недостатки, пропадает “дискретность” выполнения подпрограммы, ведь за одно кратковременное нажатие подпрограмма может выполниться несколько раз в зависимости от длительности нажатия, а нам требуется однократное выполнение. Данную функцию можно реализовать на основе предыдущего примера, немного изменив код. После длительного нажатия и выполнения подпрограммы, уходим на паузу, далее однократно выполняем проверку отжатого состояния (а не дожидаемся, пока отпустят кнопку), после чего при условии нажатой кнопки снова выполняем подпрограмму. Этот цикл будет продолжаться пока не отпустят кнопку. Здесь пауза будет определять скорость вызова подпрограммы (скорость приращения числа на цифровом табло). В итоге сохраняется “дискретность”, совместно с ускоренным многократным выполнением подпрограммы при удержании кнопки. Код программы выглядит следующим образом:

А теперь рассмотрим случай, когда микроконтроллер непрерывно выполняет какие-либо задачи, в этом случае ожидать отжатие кнопки недопустимо. Здесь можно воспользоваться прерываниями по изменению уровня на входах RB4-RB7 или по входу внешнего прерывания INT.

Для прерываний по входам RB4-RB7 алгоритм следующий: при изменении сигнала с 1 на 0 происходит переход в подпрограмму обработчика прерываний, где необходимо сначала определить, что вызвало прерывание, когда имеется несколько источников прерываний. Когда источник определен, необходимо выяснить на каком именно входе изменился уровень сигнала, определив его, выполняем соответствующие операции внутри самого обработчика прерываний, либо устанавливаем флаг в регистре, который специально выделяем для этих целей. Далее необходимо считать регистр PORTB, для устранения несоответствия ранее сохраненного значения с сигналом на входах порта, иначе флаг прерывания сбросить не удастся. После сброса флага выходим из обработчика прерывания.

Специально выделенный регистр с флагами проверяем в цикле основной программы, где по установленному флагу выполняем какую-либо подпрограмму, после чего сбрасываем флаг.
Опять же из-за дребезга контактов при таком алгоритме прерывания могут генерироваться многократно, добавлять паузу на время дребезга внутри обработчика прерываний бессмысленно, так как теряется процессорное время необходимое для выполнения других задач.

Также в данном алгоритме не учтено повторное возникновение прерывания при отжатии кнопки, смена сигнала с 0 на 1, ведь прерывания по входам RB4-RB7 возникают по переднему и заднему фронту сигнала. Но здесь все просто, одно прерывание можно пропустить, выполняя соответствующие операции только при наличии 0 на входе.

Решить проблему дребезга можно с помощью таймера. После перехода в подпрограмму обработчика прерываний, при смене сигнала с 1 на 0, запрещаем прерывания по входам RB4-RB7, определяем вход, где изменился сигнал, устанавливаем флаг в специально выделенном регистре, запускаем таймер на 5-20 мс и выходим из подпрограммы прерывания. Через установленный промежуток времени, по переполнению таймера возвращаемся в обработчик прерываний, останавливаем таймер, сбрасываем флаг по переполнению, считываем PORTB для устранения несоответствия, сбрасываем флаг и разрешаем прерывания по входам RB4-RB7. При повторном возникновении прерывания в результате отжатия кнопки, весь процесс повторится, за исключением того что, пропускаем выполнение соответствующих операций, так как сигнал на входе равен 1. Код программы представлен ниже:

Честно говоря, такую конструкцию я не применял, не нравится мне все это дело. Вешать кнопки на прерывания лучше всего для пробуждения микроконтроллера из спящего режима.

Гораздо проще и надежнее поместить код опроса кнопок в цикле основной программы, в то место где они будут опрашиваться хотя бы через каждые 100 мс, по мере выполнения других задач. Для предотвращения многократного выполнения подпрограммы при длительном нажатии на кнопку нужно использовать дополнительный регистр с флагами контроля состояния кнопок. Если во время очередного опроса в цикле основной программы кнопка окажется не нажатой, то устанавливаем в 1 соответствующий флаг регистра. При обнаружении нажатия сначала проверяем флаг, если он равен 1, сбрасываем его и выполняем подпрограмму, после чего идем на опрос второй кнопки или далее по циклу основной программы.
При следующем опросе флаг будет равен 0, ничего не делаем, идем также на опрос второй кнопки, или далее по циклу не задерживаясь. Такой пропуск будет происходить до тех пор, пока не отожмем кнопку и флаг снова не установиться в 1. Код выглядит следующим образом:

Как видно все очень просто, не нужно никаких прерываний и таймеров.

Последние записи:

Один комментарий на “Подключение кнопки к микроконтроллеру

  1. Внутренние подтягивающие резисторы удобно при отладке использовать. Меньше монтажа делать придется. Ну а в готовом устройстве внешние резисторы будут понадежнее )
    Хотя при такой хорошей программной фильтрации дребезга, при использовании трансформаторного источника питания(или батареек) и кондеров по питанию, можно избежать лишних наводок и внутренний подтяг использовать. Что поможет например в компактных устройствах.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *