AVR240: клавиатура 4x4, пробуждение AVR от нажатия |
![]() |
Добавил(а) microsin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
В AVR240 [1] приведен пример организации клавиатурной матрицы 4x4, подключенной к микроконтроллеру AVR. Есть возможность введения энергосбережения в систему, когда микроконтроллер выводится из состояния сна при нажатии на кнопку клавиатуры. Основные возможности: • Клавиатура из 16 кнопок на замыкание, организованных в матрицу 4x4 [Общее описание] В этом апноуте показан простой пример интерфейса с клавиатурой 4x4, разработанный для применения в переносных устройствах с батарейным питанием. Микроконтроллер AVR почти все свое время проводит в режиме экономии энергии (Power-down mode, или Sleep mode), просыпаясь при нажатии на кнопку клавиатуры. Для демонстрации факт пробуждения и детектирование нажатой клавиши отображается простой тест-программой, мигающей двумя светодиодами. Если нажата кнопка "0", то красный светодиод (RED LED) мигнет 10 раз. Все другие клавиши вызовут мигание зеленого светодиода (GREEN LED) столько раз, сколько написано на клавише (например, если нажата кнопка "C", то это соответствует шестнадцатеричному коду 0x0c или в десятичном виде 12, и GREEN LED мигнет 12 раз). Рис. 1-1. Подключение к AVR клавиатурной матрицы и светодиодов. [Немного теории - как это работает] Столбцы матрицы клавиатуры подключены к старшему нибблу порта B (PB7..PB4). Строки матрицы клавиатуры подключены к младшему нибблу порта B (PB3..PB0). Резисторы R1 .. R8 (см. рис. 1-1) ограничивают входной ток и напряжение до безопасного уровня, что защищает AVR от действия статического электричества, которое могло бы быть случайно приложено к клавиатуре. Они могут быть выброшены в большинстве приложений. В состоянии ожидания старший ниббл порта B (PB7..PB4) сконфигурирован как выходы, и на них выведен уровень лог. 0. Младший ниббл порта B (PB3..PB0) сконфигурирован как входы с разрешенными внутренними pull-up резисторами (что такое pull-up, как конфигурировать входы и выходы AVR см. [2, 3]). После завершения инициализации AVR переводится в режим сна. Когда нажата любая кнопка на клавиатуре, один из диодов D1..D4 откроется, и притянет к лог. 0 уровень входа внешнего прерывания PD2, на котором также разрешен внутренний резистор pull-up. Это событие разбудит AVR, и заставит его выполнить обработчик внешнего прерывания (interrupt service routine, ISR), которое просканирует клавиатуру и вычислит, какая клавиша была нажата. После этого ISR вернет управление в основную программу, которая будет управлять светодиодом в соответствии нажатой клавише, и затем снова переведет AVR обратно в режим сна. Резисторы R9 и R10 это традиционные токоограничивающие резисторы, чтобы установить для светодиодов номинальный ток. В этой схеме применены светодиоды 330?, рассчитанные на источник питания 5V (можно с успехом применить любые резисторы в диапазоне от 330? до 1k?). Светодиоды LEDx управляются втекающим током около 10mA (они загораются, когда на выходе PD0 или PD1 выведен лог. 0). [Реализация] Программное обеспечение микроконтроллера (firmware) состоит из 3 основных частей: код сброса (метка reset, см. листинг программы во врезке "Код программы на языке ассемблера"), тест-программа (метка flash) и обработчик прерывания (метка scan), которые настраивают порты, режим сна, энергосберегающий режим и прерывания. Тест-программа мигает светодиодами при пробуждении, и обработчик прерывания отвечает на клавиатурные нажатия. Код сброса. Алгоритм программы сброса показан на рис. 3-1. В момент сброса (это происходит при включении питания) порты инициализируются своим начальным направлением (какие работают на вход, какие на выход). Направление фиксировано для порта D, у которого все разряды настроены как выход, кроме PD2, который должен быть входом для того, чтобы он фиксировал внешнее прерывание от нажатия на клавиатуре. На разряде PD2 также разрешен pull-up (внутренний верхний подтягивающий резистор) путем установки бита 2 регистра PORTD. Не используемые выводы сконфигурированы как выходы, чтобы избежать повышенного энергопотребления из-за шумовых входных сигналов, что было бы возможно, если оставить входы плавающими. У порта B старший ниббл настраивается как выходы в состоянии лог. 0, и младший ниббл как входы с разрешенными на входе резисторами pull-up. Поскольку используется минимальное количество внешних компонентов, нужно гарантировать, что pull-up включены на всех настроенных входах. Направление работы порта настраивается через регистры DDRB и DDRD, и для разрядов выхода нужно записать в них лог. 1, а для разрядов входа лог. 0. Для входных разрядов нужно записать лог. 1 в соответствующие разряды регистров PORTB и PORTD. Входы можно опрашивать программно, читая содержимое регистров PINB и PIND. Эта программа ждет на входах появления лог. 0, и использует инструкцию SBIS, чтобы пропустить разряды при опросе клавиатуры, которые не находятся в состоянии лог. 0. Подробнее про работу с портами GPIO см. [2, 3]. Режим выключения (Power-down) выбирается установкой бит SE и SM в регистре MCUCR. В то же самое время внешнее прерывание конфигурируется записью нулей в биты ISC00 и ISC01. Это установит внешнее прерывание (external interrupt) INT0 для срабатывания на уровень лог. 0. Когда используется режим "Powerdown", AVR можно разбудить только по перепаду в лог. 0 на входе INT0 (разряд порта PD2). Выключение аналогового компаратора (Analog Comparator) дополнительно снижает энергопотребление в режиме сна. Это осуществляется установкой бита ACD в регистре ACSR, что должно быть осуществлено с осторожностью; иначе возможна генерация нежелательного прерывания. Для этой цели в программе запрещаются глобальные прерывания, пока не будет полной готовности к обработке прерываний. Если Вы хотите использовать Analog Comparator, то код его запрещения можно удалить, но необходимо изменить ножки портов GPIO, используемые для подключения клавиатуры, поскольку два разряда порта B аппаратно используются как входы компаратора. После всех действий по настройке, AVR вводится в режим сна (sleep mode). Это действие помещено в главный цикл программы (метка main), чтобы гарантировать, что микроконтроллер снова войдет в сон после завершения работы ISR и подпрограммы теста, которая мигает светодиодами. Когда AVR проснется от нажатия на клавиатуре, будет вызвана подпрограмма мигания (Flash) после завершения работы ISR. После завершения подпрограммы Flash снова разрешаются внешние прерывания от вывода PD2, так что может снова произойти другое прерывание. Рис. 3-1. Алгоритм работы кода сброса и основной программы. Функция тестирования Flash. Её алгоритм показан на рис. 3-2. Эта функция написана только для демонстрации, и может быть заменена на Ваше приложение, выполняющее нужные действия при выходе из режима Powerdown. It serves to demonstrate that the key scan routine is working correctly. Значение нажатой кнопки можно получить из переменной key, и использовать как указатель для доступа к 16-байтной таблице перекодирования, сохраненной в EEPROM. Таблица содержит коды нажатых кнопок. Таблица использовалась по двум причинам: это позволяет сделать программу короче, и позволяет проще реализовать полное ASCII-кодирование нажатых кнопок. Для более мощных AVR таблицу можно хранить в памяти программ, и получать к ней доступ с помощью инструкции LPM. Значение из таблицы, соответствующее нажатой кнопки, в данном примере используется как начальное значение переменной обратного отсчета в цикле включения/выключения выхода управления светодиодом. Если значение 0, то красный светодиод (RED LED) мигнет 10 раз. Если значение не 0, то зеленый светодиод (GREEN LED) мигнет столько раз, сколько будет прочитано из таблицы перекодирования в EEPROM. Например, 3 раза мигнет для кнопки 3, и 15 раз для кнопки F и т. п. Затем AVR повторит цикл и снова попадет в режим сна. Подпрограмма мигания светодиодами может быть просто изменена для нужд Вашего приложения, можно заменить функцию Flash другим кодом. Основное внимание нужно уделить времени выполнения кода. Поскольку тест-программа тратит определенное время на задержки в формировании импульсов мигания, не требуются дополнительные усилия по подавлению дребезга контактов клавиатуры. Если же Ваш код работает очень быстро, то может потребоваться вставить небольшую задержку, чтобы дать время затихнуть импульсам дребезга контактов. Время пробуждения составляет обычно около 16 миллисекунд, хотя это время может быть уменьшено для новых моделей микроконтроллеров. Рис. 3-2. Алгоритм работы функции мигания. Подпрограмма формирования длинной задержки (delay). Чтобы мигания светодиода были хорошо заметны, нужна задержка как минимум 0.25 секунды. Это достигается подходящим циклом FOR, чтобы таймер/счетчик мог выполнять другую работу. Чтобы получилась задержка свыше 0.25 при тактовой частоте 4 МГц, требуется 3 вложенных цикла. Три локальные переменные содержатся в регистрах fine, medium и coarse, которые используются в цикле задержки. Счетчики fine (точный счетчик) и medium (средний по точности счетчик) могут содержать максимальное значение 255 при счетчике coarse (грубый счетчик), установленном в значение 5, что дает задержку около 0.25 секунды. Алгоритм формирования задержки показан на рис. 3-3. Рис. 3-3. Алгоритм работы подпрограммы длинной задержки. Обработчик прерывания (Interrupt Service Routine, ISR). Обычно состояние регистра статуса (Status Register) содержит контекст выполнения основной программы, поэтому этот регистр сохраняется на входе и восстанавливается на выходе из ISR, чтобы гарантировать надежную работу кода основной программы (main). В данном примере программы это может быть по желанию опущено. Алгоритм показан на рисунке 3-4. Рис. 3-4. Алгоритм работы ISR. Сначала детектируется строка клавиатуры, путем опроса на лог. 0 состояния каждого входа строки. Затем базовое число 0, 4, 8 или 12 присваивается переменной key. Затем порты переинициализируются, и направление работы GPIO порта B переключается. Короткая задержка "settle" используется, чтобы дать время выводам установить свое состояние. Это делается как обычно, с помощью подходящего цикла FOR. Столбец нажатой кнопки детектируется и записывается в переменную temp в виде одного из чисел 0, 1, 2 или 3. Конечное нажатие вычисляется путем сложения key и temp, с помещением результата в key, после чего можно выполнять функцию Flash. Конфигурация входов/выходов порта B восстанавливается обратно перед восстановлением значения Status Register. Это экономит повторное использование задержки для установки уровней сигналов портов GPIO для строк и столбцов. И наконец, запрещается внешнее прерывание. Это делается для того, чтобы избежать повторного срабатывания прерывания сразу после выхода из ISR. Подпрограмма короткой задержки. Эта короткая задержка нужна, когда меняется конфигурация GPIO порта B, чтобы дать время на установление уровня ножек микроконтроллера. Подпрограмма использует общий временных регистр temp как одиночный счетчик для цикла FOR, и устанавливается на максимальное количество повторений цикла 255. Это дает задержку около 0.192 миллисекунд при использовании тактовой частоты 4 МГц. Значение задержки можно уменьшить экспериментально, если это имеет принципиальное значение для скорости работы Вашей программы. Возможно даже в некоторых случаях полностью убрать эту задержку. [Ресурсы, используемые программой] Таблица 3-1. Использование CPU и памяти AVR.
Примечание: одно слово команды AVR имеет размер 2 байта. Таблица 3-2. Использование периферийных устройств AVR.
;**** APPLICATION NOTE AVR240 ********************************************
;*
;* Проект: клавиатура 4x4, с пробуждением AVR при нажатии
;* Версия: 1.2
;* Последнее обновление: 2004.11.11
;* Где можно применить: подойдет для всех моделей микроконтроллеров AVR.
;*
;* E-mail техподдержки: avr@atmel.com
;*
;* ОПИСАНИЕ
;* В этом апноуте показано, как сканировать клавиатуру 4x4 с использованием
;* режима сна (sleep mode) и пробуждением AVR при нажатии на кнопку
;* клавиатуры. Эта разработка использует минимальное количество внешних
;* компонентов. Добавлена тест-программа, которая при пробуждении
;* сканированием определяет код нажатой кнопки и мигает светодиодами,
;* показывая количеством вспышек, какая кнопка нажата. Сигнал внешнего
;* прерывания INT0/PD2 используется для пробуждения микроконтроллера.
;* Этот пример тестировался на микроконтроллере AT90S1200, но его можно
;* легко портировать на любой AVR с соответствующей коррекцией кода
;* векторов прерывания, EEPROM и указателя стека. Время выполнения
;* предполагает тактовую частоту 4 МГц. Таблица перекодирования (look
;* up table) использует EEPROM, и она позволяет проще перенастроить
;* программу под другое назначение, например для получения ASCII-кода
;* нажатой клавиши.
;*************************************************************************
;***** Регистры, используемые всеми подпрограммами
.def temp =r16 ;общий временный регистр ;Выводы порта B
.equ ROW1 =3 ;входы для строк клавиатуры .equ ROW2 =2 .equ ROW3 =1 .equ ROW4 =0 .equ COL1 =7 ;выходы для столбцов клавиатуры .equ COL2 =6 .equ COL3 =5 .equ COL4 =4 ;Выводы порта D
.equ GREEN=0 ;зеленый светодиод (GREEN LED) .equ RED =1 ;красный светодиод (RED LED) .equ INTR =2 ;вход внешнего прерывания .include "1200def.inc" ;***** Регистры, используемые ISR
.def key =r17 ;указатель кнопки для таблицы в EEPROM .def status =r21 ;в этом регистре сохраняется SREG ;***** Регистры, используемые как локальные переменные
;***** в подпрограмме формирования длинной задержки
.def fine =r18 ;счетчики задержки для циклов .def medium =r19 .def coarse =r20 ;***** Таблица для перекодирования кнопок *************************
.eseg ;Сегмент EEPROM .org 0.db 1,2,3,15,4,5,6,14,7,8,9,13,10,0,11,12 ;**** Исходный код ************************************************
.cseg ;Сегмент CODE.org 0 rjmp reset ;Обработчик сброса rjmp scan ;ISR reti ;обработчик таймера не используется reti ;обработчик аналогового компаратора не используется ;*** Обработчик сброса *********************************************
reset: ldi temp,0xFB ;инициализация порта D как GPIO out DDRD,temp ;все ножки будут выходами, ; кроме PD2 для внешнего прерывания INT0 ldi temp,0x30 ;задать режим сна (sleep mode) и выключение (power out MCUCR,temp ; down), и прерывание по низкому уровню. ldi temp,0x40 ;разрешить внешние прерывания out GIMSK,temp sbi ACSR,ACD ;выключить компаратор для экономии энергии main: cli ;глобальный запрет прерываний ldi temp,0xF0 ;инициализация порта B как GPIO out DDRB,temp ; 4 выхода и 4 входа ldi temp,0x0F ;все выходы столбцов в лог. 0, out PORTB,temp ;активировать pull up на строках ldi temp,0x07 ;разрешить pull up на PD2 и out PORTD,temp ;выключить светодиоды sei ;разрешить прерывания sleep ;вход в режим сна rcall flash ;запустить подпрограмму мигания светодиодами ldi temp,0x40 out GIMSK,temp ;разрешить внешние прерывания rjmp main ;снова войти в сон после сканирования кнопок ;**** Обработчик прерывания (ISR) ***********************************
scan: in status,SREG ;сохранить регистр статуса sbis PINB,ROW1 ;найти строку клавиатуры с нажатием ldi key,0 ;и установить указатель на строку ROW sbis PINB,ROW2 ldi key,4 sbis PINB,ROW3 ldi key,8 sbis PINB,ROW4 ldi key,12 ldi temp,0x0F ;поменять направление работы порта B, out DDRB,temp ;чтобы найти столбец с нажатием ldi temp,0xF0 ;разрешить pull up и out PORTB,temp ;записать нули в строки rcall settle ;дать время для установки сигналов sbis PINB,COL1 ;найти столбец с нажатием ldi temp,0 ;и установить указатель на столбец COL sbis PINB,COL2 ldi temp,1 sbis PINB,COL3 ldi temp,2 sbis PINB,COL4 ldi temp,3 add key,temp ;сложить ROW и COL, чтобы получить полный указатель ldi temp,0xF0 ;переинициализировать обратно GPIO порта B out DDRB,temp ; 4 выхода, 4 входа ldi temp,0x0F ;все столбцы в лог. 0 и разрешить на строках out PORTB,temp ;резисторы pull up out SREG,status;восстановить регистр статуса ldi temp,0x00 out GIMSK,temp ;запретить внешнее прерывание ;это необходимо, потому что здесь используется прерывание,
;срабатывающее не по перепаду сигнала, а по его уровню reti ;возврат обратно в main ;*** Пример тест-программы, которая мигает светодиодами **************
flash: out EEAR,key ;адрес EEPROM sbi EECR,EERE ;строб EEPROM in temp,EEDR ;установить количество вспышек tst temp ;в ячейке 0? breq zero ;если да, то мигаем красным светодиодом green_flash: cbi PORTD,GREEN;будем мигать зеленым светодиодом temp раз rcall delay sbi PORTD,GREEN rcall delay dec temp brne green_flash exit: ret zero: ldi temp,10 flash_again: cbi PORTD,RED ;10 раз мигнуть красным светодиодом rcall delay sbi PORTD,RED rcall delay dec temp brne flash_again rjmp exit ;**** Подпрограмма задержки для вспышек светодиодов *********************
;**** Значения в счетчиках coarse, medium, fine подобраны для получения
;**** задержки примерно 0.25 секунды при тактовой частоте 4 МГц.
delay: ldi coarse,5 cagain: ldi medium,255 magain: ldi fine,255 fagain: dec fine brne fagain dec medium brne magain dec coarse brne cagain ret ;*** Задержка для стабилизации лог. уровня порта ************************
settle: ldi temp,255 tagain: dec temp brne tagain ret [Ссылки] 1. AVR240: 4 x 4 Keypad - Wake-up on Keypress site:atmel.com. |