AVR240: клавиатура 4x4, пробуждение AVR от нажатия Печать
Добавил(а) microsin   

В AVR240 [1] приведен пример организации клавиатурной матрицы 4x4, подключенной к микроконтроллеру AVR. Есть возможность введения энергосбережения в систему, когда микроконтроллер выводится из состояния сна при нажатии на кнопку клавиатуры. Основные возможности:

• Клавиатура из 16 кнопок на замыкание, организованных в матрицу 4x4
• Очень маленькое общее энергопотребление системы
• Микроконтроллер AVR уходит в режим сна (Sleep Mode) и просыпается при нажатии кнопки
• Минимальное количество внешних компонентов
• Если это необходимо, можно добавить защиту от статического электричества (ESD)
• Эффективный код
• Прилагается пример кода для AT90S1200
• Описанный принцип легко применить для любого микроконтроллера AVR

[Общее описание]

В этом апноуте показан простой пример интерфейса с клавиатурой 4x4, разработанный для применения в переносных устройствах с батарейным питанием. Микроконтроллер AVR почти все свое время проводит в режиме экономии энергии (Power-down mode, или Sleep mode), просыпаясь при нажатии на кнопку клавиатуры. Для демонстрации факт пробуждения и детектирование нажатой клавиши отображается простой тест-программой, мигающей двумя светодиодами. Если нажата кнопка "0", то красный светодиод (RED LED) мигнет 10 раз. Все другие клавиши вызовут мигание зеленого светодиода (GREEN LED) столько раз, сколько написано на клавише (например, если нажата кнопка "C", то это соответствует шестнадцатеричному коду 0x0c или в десятичном виде 12, и GREEN LED мигнет 12 раз).

AVR240 keypad and LED connections

Рис. 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, так что может снова произойти другое прерывание.

AVR240 Reset and Main routine

Рис. 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 миллисекунд, хотя это время может быть уменьшено для новых моделей микроконтроллеров.

AVR240 Flash function

Рис. 3-2. Алгоритм работы функции мигания.

Подпрограмма формирования длинной задержки (delay). Чтобы мигания светодиода были хорошо заметны, нужна задержка как минимум 0.25 секунды. Это достигается подходящим циклом FOR, чтобы таймер/счетчик мог выполнять другую работу. Чтобы получилась задержка свыше 0.25 при тактовой частоте 4 МГц, требуется 3 вложенных цикла. Три локальные переменные содержатся в регистрах fine, medium и coarse, которые используются в цикле задержки. Счетчики fine (точный счетчик) и medium (средний по точности счетчик) могут содержать максимальное значение 255 при счетчике coarse (грубый счетчик), установленном в значение 5, что дает задержку около 0.25 секунды. Алгоритм формирования задержки показан на рис. 3-3.

AVR240 Delay subroutine

Рис. 3-3. Алгоритм работы подпрограммы длинной задержки.

Обработчик прерывания (Interrupt Service Routine, ISR). Обычно состояние регистра статуса (Status Register) содержит контекст выполнения основной программы, поэтому этот регистр сохраняется на входе и восстанавливается на выходе из ISR, чтобы гарантировать надежную работу кода основной программы (main). В данном примере программы это может быть по желанию опущено. Алгоритм показан на рисунке 3-4.

AVR240 ISR routine

Рис. 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.

Функция Размер кода Количество циклов Использование регистров Прерывание Описание
Main 24 слова 19 R16 - Инициализация
Flash 20 слов - R16 - Тестовый код - только для примера
Scan 31 слово обычно 47 R16, R17, R21 INT0 Сканирование матрицы клавиатуры 4x4
Delay 10 слов 1000000 R18, R19, R20 - Задержка на 0.25 сек
Settle 4 слова 764 R16 - Задержка для установки значений уровней порта. Используется при сканировании матрицы клавиатуры.
ВСЕГО 87 слов - R16, R17, R18, R19, R20, R21 -  

Примечание: одно слово команды AVR имеет размер 2 байта.

Таблица 3-2. Использование периферийных устройств AVR.

Аппаратура AVR Описание Прерывания
Внешнее прерывание External Interrupt 0, INT0) Сигнал пробуждения AVR при нажатии на кнопку INT0 (срабатывание по низкому уровню)
16 байт EEPROM Таблица перекодирования для клавиатуры -
8 ножек портов GPIO Подключение матрицы клавиатуры 4x4 -
1 ножка порта GPIO Сигнал внешнего прерывания -
2 ножки порта GPIO Выходы для управления светодиодами  

;**** 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.
2. Доступ к портам I/O AVR на языке C (GCC, WinAVR).
3. GPIO и альтернативные функции порта.
4. Подключение клавиатуры к AVR.
5. 160227AVR240-AVR243.zip - код для апноутов AVR240 и AVR243 (примеры подключения клавиатуры).