TCA8418: контроллер матрицы клавиатуры |
![]() |
Добавил(а) microsin | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
TCA8418 представляет собой устройство для сканирования клавиатуры, с интегрированной защитой от статического электричества (ESD). Микросхема может работать от напряжения питания в диапазоне 1.65V .. 3.6V, имеет 18 программируемых ножек ввода/вывода общего назначения (GPIO), которые могут поддерживать до 80 кнопок. Кнопки могут быть организованы в матрицу, или подключены к отдельным ножкам GPIO. Конфигурирование микросхемы, информация о нажатиях кнопок передается через интерфейс I2C (микросхема работает как slave-устройство I2C). Контроллер клавиатуры сканирует кнопки с защитой от дребезга, и сохраняет информацию о нажатиях в стек FIFO размером 10 байт. У этого стека есть возможность перезаписывать по кругу вводимые значения (overflow wrap), что позволяет запоминать самые последние актуальные нажатия. Ножка прерывания ~INT позволяет сигнализировать внешнему контроллеру о событиях нажатий и отпусканий клавиш либо в реальном времени, либо с частотой, не большей заданной. Основные особенности контроллера клавиатуры TCA8418: • Рабочий диапазон напряжений питания 1.65V .. 3.6V. Области применения TCA8418: • Смартфоны Упрощенная схема контроллера TCA8418: Примечание: на рис. 1 показано только 7 используемых GPIO для сканирования матрицы кнопок, хотя всего имеется 18 портов GPIO. [Цоколевка корпуса и назначение выводов] Корпус WQFN24, вид сверху: Назначение выводов:
Примечание: в столбце Тип указан тип вывода. I/O обозначает вход и выход, I вход, O выход. [Предельные допустимые значения(1)]
Примечания: (1) Стрессовые значения, перечисленные в таблице 2, могут привести к необратимому повреждению устройства. Эти параметры указаны только для справки, не подразумевается работа устройства в таких условиях или в условиях, отличающихся от рекомендованных (см. далее таблицу 4). Длительная работа в условиях, перечисленных в таблице 2, может повлиять на надежность устройства. [Параметры защиты от ESD]
Примечания: (1) Документ JEDEC JEP155 устанавливает, что 500V HBM позволяет безопасно реализовать производство со стандартным контролем ESD. [Рекомендуемые рабочие условия]
[Температурные параметры]
Примечание (1): для дополнительной информации по температурным метрикам см. документ SPRA953 [3]. [Электрические характеристики] Параметры указаны для напряжения питания VCC в диапазоне 1.65V .. 3.6V, если не указано нечто иное.
Примечание (1): подразумевается, что разрешен один GPIO. [Требования интервалов времени к интерфейсу I2C] Параметры показаны для рекомендованного диапазона температур окружающей среды. Диаграммы см. на рис. 16.
Примечания: (1) Cb = общая емкость одной линии шины в пФ. [Требования к интервалам сброса] Параметры показаны для рекомендованного диапазона температур окружающей среды. Диаграммы времени см. на рис. 19.
Примечание (1): схема подавления дребезга GPIO (debounce) пропускает каждую ножку входа GPIO через двухкаскадную схему регистров. Оба этих регистра тактируются одинаковой тактовой частотой, предположительно непрерывной, с номинальным периодом 50 мкс. Когда на входе меняется состояние, новое состояние защелкивается на первом каскаде в одном периоде тактов. Если на следующем такте оба состояния одинаковые, то входной сигнал переходит на второй регистр, и далее на остальные схемы. Поскольку состояния входов изменяются асинхронно по отношению к частоте тактов, может пройти любое время от 0 до 50 мкс до запоминания сигнала в первом каскаде. Таким образом, общее время дебоунсинга может доходить до 100 мкс. И если учитывать понижение частоты тактов, спецификация задержки расширяется до 120 мкс. [Характеристики переключения]
[Характеристики опроса кнопок(1)]
Примечание (1): показанные в таблице min и MAX интервалы опроса кнопок действуют для всех режимов скоростей передачи I2C. [Типовые характеристики] Графики характеристик указаны для TA = 25°C (если не указано нечто иное).
[Информация от измерении параметров] Конфигурация нагрузки ножки SDA: Рис. 16. Диаграммы сигналов (байт 1 адрес I2C, байты 2 и 3 данные P-порта) при нагруженной ножке SDA. Примечания: (A) CL включает емкость пробника и емкость jig. tocf измерено с CL 10 пФ или 400 пФ. Конфигурация тестирования ножки прерывания ~INT: Рис. 17. Форма сигналов на схеме нагрузки прерывания. Примечания: (A) CL включает емкость пробника и емкость jig. Конфигурация нагрузки P-порта: Рис. 18. Форма сигналов на схеме нагрузки P-порта. Конфигурация нагрузки ножки SDA: Конфигурация нагрузки P-порта: Рис. 19. Форма сигналов на схеме нагрузки сброса. Примечания: (A) CL включает емкость пробника и емкость jig. [Описание функционала] TCA8418 поддерживает до 10 столбцов и до 8 строк матрицы клавиатуры, давая возможность подключить до опрашиваемых 80 кнопок. Для организации матрицы клавиатуры может быть сконфигурирована любая комбинация из этих столбцов и строк. Конфигурирование матрицы осуществляется установкой лог. 1 в соответствующие регистры столбцов и строк (регистры KP_GPIO, см. таблицу 9). После того, как столбцы и строки, соединенные с матрицей клавиатуры, были добавлены, контроллер TCA8418 будет опрашивать этот массив кнопок, и также будет работать с любыми сконфигурированными как входы ножками GPIO. Функциональная блок-схема TCA8418: Key Event Table. Контроллер TCA8418 может быть сконфигурирован для поддержки многих различных конфигураций клавиатур. Все 18 ножек GPIO для строк и столбцов опрашиваемой матрицы могут поддерживать до 80 кнопок (режим матрицы). Другой вариант подключения опрашиваемых кнопок - без матрицы, использование 18 ножек GPIO как входы (режим GPI) для прямого подключения до 18 кнопок, просто замыкающих вход на GND. Также доступна любая комбинация опрашиваемой матрицы - например, может быть матрица кнопок 3 x 4, с использованием оставшихся 11 ножек GPIO под любые цели ввода/вывода. Для обоих типов подключения кнопок (матрица и GPI) в стек событий FIFO может быть добавлено событие кнопки (key event). Значния, которые добавляются в FIFO, зависят от настроенной конфигурации (матрица или GPI), и на каком порте было прочитано нажатие. Таблицы ниже показывают значения, которые соответствуют обоим конфигурациям (Key Event Table, таблица событий кнопок). Значение кодов кнопок ниже представлены десятичными, поскольку позиция десятков в коде используется для обозначения строки, а позиция единиц для обозначения столбца. Это самый понятный и удобный способ нумерации кодов кнопок. Таблица 1. Key Event Table, таблица событий кнопок (режим матрицы, кодирование позиций кнопок).
Таблица 2. Таблица событий кнопок (режим GPI, события строк).
Таблица 3. Таблица событий кнопок (режим GPI, события столбцов).
События GPI. Столбцы или входы, сконфигурированные как GPI, могут быть запрограммированы для вхождения как часть в Key Event Table, чтобы они могли генерировать прерывание события кнопки (Key Event Interrupt). Тогда Key Event Interrupt, вызванное GPI, будет следовать такому же процессу обработки, как и Key Event Interrupt, вызванное нажатием клавиши в матрице. GPI, сконфигурированные как часть Key Event Table, позволяют мониторить одиночные кнопки так же, как другие прерывания входов GPI. Как часть таблицы событий, GPI представлены десятичными значениями от 97 до 114. Строки R0-R7 представлены кодами 97 .. 104, и столбцы C0-C9 представлены кодами 105 .. 114. Для ножек GPI, которые установлены активными на лог. 1, и добавлены в Key Event Table, конечный автомат будет добавлять событие к счетчику событий код в таблицу событий всякий раз, когда эта ножка GPI перейдет от лог. 0 к лог. 1. Если ножка GPI установлена активной на лог. 0, то переход этой ножки от лог. 1 к лог. 0 будет считаться нажатием, и это событие также будет добавлено к счетчику событий и в таблицу событий. Как только выполнится условие генерации прерывания, машина состояний установит внутри себя прерывание для противоположного состояния, запрограммированного в регистр, чтобы избежать опроса для состояния отпускания, экономя тем самым потребляемый ток. Как только было достигнуто состояние отпускания, оно будет добавлено к таблице событий. Нажатие и отпускание все еще будут индицироваться битом 7 в регистре событий. События GPI также могут использоваться как последовательности разблокирования. Когда установлен бит GPI_EM, события GPI не будут отслеживаться, когда клавиатура заблокирована. Когда клавиатура заблокирована, бит GPI_EM должен быть очищен для отслеживаемых событий GPI, чтобы они попадали в счетчик событий и таблицу событий. Чтение событий кнопок (FIFO). TCA8418 содержит встроенный 10-байтный event FIFO, где сохраняются любые нажатия или отпускания кнопок, которые были добавлены в Key Event Table. Все строки (ROW) и столбцы (COL), добавленные в матрицу клавиатуры программированием регистров KP_GPIO1-KP_GPIO3, будут добавлять события в этот FIFO. Любые ножки GPI, сконфигурированные записью лог. 1 в регистры GPI_EM1-GPI_EM3, также будут генерировать события для FIFO. Когда хосту (I2C master) нужно прочитать FIFO, рекомендуется следовать описанной ниже процедуре. 1. Прочитать регистр INT_STAT (0x02), чтобы определить, выставлен ли сигнал прерывания на выводе ~INT. Если установлен GPI_INT или K_INT, то произошло событие кнопки, и оно было сохранено в FIFO. В качестве примера рассмотрим следующие нажатия кнопок (таблица 4). Таблица 4. Пример последовательности событий клавиатуры.
Если имела место последовательность событий из таблицы 4, то при выполнении рекомендуемых шагов по чтению FIFO хост увидит следующую информацию (таблица 5). Информация на вершине списка соответствует первоначальному чтению регистра KEY_LCK_EC[3:0]. Таблица 5. Пример чтения событий из FIFO.
Key Event Overflow(1). TCA8418 может обработать переполнение key event FIFO. Такое переполнение возникнет, когда FIFO полностью заполнен событиями (в него было сохранено 10 событий кнопок), и возникло новое событие. Это значит, что TCA8418 не может запомнить в своем внутреннем буфере большее количество информации о нажатиях. Когда произошло такое переполнение, установится бит OVR_FLOW_INT в регистре INT_STAT, и если установлен бит OVR_FLOW_IEN в регистре CFG, то выход ~INT установится в лог. 0 для информирования хоста о переполнении FIFO. Примечание (1): обратите внимание, что старший бит значения KEY_EVENT_A обозначает нажатие или отпускание кнопки. 1 обозначает нажатие, 0 отпускание. TCA8418 может обработать переполнение одним из двух методов, в зависимости от значения бита OVR_FLOW_M в регистре CFG (таблица 6). Подробнее про поведение переполнения см. секцию Overflow Errata. Таблица 6. Бит OVR_FLOW_M.
Рассмотрим следующий пример: FIFO заполнен нажатиями, и образовалось новое нажатие. Это новое нажатие соответствует кнопке 2 (0x82 в hex-представлении события нажатия кнопки 2). Тогда событие переполнение будет обработано следующим образом, см. таблицу 7: Таблица 7. Пример обработки Key Event Overflow.
Keypad Lock/Unlock. Пользователь может заблокировать клавиатуру с помощью функции lock/unlock. Клавиатура блокируется установкой BIT6 в регистре KEY_LCK_EC, что может предотвратить выдачу прерываний событий клавиатуры и отключить запись событий. Разблокировка кнопок может быть запрограммирована любым значением кнопки в матрице клавиатуры или любым из входов (GPI), которые введены в Key Event Table. Когда таймер маски прерываний блокировки клавиатуры не равен 0, пользователю нужно нажать 2 специальные клавиши, прежде чем будет сгенерировано прерывание keylock или будут записаны события клавиатуры. Прерывание события кнопки генерируется при первом нажатии пользователем на любую кнопку. Это первое прерывание может использоваться для включения LCD и отображения сообщения о необходимости разблокировки клавиатуры. Затем процессор прочитает регистр состояния блокировки (lock status register) чтобы увидеть, заблокирована ли клавиатураd. Следующее прерывание (keylock interrupt) не будет генерироваться до тех пор, пока обе последовательности кнопок разблокировки не будут правильными. Если корректные кнопки разблокировки не были нажаты до истечения таймера маски, то машина состояния вернется к началу этой процедуры. Рекомендуется выполнить следующую процедуру для блокировки клавиатуры: 1. Определиться, какие кнопки будут использоваться для последовательности разблокировки. Для этого в регистры UNLOCK1 и UNLOCK2 нужно записать значения кнопок из Key Event Table. Рис. 20. Алгоритм блокировки клавиатуры. Keypad Lock Interrupt Mask Timer. Функция Keypad Lock/Unlock контроллера TCA8418 дает возможность пользователю прекратить генерацию событий кнопок путем блокировки клавиатуры. С этим связана функция таймера маски прерываний (interrupt mask timer) блокировки клавиатуры, которая позволяет генерировать только оно прерывание, когда была нажата одна первая клавиша во время заблокированного состояния клавиатуры. Обычное назначение этой функции - дать пользователю понять, что прибор не завис, просто активирована функция блокировки клавиатуры (например, путем включения подсветки LCD и/или вывода сообщения о необходимости разблокировать клавиатуру). Обратите внимание, что этот interrupt mask timer может также использоваться для ограничения количества прерываний, генерируемых на определенном интервале времени. Разрешается interrupt mask timer путем установки поля бит [7:3] регистра KP_LCK_TIMER. Значение в этом поле может быть любым в диапазоне от 0 до 31 секунд (значение 0 запретит эту функцию interrupt mask). Когда клавиатура заблокирована, и interrupt mask timer установлен в ненулевое значение, то это разрешит функцию таймера маски прерываний. Эта маска ограничивает количество генерируемых прерываний. Обычно эта возможность используется для совместного использования Keypad Lock/Unlock, чтобы зажечь экран LCD и вывести сообщение "клавиатура заблокирована". Проще всего объяснить работу этой функции на следующем примере. Представим себе мобильное устройство с экраном LCD, подсветка которого выключается после 10 прекращения активности пользователя (для экономии энергии). Обычно прерывание для процессора снова включит подсветку LCD. Без функции interrupt mask timer когда клавиатура заблокирована, прерывания от неё не генерируются, и подсветка экрана не включится. Для рассмотрения примера ниже см. алгоритм на рис. 20: 1. Поскольку подсветка выключится через 10 секунд, если не поступают прерывания от клавиатуры, interrupt mask timer (KP_LCK_TIMER[7:3]) получает значение настройки на 10 секунд. Затем клавиатура блокируется. Поддержка Control-Alt-Delete. Вместе с обработкой обычных клавиатурных нажатий TCA8418 может поддерживать функцию нажатия клавиш Ctrl-Alt-Del (CAD). Эта функция дает возможность хосту распознать специальную комбинацию клавиш и отреагировать на неё должным образом. TCA8418 распознает нажатие Ctrl-Alt-Del, если одновременно были нажаты кнопки 1, 11 и 21. Эти кнопки связаны со значениями клавиш, перечисленных в Key Event Table. Обратите внимание, что эта комбинация кнопок, которая вызывает прерывание CAD, не настраивается, так что для неё обязательно назначаются кнопки 1, 11 и 21. Для дополнительной информации см. секцию "CAD Interrupt Errata". Выход прерывания (ножка ~INT). По любому нарастанию или спаду уровня на ножке порта, настроенного в режим ввода, будет сгенерировано прерывание. После времени tiv сигнал ~INT становится достоверным. Сброс схемы прерывания достигается, когда данные на порте меняются на свое исходное состояние, или когда были прочитаны данные порта, который сгенерировал прерывание. Сброс происходит в режиме считывания на бите подтверждения (ACK) или на бите отсутствия подтверждения (NACK) после переднего фронта сигнала SCL. Прерывания, которые возникли в момента тактового импульса бита ACK или NACK, могут быть потеряны (или быть очень короткими по длительности) из-за сброса прерывания во время этого импульса. Каждое изменение уровня I/O после сброса прерывания детектируется и передается как ~INT. Чтение или запись в другое устройство не влияет на схему прерывания, и ножка, сконфигурированная как выход, не может генерировать прерывание. Перевод ножки I/O из режима выхода в режим входа может вызвать ложное прерывание, если состояние вывода не соответствует содержимому регистра входа порта. Ножка выхода ~INT реализована как открытый сток, и требует верхнего подтягивающего резистора (pull-up) на шину питания VCC, в зависимости от приложения. Если сигнал ~INT подается обратно на хост, который предоставляет сигнал SCL для TCA8418, то ножка ~INT должна быть подтянута к VCC. Если нет, то ножка ~INT может быть подтянута к VCC. Конфигурирование прерывания 50 мкс. TCA8418 предоставляет возможность снять сигнал прерываний через 50 мкс, в то время как присутствует не обработанное прерывание. Когда бит INT_CFG в регистре 0x01 установлен, любая попытка очистить бит прерывания, когда ножка прерывания уже установлена, приведет к снятию прерывания через 50 мкс. Когда бит INT_CFG очищен ~INT остается установленным, если хост пытается очистить прерывание. Эта функция обычно полезна при разработке firmware хоста и приложений, обрабатывающих прерывания по перепаду. [Функциональные режимы TCA8418] Power-On Reset (POR). Когда подается питание на VCC (напряжение на VCC нарастает, начинаясь от 0V), внутренняя схема сброса по питанию (power-on reset) удерживает TCA8418 в состоянии сброса, пока уровень VCC не достигнет VPORR. В этот момент состояние сброса освобождается, и регистры TCA8418 и машина состояния I2C/SMBus инициализируются в свои значения по умолчанию. После этого VCC должно опуститься ниже VPORF и подняться опять до рабочего напряжения, чтобы произошел новый цикл сброса по питанию. См. секцию "Рекомендации по источнику питания" для дополнительной информации по требованиям к сбросу по питанию. Powered (Key Scan Mode). TCA8418 может использоваться для чтения уровня GPI от одиночных кнопок, или может быть сконфигурирована в режиме сканирования матрицы кнопок. В режиме сканирования существует 2 режима работы - Idle Key Scan Mode и Active Key Scan Mode. Idle Key Scan Mode. Как только TCA8418 была сконфигурирована на матрицу кнопок, она входит в режим ожидания (idle mode) когда не была нажата ни одна из кнопок. Все столбцы, сконфигурированпые как часть матрицы клавиатуры, переводятся как выходы в уровень лог. 0, и все строки, сконфигурированные как часть той же матрицы, настраиваются как входы, с разешенными внутренними pullup-резисторами. Во время idle mode внутренний генератор выключается, так что потребляемая мощность от источника питания становится очень малой. В этом состоянии клавиатура ожидает нажатие на кнопку в матрице. Active Key Scan Mode. Когда контроллер TCA8418 находится в режиме idle key scan, он ожидает нажатия на кнопку. Как только кнопка в матрице была нажата, низкий уровень на входе строки (ROW), соответсвующем кнопке, разбудит внутренний генератор, и TCA8418 перейдет в active key scan mode. В этот момент TCA8418 начнет выполнять алгоритм сканирования клавиатуры, чтобы определить какая кнопка нажата, и этот же генератор используется для алгоритма подавлеия дребезга контактов (debouncing). Когда все кнопки отпущены, TCA8418 возвратится в idle key scan mode. [Программирование] TCA8418 снабжен стандартным интерфейсом I2C, и работает как подчиненное (slave) устройство под управлением главного устройства шины I2C (микроконтроллер хоста, устройство master I2C). Через I2C контроллер TCA8418 конфигурируется, и может быть прочитано его состояние. Каждое slave-устройство на шине I2C имеет свой определенный адрес, чтобы можно было обращаться к каждому из устройств на шине I2C по отдельности (к одной шине I2C может быть подключено несколько slave-устройств). Физически интерфейс I2C состоит из 2 сигналов - последовательные такты (SCL) и последовательные данные (SDA). Оба этих сигнала должны быть подтянуты к уровню питания VCC через pull-up резисторы. Номинал этих резисторов определяется паразитной емкостью сигналов I2C и скоростью обмена по шине (для дополнительной информации по вычислению номиналов резисторов подтяжки см. даташит SLVA689 [2]). Передача данных может быть инициирована только когда шина находится в состоянии ожидания (idle). Состояние idle шины определено как одновременное нахождение уровней SDA и SCL в лог. 1, когда они установились в лог. 1 после сигнала STOP. Для доступа устройства master к устройству slave выполняется следующая общая процедура. 1. Если master должен послать данные к slave: – Master генерирует сигнал START и обращается к определенному slave передачей уникального адреса. 2. Если master должен получить (прочитать) данные из slave: – Master генерирует сигнал START и обращается к определенному slave передачей уникального адреса. Рис. 21. Определение для сигналов START и STOP. Транзакции шины. Данные должны бтыь переданы в slave-устройства и приняты от них путем записи или чтения их соответствующих регистров. Регистры можно рассматривать как ячейки памяти slave, в которых содержится информация - либо конфигурация, либо какая-то информация, которая нужна устройству master. Устройство master должен записать информацию в эти регистры, чтобы инструктировать slave-устройство на выполнение определенной задачи. Хотя наличие регистров - обычное дело для slave-устройств I2C, следует отметить, что не все slave-устройства I2C снабжены регистрами. Некоторое очень простые, и представляют только 1 регистр, который может быть записан напрямую отправкой данных после отправки slave-адреса I2C, в этом случае специальная адресация целевого регистра не нужна. Примером такого однорегистрового устройства может служить 8-битный мультиплексор, управляемый командами I2C, или электронный потенциометр. Рис. 22. Транзакция на шине I2C (передача потока бит). Операция записи. Для записи по шине I2C, устройство master отправит сигнал START далее slave-адрес вместе с последним его битом, установленным в 0 (так называемый R/W бит, его 0 обозначает начало операции записи). После этого slave посылает в ответ бит подтверждения ACK, и master затем отправит адрес нужного регистра, куда он хочет записать данные. Устройство slave снова выдаст в ответ бит ACK, давая понять устройству master, что оно готово к приему записываемых данных. После этого master начнет передачу данных регистра для slave, пока не отправит все необходимые данные (которые иногда могут быть только одним байтом). После этого master завершит передачу генерацией сигнала STOP. На рис. 23 и 24 показан пример записи одного байта в регистр. Рис. 23. Запись в регистр. Рис. 24. Запись в регистр конфигурации (01h). Операция чтения. Чтение организовано похоже на запись, но здесь необходимы дополнительные шаги. Чтобы прочитать из slave, устройство master сначала должно указать для slave, какой регистр должен быть прочитан. Это осуществляется предварительной операцией записи адреса нужного регистра (отправка slave-адреса с битом R/W = 0, затем отправка адреса читаемого регистра). После того, как slave подтвердит ACK адрес регистра, устройство master снова пошлет сигнал START (так называемый сигнал REPEATED START), затем slave-адрес, но здесь бит R/W = 1 (обозначает операцию чтения). Устройство slave подтвердит сигналом ACK запрос на чтение, master освободит сигнал SDA и будет генерировать такты SCL, по которым устройство slave будет последовательно передавать данные запрошенного регистра. Во время этой части транзакции устройства меняются местами - master становится приемником и подтверждает кадр данных сигналом ACK, а slave становится передатчиком данных, и будет передавать данные по тактам SCL до тех пор, пока master не остановит передачу сигналами NACK и STOP. Рис. 25 показывает пример чтения одного байта из регистра slave-устройства. Рис. 25. Чтение регистра. Микросхема контроллера TCA8418 отвечает на slave-адрес 0x34 (0110100), как показано в таблице 8. Таблица 8. Адрес устройства TCA8418.
Как уже упоминалось, последний бит slave-адреса определяет операцию (чтение или запись). Лог. 1 выбирает чтение (Read), лог. 0 запись (так называемый R/W бит). [Карта регистров] Control Register и Command Byte. За успешным подтверждением байта адреса master посылает байт команды (Command Byte), который сохраняется в регистре управления (Control Register) микросхемы TCA8418. Command Byte показывает, какой регистр будет обновлен информацией. Все регистры могут быть записаны и прочитаны устройством master (обычно это микроконтроллер). Таблица 9 показывает все регистры и их краткое описание. Значение по умолчанию у всех регистров равно 0. Таблица 9. Описание регистров TCA8418.
AI (бит 7): разрешает автоинкремент адреса для операций чтения и записи. 0 автоинкремент запрещен, 1 разрешен. Бит 7 (AI) в этом регистре используется для определения режима программирования. Если он равен 0, то все записываемые байты данных будут записаны в тот регистр, который определил байт команды. Если он равен 1, то значение байта команды автоматически инкрементируется с каждым записанным байтом, и следующий байт данных будет записан в соответствующий регистр. Регистры будут записаны в последовательности, показанной в таблице 9. Как только был записан последний регистр GPIO_PULL3 (0x2E), байт команды снова станет равным 0. Регистры 0 и 2F зарезервированы, и байт команды, который соответствует этим регистрам, не подтверждается контроллером TCA8418. GPI_E_CFG (бит 6): конфигурация режима событий GPI. 0 события GPI отслеживаются, когда клавиатура заблокирована, 1 не отслеживаются. OVR_FLOW_M (бит 5): Overflow mode. 0 задает, что данные нажатий/отпусканий при переполнении FIFO будут теряться. 1 задает, что при переполнении данные FIFO будут смещаться: старые самые данные будут удалены, а новые добавлены. INT_CFG (бит 4): конфигурация прерывания. 0 прерывание хоста остается выставленным (ножка ~INT в состоянии лог. 0), если хост пытается очистить прерывание, когда все еще ожидают обработки нажатия кнопок, отпускания кнопок или прерывания GPI. 1 прерывание хоста снимается через 50 мкс, и переустановится с ожидающими прерываниями. OVR_FLOW_IEN (бит 3): разрешение прерывания при переполнении FIFO. 0 запрещено, сигнал ~INT не будет выставлен, если произошло прерывание FIFO. 1 разрешено, ~INT активируется при переполнении FIFO. K_LCK_IEN (бит 2): Keypad lock interrupt enable. 0 запрещено, ~INT не активируется после корректной последовательности нажатий разблокировки. 1 разрешено, ~INT активируется после корректной последовательности нажатий разблокировки. Keypad lock interrupt enable определяет, будет ли активна ножка прерываний, когда установлен бит прерывания блокировки клавитатуры (бит key lock interrupt, см. описание Interrupt Status Register). GPI_IEN (бит 1): разрешение прерывания GPI для хоста. 0 запрещено, ~INT не активируется при изменении уровня GPI. 1 разрешено, ~INT активируется при изменении уровня GPI. KE_IEN (бит 0): разрешение прерывания от событий кнопок для хоста. 0 запрещено, ~INT не активируется при событии кнопки (нажатие или отпускание). 1 разрешено, ~INT активируется при событии кнопки. Регистр INT_STAT используется для проверки, какое именно прерывание вызвало активацию ножки ~INT. Если соответствующий биты разрешения прерывания установлены в Configuration Register, то значение 1 в соответствующем бите регистра INT_STAT приведет к переводу сигнала ~INT в лог. 0. Исключение из этого составляет бит CAD_INT, который выставит активный уровень лог. 0 на выводе CAD_INT для корпусов YFP. Чтение этого регистра возвратит типы произошедших прерываний. Запись 1 в бит регистра INT_STAT очистит его, но бит не очистится, если в FIFO все еще находятся не прочитанные данные (например, не прочитанные события кнопок).
Все перечисленные ниже флаги прерывания установятся автоматически при возникновении соответствующего события. Для очистки флага нужно в него записать 1, запись 0 не оказывает никакого действия. N/A не используемые биты, они всегда равны 0. CAD_INT (бит 4): CTRL-ALT-DEL key sequence status, статус последовательности клавиш CTRL-ALT-DEL. Лог. 1 означает, что было обнаружено нажатие этих клавиш. OVR_FLOW_INT (бит 3): Overflow interrupt status. Установится, если было обнаружено переполнение FIFO. K_LCK_INT (бит 2): Keypad lock interrupt status. Прерывание для хоста - установится, когда началась последовательность keypad lock. GPI_INT (бит 1): GPI interrupt status. Установится, когда была обнаружена активность на входах GPI. K_INT (бит 0): Key events interrupt status. Установится, если было обнаружено событие клавиатуры.
N/A не используемый бит, он всегда равен 0. K_LCK_EN (бит 6): Key lock enable, разрешение блокировки клавиатуры. 0 блокировка запрещена, запись в этот бит 0 программно разблокирует клавиатуру. 1 блокировка разрешена, запись 1 в этот бит блокирует клавиатуру. LCK2 (бит 5): Keypad lock status, состояние блокировки клавиатуры. 0 разблокировано (если LCK1 также 0). 1 заблокировано (если LCK1 также 1). LCK1 (бит 4): Keypad lock status, состояние блокировки клавиатуры. 0 разблокировано (если LCK2 также 0). 1 заблокировано (если LCK2 также 1). KEC3 .. KEC0 (биты 3 .. 0): Key event count, счетчик событий клавиатуры. KEC[3:0] показывает, сколько событий клавиатуры находится в FIFO. Например, KEC[3:0] = 0b0000 = 0 событий, KEC[3:0] = 0b0001 = 1 событие, и KEC[3:0] = 0b1010 = 10 событий. При возникновении событий (нажатие или отпускание кнопки) счетчик увеличивает свое значение.
Примечание: показан только регистр KEY_EVENT_A. Регистры KEY_EVENT_A - KEY_EVENT_J работают как стек FIFO, который может хранить в себе до 10 событий клавиш - нажатий и отпусканий. Пользователь предварительно проверяет регистр INT_STAT, чтобы узнать, были ли какие-либо прерывания. Если были, то считывается регистр блокировки и счетчика событий (KEY_LCK_EC, адрес 0x03), чтобы увидеть, сколько прерываний было сохранено. Затем INT_STAT снова прочитывается, чтобы убедиться, что больше новых прерываний не было. Регистр KEY_EVENT_A затем считывается столько раз, сколько было прерываний (количество прерываний было считано из счетчика событий). При каждом чтении регистра KEY_EVENT_A счетчик в регистре KEY_LCK_EC уменьшается на 1. Данные в стеке FIFO также смещаются в сторону регистра KEY_EVENT_A на одну позицию (в направлении от KEY_EVENT_J к KEY_EVENT_A). Как только все события были прочитаны, счетчик событий становится нулем, и бит KE_INT может быть очищен записью в него лог. 1. В регистре KEY_EVENT_A биты KEA[6:0] показывают номер клавиши, которая была нажата или отпущена. Значение от 0 до 80 показывают, какая клавиша в матрице была нажата или отпущена. Значения от 97 до 114 соответствуют событиям GPI. Старший бит KEA[7] показывает, какое именно событие клавиши (с кодом KEA[6:0]) произошло - отпускание или нажатие. 0 означает отпускание клавиши, 1 нажатие (чтобы получить код нажатой клавиши, старший бит при чтении может быть очищен). Например, были нажаты 3 клавиши, и тогда в FIFO будет записано 6 байт, 3 нажатия и 3 отпускания. При чтении каждого слова будет понятно, что оно означает - нажатие или отпускание, и какая это была клавиша. Нажатия наподобие CTRL+ALT+DEL сохраняются как 3 одновременных нажатия. Нажатия и отпускания клавиш генерируют события клавиатуры (key event interrupts). Бит KE_INT не очистится и ножка ~INT не будет деактивирована до тех пор, пока FIFO не будет очищен от всех событий. Можно прочитать все регистры от KEY_EVENT_A до KEY_EVENT_J, однако для правильной работы по принципу FIFO (First Input First Output, первым вошел - первым вышел) пользователю нужно считывать только регистр KEY_EVENT_A. Как только все события в FIFO были прочитаны, регистр KEY_EVENT_A будет считываться как 0.
KL[2:0]: эти биты предназначены для таймера отсчета времени от Lock1 до Lock2. KL[7:3]: эти биты для таймера маски прерывания (interrupt mask timer). Значение таймера KL[2:0] должно быть не нулевым для разрешения блокировки клавиатуры. Значение KL[2:0] определяет количество секунд, прошедшее между нажатием клавиш разблокировки 2 и 1 (unlock key 2 нажимается после unlock key 1), это нужно для отслеживания таймаута последовательности разблокировки клавиатуры. Более подробно про блокировку и разблокировку клавиатуры см. выше секцию "Keypad Lock/Unlock". Если таймер маскирования прерывания блокировки клавиатуры (keypad lock interrupt mask timer) не равен 0, будет сгенерировано событие кнопки (key event interrupt, K_INT) только на первом нажатии на любую кнопку. Второе прерывание (K_LCK_IN) будет сгенерировано только когда была выполнена корректная последовательность разблокировки клавиатуры (unlock sequence). Если таймаут любого из таймеров KL[2:0] или KL[7:3] истек, то машина состояния блокировки сбрасывается в исходное положение. Когда таймер маски прерывания запрещен (0), прерывание блокировки кнопок будет генерироваться только когда была выполнена корректная последовательность разблокировки. Таймер маски прерывания должен быть установлен на время, которое отводится на интервал включенного состояния экрана LCD. Для дополнительной информации см. выше секцию "Keypad Lock Interrupt Mask Timer".
UK1[6:0] содержит номер кнопки, используемой для клавиши разблокировки 1. UK2[6:0] содержит номер кнопки, используемой для клавиши разблокировки 2. 0 в любом из этих регистров запретит работу функции разблокировки. Регистры GPIO_INT_STAT1, GPIO_INT_STAT2, GPIO_INT_STAT3 используются для проверки статуса прерывания ножек GPIO. Если установлен бит GPI_INT в регистре INT_STAT, то ножка GPI, которая установила это прерывание, будет помечена 1 в соответствующей таблице. Чтобы очистить бит GPI_INT, значение всех этих регистров должно быть равно 0x00. Чтение регистра GPIO_INT_STAT1 - GPIO_INT_STAT3 автоматически очистит его.
Эти регистры показывают состояние GPIO, когда они считываются в режиме входов и выходов. Для очистки их нужно прочитать дважды.
Эти регистры содержат данные GPIO для записи в выходной драйвер. На входы эти данные не влияют. Данные установят лог. уровень для соответствующей ножки выхода GPIO.
Эти регистры разрешают прерывания (значением 1 бита) или запрещают их (значением 0 бита) только для входов (GPI). Если вход, настроенный как GPI, поменяет свой уровень, то установится бит GPI_INT в регистре INT_STAT. Значение 0 в любом из используемых бит запретит для соответствующей ножки возможность генерации прерывания, когда состояние её входа поменялось. Это значение по умолчанию. Значение 1 в любом из используемых бит разрешит для соответствующей ножки возможность генерации прерывания, когда состояние её входа поменялось.
Значение 0 в любом из используемых бит переведет соответствующую ножку в режим GPIO, это состояние по умолчанию. Ножка в режиме GPIO может быть сконфигурирована либо как вход, либо как выход, путем программирования регистров GPIO_DIR1-3. Значение 1 в любом из используемых бит переведет соответствующую ножку в режим сканирования, и она будет работать в составе клавиатурной матрицы. В результате ножка будет работать как разряд строки или столбца (это уже не настраивается).
Значение 0 в любом из используемых бит показывает, что ножка не принимает участие в регистрации событий FIFO. Это значение по умолчанию. Значение 1 в любом из используемых бит означает, что соответствующая ножка, настроенная на вход (GPI), будет регистрировать события для FIFO. Тогда эта ножка может использоваться для прямого подключения кнопки и записи в FIFO событий нажатия и отпускания. Для дополнительной информации см. выше секцию "Key Event Table".
Значение 0 в любом из используемых бит установит соответствующую ножку как вход. Это значение по умолчанию. Значение 1 в любом из используемых бит установит соответствующую ножку как выход.
Значение 0 в любом из используемых бит показывает, что прерывание будет генерироваться переходах от 1 к 0 и от 0 к 1 на входах, когда соответствующая ножка находится в режиме GPIO. Это значение по умолчанию. Значение 0 в любом из используемых бит показывает, что прерывание будет генерироваться при переходе от 0 к 1 и при уровне 1 на входах, когда соответствующая ножка находится в режиме GPIO.
Это регистры для запрета подавления дребезга, их значения применимы только для тех ножек, которые сконфигурированы как входы. Значение 0 в любом из используемых бит разрешает подавление дребезга, это значение по умолчанию. Значение 1 для бита запрещает подавление дребезга.
Запрет подавления дребезга дает одинаковый эффект и для режима GPI входов, и для строк, когда они работают в составе сканируемой матрицы клавиатуры. У входа ~RESET всегда присутствует время подавления дребезга 50 мкс. Интервал подавления дребезга контактов (который составляет 50 мкс) необходим для того, чтобы лог. уровень на входе стал стабильным. Время подавления дребезга для клавиатуры применимо только для столбцов. Минимальное время составляет 25 мс. Все столбцы сканируются один раз каждые 25 мс, чтобы определить нажатия кнопок. Требуется 2 полных сканирования, чтобы определить, была ли нажата любая кнопка. Если первое сканирование было выполнено сразу после нажатия, то для определение этого нажатия займет по времени 25 мс. Если первое сканирование произошло намного позже нажатия клавиши, то определение этого нажатия займет по времени 40 мс. Эти регистры разрешают или запрещают внутренние верхние подтягивающие резисторы (pull-up) для входов. Значение 0 бита разрешает pullup-резистор, это значение по умолчанию. Значение бита 1 запрещает pullup-резистор.
[CAD Interrupt Errata] В регистре состояния прерываний, (Interrupt Status Register, INT_STAT с адресом 0x02, см. выше соответствующую врезку), бит 4 CAD_INT используется для детектирования последовательности нажатия клавиш CTRL-ALT-DEL. Некоторые последовательности нажатий клавиш установят бит CAD_INT ошибочно. Следующие комбинации нажатий клавиш приведут к неправильной установке CAD_INT: 1 + 11 Для этой проблемы не существует способа избежать ошибочного детектирования прерывания CAD_INT. [Overflow Errata] TCA8418 позволяет обнаружить переполнение 10-байтного FIFO для событий нажатия и отпускания клавиш. Чтобы разрешить обнаружение переполнения, оба бита - бит 3 (OVR_FLOW_IEN) и бит 5 (OVR_FLOW_M) в регистре конфигурации (см. выше врезку "Configuration Register (0x01)") должны быть установлены в лог. 1. Если установлен только бит 3 (OVR_FLOW_IEN), то прерывание переполнения генерироваться не будет. Способ обхода проблемы: стек FIFO должен считываться по мере появления в нем новой информации. Поскольку прерывания переполнения будут инициированы, когда стек начал переполняться, это будет означать, что некоторые данные были потеряны. [Рекомендации по применению] Ghosting (двоение). Этим термином называют нежелательное обнаружение дополнительных клавиш в случае некоторых одновременных нажатий (обнаружение дополнительного, не существующего нажатия), связанное с расположением клавиш в матрице. Несмотря на то, что TCA8418 поддерживает обнаружение нескольких одновременных нажатий кнопок в матрице, для приложений, требующих определения заданных одновременных комбинаций нажатий (наподобие Ctrl-Alt-Del) требуется уделить особое внимание. Необходимо гарантировать, чтобы эти кнопки в матрице занимали особое положение. Для примера рассмотрим матрицу 3x4 (3 столбца C0-C2 и 4 строки R0-R3), см. рис. 26. Чтобы избежать ситуации ghosting для ожидаемого одновременного нажатия трех кнопок, необходимо эти три кнопки разместить на разных строках и столбцах. Рис. 26. Пример клавиатурной матрицы. Для матрицы клавиатуры на рис. 26 используются выводы ROW0-ROW3 для строк и COL0-COL2 для столбцов. Все строки (ROWx) сконфигурированы как входы с pullup-резисторами. Столбцы (COLx) сконфигурированы как выходы, управляемые лог. 0. Когда происходит нажатие на кнопку, входы ROWx подтягиваются к лог. 0, информируя тем самым TCA8418, что была нажата кнопка, и тогда TCA8418 запускает алгоритм сканирования матрицы. При выполнении этого алгоритма TCA8418 будет сдвигать лог. 0 по столбцам, в любой момент времени выдавая лог. 0 только на 1 столбец. При подаче лог. 0 на каждый столбец TCA8418 считывает уровни на входах строк ROWx, чтобы определить, какая из кнопок в столбце была нажата. На рис. 27 приведен пример ситуации ghosting, когда были нажаты только кнопки, закрашенные красным, но дополнительно обнаружилось, что якобы была нажата четвертая кнопка, которая закрашена желтым. Рис. 27. Некорректно считываемая комбинация одновременного нажатия 3 клавиш. Очевидно, что одновременное нажатие кнопок 1, 2 и 11 создает ghosting-проблему. Поскольку R1 оказывается подтянутым к GND кнопкой 1 (через кнопку 2, когда на C1 был выдан лог. 0), когда C1 переводится в 0, TCA8418 увидит лог. 0 на обоих строках R0 и R1. Это ошибочно приведет к обнаружению нажатия на кнопке 12 (она подкрашена желтым). Причина ошибки в том, что клавиатурные матрицы замыкают друг на друга столбцы и строки. Когда C1 переведен в 0, этот 0 передается на R0 через кнопку 2. Нажатая кнопка 1 также замыкает C0 на GND. Нажатая кнопка 11 тогда замкнет R1 на C0. В результате этого процесса R1 замкнется на C1, и получается ghosting для кнопки 12. Матрицы клавиатуры могут поддерживать корректное обнаружение одновременных нажатий, если был правильно произведен выбор положения этих одновременных нажатий в матрице. На рис. 28 мы видим ситуацию, когда обнаружение комбинации 3 одновременных нажатий срабатывает ожидаемо. Здесь нажаты кнопки 1, 11 и 21, и при этом ситуация ghosting не возникает. Комбинация кнопок 1, 11 и 21 также фиксировано задана для прерывания Ctrl-Alt-Del, для дополнительной информации см. выше секцию "Поддержка Control-Alt-Delete". Рис. 28. Корректное распознавание комбинации нажатия 3 кнопок. Рис. 29 показывает типичное приложение для TCA8418 - стандартная цифровая клавиатура из 12 кнопок (цифры от 0 до 9, кнопки * и #). Рис. 29. Пример реализации матрицы цифровой клавиатуры. Разработчику следует учесть следующие моменты для своей системы на контроллере клавиатуры TCA8418. • Необходимое количество клавиш. Первые шаги в разработке массива клавиш - определение желаемой компоновки клавиатуры, отображение каждой кнопки на подходящее значение, которое будет записываться в FIFO. Для этого примера не предполагается, что будут использоваться другие выводы TCA8418, не входящие в матрицу. Предполагается следующее желаемое поведение: • В FIFO должны добавляться события нажатия и отпускания всех кнопок в матрице. Поскольку TCA8418 сообщает о нажатиях клавиш в соответствии со значениями в своей внутренней таблица (key value table), важно заранее знать, каковы будут эти значения для каждой из кнопки в матрице. В соответствии с Key Event Table нажатия клавиш назначаются, как показано в таблице 12. Таблица 12. Коды, назначенные событиям клавиш в матрице.
Схема для этой клавиатуры показана на рис. 30 вместе со значениями кодов клавиш. Обратите внимание на отсутствие резисторов подтяжки, потому что используются внутренние резисторы подтяжки TCA8418. Рис. 30. Схема матрицы клавиатуры. Конфигурация регистров. Следующий шаг в разработке клавиатуры - конфигурирование соответствующих регистров TCA8418. Регистры должны быть модифицированы, как показано в следующей таблице.
Рис. 31. Сигнал прерывания ~INT при начальном нажатии на кнопку. Рис. 32. Диаграммы сигналов второго сканирования. [Рекомендации по источнику питания] В случае сбоя или повреждения данных контроллер TCA8418 может быть сброшен в состояние по умолчанию с использованием функции сброса по питанию (power-on reset, POR). Power-on reset требует, чтобы устройство прошло весь цикл спада и нарастания уровня напряжения питания, чтобы произошел полный сброс. Этот сброс также произойдет, когда устройство только что получило питание при первом включении. Два типа сброса power-on reset показаны на рис. 33 и 34. Рис. 33. VCC понизилось до уровня ниже 0.2V или до 0V, и затем возросло до VCC. Рис. 34. VCC понизилось до уровня ниже порога POR, и затем возросло обратно до VCC. Таблица 13 показывает параметры power-on reset для обоих таких типов сброса. Таблица 13. Рекомендуемые последовательности подачи питания(1).
Примечание (1): значения показаны для температуре окружающей среды TA = –40°C .. 85°C (если не указано нечто иное). Сбои в блоке питания также могут повлиять на работоспособность TCA8418 при формировании сброса по питанию. Ширина (VCC_GW) и высота (VCC_GH) импульса провала зависят друг от друга. Блокирующая емкость, импеданс источника и импеданс устройства являются факторами, влияющими на характеристики сброса по питанию. На рис. 35 и в таблице 13 представлена дополнительная информация по том, как измерять эти характеристики. Рис. 35. Ширина и высота провала по питанию. VPOR критично для формирования сброса по питанию. Это уровень напряжения, при котором состояние сброса освобождается, и все регистры вместе с машиной состояния I2C/SMBus инициализируются в значения по умолчанию. Значение VPOR отличается в зависимости от того, понижается ли VCC, или же нарастает от 0V. Рис. 36 и таблица 13 более подробно описывают эти характеристики. Рис. 36. VPOR. Чтобы правильно работал сброс по питанию, соблюдайте вышеперечисленные рекомендации по параметрам, показанные на рисунках 33-36 и в таблице 13. Рекомендации по разводке печатной платы, получение поддержки, информацию по закупке, размерам корпусов и посадочных мест TCA8418 см. в даташите [1]. [Пример работы с TCA8418] Этот пример скетча основан на библиотеке [4]. #include < Wire.h>
#include < tca8418.h>
KEYS Keypad; volatile bool KeyInt=false; void KeyISR(void) { // Обработчик прерывания клавиатурной матрицы KeyInt = true; } void setup() { Serial.begin(9600); Wire.begin(); // Конфигурирование матрицы 4x4 на COL0-COL3, ROW0-ROW3, // и разрешение прерываний: Keypad.begin(ROW0|ROW1|ROW2|ROW3, COL0|COL1|COL2|COL3, CFG_KE_IEN|CFG_OVR_FLOW_IEN|CFG_INT_CFG|CFG_OVR_FLOW_M); // Первый аргумент это номер порта Arduino для подключения // к сигналу ~INT от TCA8418, второй аргумент это адрес ISR: Keypad.enableInterrupt(2, KeyISR); } void loop() { // Проверка флага прерывания и его обработка if(KeyInt) { uint8_t key; // Получение первого кода кнопки из FIFO TCA8418: key=Keypad.readKeypad(); // Печать HEX-кода кнопки ... Serial.print("Keyboard ISR...Key:"); Serial.print((key&0x7F), HEX); // ... и события нажатия или отпускания (по биту 7): if(key & 0x80) { Serial.println(" key down"); } else { Serial.println(" key up"); } KeyInt=false; // Сброс нашего флага прерывания // Очистка флага прерывания в регистре статуса TCA8418: Keypad.clearInterruptStatus(); } // Тут можно вставить другую обработку: ; } [Как реализовать остлеживание автоповтора] Ниже приведен код, где с контроллером TCA8418 реализован автоповтор кнопок при их удержании. Заголовок TCA8418auto.h: #pragma once
#include < stdbool.h>
#include < stdint.h>
#include "FreeRTOS.h"
#include "queue.h"
#define KEY_THREAD_SLEEP_MS 30
#define NO_KEY_PRESS_TIMEOUT_MS 15000
// Состояние регистра:
// I английские буквы, II русские, III цифры и символы
typedef enum { KM1_low = 0, // I KM2_low = 2, // II KM3_low = 4, // III }TKeyMode; // Функциональные действия клавиатуры:
typedef enum { KA_NONE, KA_SHIFT_ONCE, KA_SHIFT_PERMANENT, KA_MENU, KA_ENTER, KA_BACK, KA_DEL, KA_UP, KA_LEFT, KA_RIGHT, KA_DOWN, KA_III, KA_II, KA_I, KA_VOLUME_MINUS, KA_VOLUME_PLUS }TKeyboardAction; // Состояния выдачи больших или маленьких букв:
typedef enum { SHIFT_NONE = 0, // всегда маленькие буквы SHIFT_ONCE, // большая буква 1 раз SHIFT_PERMANENT // большие буквы постоянно }TShiftState; // Состояния отслеживания автоповтора и нажатия SHIFT:
typedef enum { KEYAUTO_NONE = 0, KEYAUTO_PRESS_INIT, KEYAUTO_PRESS_PULSE, KEYAUTO_SHIFT_PRESS_INIT }TKeyAutoState; // Структура, где хранится состояние алгоритма функции
// отслеживания автоповтора AutoRepeatHandler:
typedef struct { uint8_t scancode; TKeyAutoState state; uint32_t counter; }TKeyInfo; extern TKeyboardAction keybaction;
extern TKeyMode km;
extern TShiftState shiftstate;
void keypadtask(void const * argument); Модуль TCA8418auto.c: #include "keyapp.h"
#include "beeper.h"
#include "screenthread.h"
#include "modes.h"
#include "guiapp.h"
#include "editor.h"
#include "TCA8418.h"
static int16_t key_press_timeout = NO_KEY_PRESS_TIMEOUT_MS; // 30 мс TShiftState shiftstate = SHIFT_NONE; static SemaphoreHandle_t keybsem;
static TKeyInfo kinfo = {0, KEYAUTO_NONE, 0}; TKeyboardAction keybaction = KA_NONE; // Обработчик прерывания от ножки ~INT контроллера клавиатуры TCA8418.
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { static BaseType_t xHigherPriorityTaskWoken; xSemaphoreGiveFromISR(keybsem, &xHigherPriorityTaskWoken); } // Таблица перекодировки сканкодов TCA8418 в символы ASCII.
static uint8_t KeyMap[KEYMAP_TOT_KEYS][KEYMAP_TOT_MODES] = { // Регистры: верхний, средний, нижний { 'q', 'Q', 'й', 'Й', '1', '1'}, { 'w', 'W', 'ц', 'Ц', '2', '2'}, { 'e', 'E', 'у', 'У', '3', '3'}, { 'r', 'R', 'к', 'К', '4', '4'}, { 't', 'T', 'е', 'Е', '5', '5'}, { 'y', 'Y', 'н', 'Н', '6', '6'}, { 'u', 'U', 'г', 'Г', '7', '7'}, { 'i', 'I', 'ш', 'Ш', '8', '8'}, { 'o', 'O', 'щ', 'Щ', '9', '9'}, { 'p', 'P', 'з', 'З', '0', '0'}, { 'a', 'A', 'ф', 'Ф', '?', '?'}, { 's', 'S', 'ы', 'Ы', '!', '!'}, { 'd', 'D', 'в', 'В', '$', '$'}, { 'f', 'F', 'а', 'А', '#', '#'}, { 'g', 'G', 'п', 'П', '%', '%'}, { 'h', 'H', 'р', 'Р', '(', '('}, { 'j', 'J', 'о', 'О', ')', ')'}, { 'k', 'K', 'л', 'Л', '+', '+'}, { 'l', 'L', 'д', 'Д', '-', '-'}, { '\a', '\a', '\a', '\a', '\a', '\a'}, // TX { 'z', 'Z', 'я', 'Я', '`', '`'}, { 'x', 'X', 'ч', 'Ч', ';', ';'}, { 'c', 'C', 'с', 'С', ':', ':'}, { 'v', 'V', 'м', 'М', '@', '@'}, { 'b', 'B', 'и', 'И', '"', '"'}, { 'n', 'N', 'т', 'Т', '/', '/'}, { 'm', 'M', 'ь', 'Ь', '< ', '< '}, { '.', '.', 'х', 'х', 'ъ', 'Ъ'}, { ',', ',', 'ж', 'Ж', '*', '*'}, { '&', '&', 'э', 'Э', 'ё', 'Ё'}, { ' ', ' ', ' ', ' ', ' ', ' '}, { '\a', '\a', '\a', '\a', '\a', '\a'}, // M1 { '\a', '\a', '\a', '\a', '\a', '\a'}, // M2 { '\a', '\a', '\a', '\a', '\a', '\a'}, // M3 { '\a', '\a', '\a', '\a', '\a', '\a'}, // SHIFT { '\a', '\a', '\a', '\a', '\a', '\a'}, // MENU { '\a', '\a', '\a', '\a', '\a', '\a'}, // ENTER }; // Подпрограмма перекодировки сканкодов TCA8418.
static char fullkeysdecode (uint8_t scancode) { char key = 0; switch(scancode) { case 0xC5: keybaction = KA_MENU; break; case 0xC6: // ENTER keybaction = KA_ENTER; break; case 0xC7: // BACK keybaction = KA_BACK; break; case 0xC8: // DEL keybaction = KA_DEL; break; case 0xC9: // UP keybaction = KA_UP; break; case 0xCA: // LEFT keybaction = KA_LEFT; break; case 0xCB: // RIGHT keybaction = KA_RIGHT; break; case 0xCC: // DOWN keybaction = KA_DOWN; break; case 0xCE: // mode III km = KM3_low; keybaction = KA_III; break; case 0xCF: // mode II km = KM2_low; keybaction = KA_II; break; case 0xBA: case 0xBB: // Кнопки регулировки громкости: keybaction = (TKeyboardAction)(KA_VOLUME_MINUS + (scancode - 0xBA)); break; case 0xD0: // mode I km = KM1_low; keybaction = KA_I; break; default: // Выдача символа в зависимости от регистра и состояния SHIFT: if (SHIFT_ONCE==shiftstate) { key = KeyMap[scancode-0x9F][km+1]; shiftstate = SHIFT_NONE; UpdateAtScreen(SCR_UPDATE_RUS_ENG); } else if (SHIFT_PERMANENT==shiftstate) key = KeyMap[scancode-0x9F][km+1]; else key = KeyMap[scancode-0x9F][km]; } return key; } // Отслеживание времени, сколько не было нажатий на клавиатуре.
static bool KeyTimeout (void) { bool result = false; switch(appmode) { case MODE_MAIN_MENU: case MODE_MENU_SETTINGS: key_press_timeout -= KEY_THREAD_SLEEP_MS; if (key_press_timeout < 0) result = true; break; default: key_press_timeout = NO_KEY_PRESS_TIMEOUT_MS; } return result; } // Инициализация I2C STM32 в режиме master для работы с контроллером
// клавиатуры TCA8418.
static void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; // Для режима master I2C hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) HALerrorHandler(__FILE__, __LINE__); if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK) HALerrorHandler(__FILE__, __LINE__); if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK) HALerrorHandler(__FILE__, __LINE__); } // Если на кнопке работает автоповтор, то вернет true.
static bool IsRepeatKey (uint8_t scancode) { switch (scancode) { case 0xC4: // SHIFT case 0xC5: // MENU case 0xC6: // ENTER case 0xC7: // BACK case 0xC8: // DEL case 0xCE: // III case 0xCF: // II case 0xD0: // I return false; default: return true; } } // Функция, которая реализует работу автоповтора и поведение кнопки
// SHIFT. Чтобы отслеживался автоповтор, эта функция должна вызываться
// с периодом порядка 30 мс (в этом случае на входе scancode == 0),
// либо в любой момент получения сканкода от TCA8418 (в этом случае
// на входе 8-битный сканкод, лог. 1 в старшем разряде которого
// означает нажатие, лог. 0 отпускание). На выходе также выдает сканкод.
//
// Если кнопка удерживалась дольше 1 секунды, то функция автоматически
// генерирует выдачу сканкодов этой кнопки каждые 30 мс для регулировки
// громкости, и (30*8) мс для символьных кнопок. Если действие на выходе
// не требуется, то на выходе возвращает 0.
static uint8_t AutoRepeatHandler (uint8_t scancode) { bool press = (scancode & 0x80) ? true : false; switch (kinfo.state) { case KEYAUTO_NONE: if (press) { if (IsRepeatKey(scancode)) { kinfo.scancode = scancode; kinfo.counter = 0; kinfo.state = KEYAUTO_PRESS_INIT; } else if (0xC4 == scancode) { kinfo.scancode = scancode; scancode = 0; kinfo.counter = 0; if (MODE_EDIT_TX_MESSAGE == appmode) kinfo.state = KEYAUTO_SHIFT_PRESS_INIT; else kinfo.state = KEYAUTO_NONE; } } else scancode = 0; break; case KEYAUTO_PRESS_INIT: if (0 == scancode) { if (kinfo.counter > 500) { scancode = kinfo.scancode; kinfo.state = KEYAUTO_PRESS_PULSE; } else { kinfo.counter += KEY_THREAD_SLEEP_MS; } } else if (press) { if (IsRepeatKey(scancode)) { kinfo.scancode = scancode; kinfo.counter = 0; } else if (0xC4 == scancode) { kinfo.scancode = scancode; scancode = 0; kinfo.counter = 0; if (MODE_EDIT_TX_MESSAGE == appmode) kinfo.state = KEYAUTO_SHIFT_PRESS_INIT; else kinfo.state = KEYAUTO_NONE; } } else { scancode = 0; kinfo.state = KEYAUTO_NONE; } break; case KEYAUTO_PRESS_PULSE: if (0 == scancode) { kinfo.counter++; if (IsVolumeAction(kinfo.scancode)) { scancode = kinfo.counter % 2 ? kinfo.scancode : 0; } else { scancode = (7 == (kinfo.counter % 8)) ? kinfo.scancode : 0; } } else if (press) { if (IsRepeatKey(scancode)) { kinfo.scancode = scancode; kinfo.counter = 0; } else if (0xC4 == scancode) { kinfo.scancode = scancode; scancode = 0; kinfo.counter = 0; if (MODE_EDIT_TX_MESSAGE == appmode) kinfo.state = KEYAUTO_SHIFT_PRESS_INIT; else kinfo.state = KEYAUTO_NONE; } } else { scancode = 0; kinfo.state = KEYAUTO_NONE; } break; case KEYAUTO_SHIFT_PRESS_INIT: if (0 == scancode) { if (kinfo.counter < 1000) { kinfo.counter += KEY_THREAD_SLEEP_MS; } else { Beep(100); osDelay(100); Beep(100); // Поменять состояние SHIFT "на постоянку". if (SHIFT_PERMANENT == shiftstate) { keybaction = KA_NONE; shiftstate = SHIFT_NONE; UpdateAtScreen(SCR_UPDATE_RUS_ENG); } else { keybaction = KA_SHIFT_PERMANENT; shiftstate = SHIFT_PERMANENT; UpdateAtScreen(SCR_UPDATE_RUS_ENG); } kinfo.scancode = scancode = 0; kinfo.counter = 0; kinfo.state = KEYAUTO_NONE; } } else if (press) { if (IsRepeatKey(scancode)) { kinfo.scancode = scancode; kinfo.counter = 0; if (MODE_EDIT_TX_MESSAGE == appmode) kinfo.state = KEYAUTO_SHIFT_PRESS_INIT; else kinfo.state = KEYAUTO_NONE; } else if (0xC4 == scancode) { kinfo.scancode = scancode; scancode = 0; kinfo.counter = 0; if (MODE_EDIT_TX_MESSAGE == appmode) kinfo.state = KEYAUTO_SHIFT_PRESS_INIT; else kinfo.state = KEYAUTO_NONE; } } else { if (scancode = kinfo.scancode) { // Поменять состояние SHIFT однократно. Beep(100); if (SHIFT_PERMANENT == shiftstate || (SHIFT_ONCE == shiftstate)) shiftstate = SHIFT_NONE; else { shiftstate = SHIFT_ONCE; keybaction = KA_SHIFT_ONCE; } UpdateAtScreen(SCR_UPDATE_RUS_ENG); } kinfo.scancode = scancode = 0; kinfo.counter = 0; kinfo.state = KEYAUTO_NONE; } break; } return scancode; } // Поток, который обрабатывает клавиатурные нажатия:
void keypadtask(void const * argument) { uint8_t scancode; keybsem = xSemaphoreCreateBinary(); if( NULL == keybsem ) FreeRTOSerrorHandler(__FILE__, __LINE__); MX_I2C1_Init(); TCA8418_configure(); for(;;) { // Цикл прокручивается каждый раз, когда контроллер TCA8418 // выдает сканкод, либо каждые KEY_THREAD_SLEEP_MS миллисекунд. if (pdTRUE == xSemaphoreTake(keybsem, KEY_THREAD_SLEEP_MS)) { scancode = TCA8418_getState(); TCA8418_clearFlag(); } else { scancode = 0; if (KeyTimeout()) { SetAppMode(MODE_RX_SCREEN, SCR_UPDATE_RX_SCREEN_TEXT |SCR_UPDATE_RX_SCREEN_WATERFALL); } } scancode = AutoRepeatHandler (scancode); if (scancode) { TWork* pwork = &work[idxwork++]; idxwork &= WORKCMDMASK; pwork->cmd = CMD_KEY; pwork->scancode = fullkeysdecode(scancode | 0x80); xQueueSend( work_queue, &pwork, 0 ); key_press_timeout = NO_KEY_PRESS_TIMEOUT_MS; } } } [Ссылки] 1. TCA8418 I2C Controlled Keypad Scan IC With Integrated ESD Protection site:ti.com. |