Обычно я использовал следующий алгоритм антидребезга:
- Разрешаем EXTI ISR по входам с клавиш, по обоим фронтам.
- Происходит ожидание изменения уровня сигнала на входах.
- Прерывание по EXTI, вызов EXTI ISR.
В EXTI ISR останавливаем и запускаем заново таймер. Например, на 20 мс. - Если ко времени вызова ISR таймера произойдёт новый вызов EXTI ISR, то таймер будет перезапущен и начнёт считать заново.
- Таймер досчитал, вызывается ISR таймера.
Таймер останавливаем.
Здесь состояние клавиатуры можно считать стабильным. Поэтому считываем её состояние и передаём на обработку, куда следует. - Переходим к пункту 1.
Этот же метод вполне пригоден для определения таймаута по приёму UART на микроконтроллерах, у которых отсутствует отдельное прерывание по таймауту.
На CyberForum'е заметили, что при плохом контакте прерывания от клавиатуры могут идти слишком часто и микроконтроллер будет всё время висеть в прерываниях. Отсюда возникла небольшая доработка.
- Разрешаем EXTI ISR по входам с клавиш, по обоим фронтам.
- Нажимается ржавая кнопка.
- По первому вызову EXTI ISR:
- Запускается таймер;
- Отключается только вызов ISR по EXTI в NVIC, флаги прерываний продолжают сохраняться в регистре PR;
- В ISR таймера:
- Останавливаем таймер;
- проверяем наличие флага прерывания от EXTI:
- Если флаг установлен, перезапускаем таймер;
- Если флаг не установлен, то считываем состояние клавиатуры и передаём на обработку.
- Переходим к пункту 1.
Видео: Демонстрация подавления дребезга контактов
Наличие матричной клавиатуры ничего не меняет. Просто на EXTI надо завести все линии строк либо столбцов, чтобы изменение уровня сигнала из-за любой кнопки вызывало прерывание EXTI. В момент же считывания состояния матричной клавиатуры прерывания мешать не будут, так как таймер полностью остановлен, а EXTI ISR отключены.