Свързване на матрична клавиатура към микроконтролера. AVR. Курс на обучение. Процедура за сканиране на клавиатурата. Задание за работа в лабораторията

Отличителни черти:

  • 64-клавишна 8 x 8 матрична клавиатура
  • Не са необходими външни компоненти
  • Излезте от режим на заспиване, като натиснете бутона
  • Лесна интеграция с други приложения
  • Ниска консумация
  • Софтуерен алгоритъм за отблъскване
  • Поддръжка на алтернативни функции на бутоните, които могат лесно да бъдат премахнати, за да се намали размера на програмата
  • Програмният код може да се използва от всеки AVR микроконтролер, който има поне 17 I/O порта и има прекъсване за промяна на линията (в момента само ATmega162 и ATmega169)
  • Кодът може лесно да бъде модифициран за използване в други микроконтролери, като се използва общо прекъсване (вижте пример за приложение "AVR240: 4 x 4 клавиатура - събуждане при натискане на клавиш")

Въведение

AT този примерприложението описва драйверната програма за интерфейс на матрицата на клавиатурата 8 x 8. Примерът за приложение е предназначен за използване в устройства със самостоятелно захранване. Микроконтролерът AVR прекарва по-голямата част от времето си в режим на заспиване, като се активира само при натискане на бутоните на клавиатурата. След това матрицата на клавиатурата се сканира, информацията се обработва и системата се връща в режим на ниска мощност.

Освен това устройството, описано в този пример за приложение, поддържа алтернативни програмируеми от потребителя функции, като напр заключване на капачката, Ctrl-, Shift- и Alt-. Тестовото приложение обслужва клавиатурна матрица 4 х 4, всеки бутон от която отговаря на една цифра и три знака. Алтернативните бутони ви позволяват да изберете функцията на натиснатия бутон.

Фигура 1. Тестово приложение

Това устройство е подходящо за всички приложения, които използват матрична клавиатура, като дистанционни дистанционно, Мобилни телефонии алармени системи и системи за контрол на достъп. Актуализация софтуерсе прави много лесно поради наличието на функции за самопрограмиране и вътрешносистемно програмиране в микроконтролерите от семейството ATmega. Тези функции са особено полезни при използване на тези микроконтролери в универсални дистанционни управления.

Устройството, описано в този пример за приложение, е базирано на микроконтролера ATmega162. Въпреки това след малки променипрограмният код може да се използва в микроконтролера ATmega169.

Принцип на действие

Свързването на бутоните на клавиатурната матрица 8 x 8 е показано на фигура 2. Когато бутонът е натиснат, съответните редове и колони са свързани. Щракването върху горния ляв бутон затваря най-лявата колона и най-горния ред.


Фигура 2. Свързване на матрицата на клавиатурата

Клавиатурните матрици могат да бъдат сканирани по няколко начина. Ако може да се натисне само един бутон, изберете бърз начинсканиране, което едновременно избира (задава ниско) всички редове и чете състоянието на колоните. След това се избират всички колони и се четат състоянията на редовете. Върнатите стойности на колона и ред са свързани в код, който идентифицира бутона, който е бил натиснат. Този метод се използва в този пример за приложение.

Ако е необходимо да се поддържа клавиатура, която позволява едновременно натискане на бутони, тогава описаният по-горе метод не може да се използва. В този случай линиите трябва да се сканират отделно. Редовете трябва да бъдат избрани (зададени ниско) последователно, като всички колони са депозирани. В този случай се определят всички натиснати бутони. В този случай обаче се появяват взаимовръзки. Фигура 3 показва резултата от натискането на три клавиша, при което изглежда, че бутонът, маркиран с X, също е натиснат. Това води до грешка при декодиране.


Фигура 3. Фалшиво декодиране при едновременно натискане на бутони

За да откриете натискане на бутони и да се събудите от заспиване, използвайте прекъсването за смяна на щифта, налично на AVR микроконтролера, който използвате. Преди да влезете в режим на заспиване, всички изходи на редове са настроени на ниски стойности, което кара входовете на колоните да изглеждат ниски при натискане на бутоните. Това ще доведе до прекъсване.

Когато се използва прекъсване за промяна на състоянието на входа, се обслужва само едно натискане. В този случай не се формира автоматично повторение на натискане при задържане на бутона. Симулацията на многократно натискане трябва да се реализира от отделна подпрограма.

Алтернативни бутони

Много интерфейси на клавиатурата използват допълнителни функции на бутоните. Това може да се реализира по няколко начина. Един от най-често срещаните методи е да се посветят няколко бутона, на които се присвояват алтернативни функции. Когато тези и обикновените бутони се натиснат едновременно, се генерира вторичен код за сканиране. Има и варианти, при които алтернативният бутон се натиска точно преди да се натисне основният бутон. В този случай необходимостта от проследяване на едновременни кликвания отпада.

Алтернативните бутони се вземат предвид само когато са натиснати основните бутони. В този случай алтернативните бутони се наричат ​​"single-shot".

Също така е възможно да се внедрят "тригерни" бутони, които при първото натискане активират алтернативни функции, а при повторно натискане ги деактивират. В този случай се използват алтернативни функции за всички последващо натиснати бутони. Такива функции имат стандартният бутон Caps Lock компютърна клавиатура. Този пример за приложение използва както бутони за единичен изстрел, така и бутони за задействане.

Използването на принципа на последователно, а не едновременно натискане на бутоните избягва проблемите, свързани с грешно декодиране. Ако няколко бутона бъдат натиснати едновременно, приложението просто ще го игнорира.

Контакт бърборене

Фигура 4 показва отскачането на контактите при натискане на бутон. Както можете да видите, има имитация на многократно натискане. За да се избегне неправилно декодиране, сканиращият код се чете известно време след прекъсването на промяната на състоянието. Освен това този алгоритъм, наречен анти-отскачане, избягва фалшиви положителни резултати, когато е изложен на шум. Дебоункцията може също да се реализира с хардуерен или цифров филтър, но методът, използван в това приложение, е най-евтиният.


Фигура 4. Контактно бърборене

Внедряване

В тази реализация се използва микроконтролерът ATmega162. Препоръките за мигриране към микроконтролера ATmega169 са изброени в края на този документ.

Клавиатурата е свързана към два 8-битови AVR микроконтролерни порта. Един порт (порт D) е конфигуриран да управлява всички линии като изходи и е свързан към редовете на матрицата на клавиатурата. Другият порт (порт C) е конфигуриран да управлява всички линии като входове и е свързан към колоните на матрицата на клавиатурата. Можете да видите това по-подробно на Фигура 2. Когато сканирате матрица на клавиатурата, портът, използван като изход, трябва да поддържа изходите ниски, а портът, използван като вход, трябва да има вградени съпротивления за изтегляне.

Описаното устройство използва първия ред на порт Е за генериране на сериен код, съответстващ на кода на натиснатия бутон. Данните се предават с помощта на вградения UART, чието използване е описано в примера за приложение AVR306.

При нормално натискане се генерира код за сканиране, чиято стойност е в диапазона от 0 до 63 (8 реда * 8 колони). Натискането на бутона за извикване на алтернативна функция също генерира нормален скан код, но освен това се задават съответните флагове на алтернативни функции. Тези флагове за състояние се съхраняват в глобална променлива.

Три бутона за извикване на алтернативни функции са конфигурирани да работят в режим на тригерни бутони, а четири - като бутони за единичен изстрел. Щракването върху тези бутони генерира нормален код за сканиране, което позволява на приложението да ги третира като обикновени бутони.

Друга глобална променлива се използва за предаване на сканирания код към приложението, заедно с флаговете. Шестте най-малко значими бита се използват за предаване на кода (от 0 до 63), а най-значимият бит (MSB) показва промяна в състоянието. Драйверът на клавиатурата задава този бит при натискане на бутон. Приложението проверява този бит и го нулира след прочитане на кода за сканиране. Глобалният байт и сканирана дума са показани на фигура 5.


Фигура 5. Разширен код за сканиране

Програмата на драйвера на клавиатурата е реализирана като манипулатор на прекъсвания. Основната програма поставя микропроцесора в режим на заспиване. Когато се натисне бутон, драйверът на клавиатурата събужда AVR микроконтролера, получава кода за сканиране и актуализира глобалните байтове. След изпълнение на функциите на натиснатите бутони, основната програма връща микроконтролера обратно в режим на заспиване.

Начален модул и основна програма

Фигура 6 показва модула за инициализация и основната програма. Нулирането на алтернативни функционални флагове и глобални променливи, както и инициализиране на портове, е описано по-горе. Ако не е необходима обработка, се избира режимът на неактивен сън.


Фигура 6. Иницииращ модул и основна програма

Главен модул на декодера на клавиатурата Декодерът на клавиатурата е манипулатор на прекъсвания при смяна на порт. Първо се избира неактивен режим на заспиване, което позволява AVR микроконтролерда се активира при препълване на таймера, което е невъзможно, когато микроконтролерът е в режим на заспиване при изключване. Таймерът е настроен да генерира прекъсване след 5 ms, което е напълно достатъчно за прекратяване на преходните процеси на сигналите на изходите. По време на това време на забавяне основната програма възвръща контрола и може да активира режима на заспиване. В края на времето за забавяне се извиква процедурата за обработка на натискания на бутони. Тази функция допълва дефинирането на кода на натиснатия бутон. В края му се задава ниско ниво на портовите линии на всички линии и се активира режимът на заспиване при изключване, излизането от което е възможно чрез натискане на бутона. Блоковата схема на този софтуерен модул е ​​показана на фигура 7.

Фигура 7. блокова схема на основния софтуерен модул на клавиатурния декодер

Сканиране на клавиатура (обработка на натискане на бутон) Фигура 8 е блокова диаграма на подпрограмата за сканиране на клавиатура. Първо, резултатът се сканира по колони. Най-малко значимите три бита от кода за сканиране (колони) се увеличават, докато се открие ниско ниво на реда на колоната. След това посоката на линиите на портовете се обръща и сканирането се повтаря. Това търси ниско ниво на линиите на линиите. След това се извиква подпрограмата за обработка на кода за сканиране.


Фигура 8. Блокова диаграма на рутинното сканиране на клавиатурата

Първо, функцията за обработка на сканирания код копира генерирания сканиран код в глобална променлива. След това сканираният код се сравнява с кодовете на бутоните на алтернативните функции и се генерират съответните флагове на алтернативните функции. Тези флагове се копират в глобалната променлива. Ако натиснатият бутон не е алтернатива, тогава флаговете на всички еднократни алтернативни функции се изчистват. Накрая се задават нови флагове. Блоковата диаграма на тази функция е показана на фигура 9.


Фигура 9. Блокова диаграма на функцията за обработка на сканирания код

тестов случай myCellPhone

Има приложение за тестови случаи, което реализира клавиатурна матрица, която прилича на клавиатура мобилен телефон. Крайните знаци в него се предават през интерфейса USART. Използвайки клавиатурната матрица 4 x 4, можете да формирате всички числа и символи, които могат да бъдат предоставени, като използвате още четири алтернативни бутона за извикване на функции. Три бутона се използват за избор на алтернативна функция на всеки основен бутон, докато четвъртият бутон действа като бутон Caps Lock (превключване между главни или малки букви).

За преобразуване на сканирани кодове в кодови комбинации, съответстващи на кодовете на натиснатите бутони, като се вземат предвид бутоните на алтернативни функции, се използва таблица за преобразуване. Кодът за сканиране може да се използва и за сканиране на клавиатурна матрица 8 x 8. По този начин таблицата трябва да има 8 записа на ред, докато се използват само 4 бутона на ред. По този начин, с увеличаване на броя на колоните на матрицата на клавиатурата, размерът на програмата няма да се промени.

Размер на кода приложна програмаи времеви параметри

Размери на кода на подпрограмата различни функцииматричната обработка на клавиатурата са показани в таблица 1.

Таблица 1. Размери на кодове на подпрограми на различни функции за обработка на клавиатурната матрица

Таблица 2 показва продължителността на различни действия, извършвани от микроконтролера ATmega162, работещ на честота 8 MHz. Ето последователностите от действия от събуждане при засичане на натискане на бутон до влизане в режим на заспиване след обработка на натиснатите бутони.

Таблица 2. Продължителност на извършените последователности от действия

Ако не вземете предвид режима на заспиване при изключване, тогава можете да видите, че през повечето време микроконтролерът работи в режим на неактивност. В активен режим микроконтролерът е само 0,3 ms, което е около 0,5% от общото време. Относителното време на престой в различни режими на работа е дадено в таблица 3.

Таблица 3. Консумация и относително време, прекарано от микроконтролера в различни режими на работа

Ако приемем, че бутоните се натискат веднъж на всеки 10 минути, тогава средната консумация ще бъде само 2 μA.

Разсъждения относно използването на други микроконтролери

Единствената разлика при използването на микроконтролерите ATmega162 и ATmega169 е, че те трябва да използват различни портове за свързване на матрицата на клавиатурата. ATmega162 използва порт C, докато ATmega169 трябва да използва порт E. Това е така, защото те имат различни портове с прекъсване при смяна на линия. ATmega162 има функцията да генерира прекъсване при промяна на състоянието на линиите на порт C, а ATmega169 - при промяна на състоянието на линиите на порт E. Ако трябва да използвате други алтернативни функции на тези портове , тогава трябва да модифицирате приложението по такъв начин, че да използвате друг порт, който има функцията за формиране на прекъсвания за промяна на състоянието на линията.

Също така имайте предвид, че ATmega169 използва регистъра SMCR, за да активира режима на заспиване.

Когато използвате други микроконтролери, ще ви трябват допълнителни външни компоненти и промяна на използваното прекъсване. Използването на такива микроконтролери за обработка на клавиатурна матрица 4x4 е описано в примера за приложение на AVR240. Останалите функции на описания пример за приложение не е необходимо да се променят.

Често свободните щифтове на микроконтролера не са достатъчни за свързване на необходимия брой бутони. При директна връзка за n бутона е необходимо да се разпредели същия брой I / O линии, което не винаги е възможно. За по-рационално използване на портовите линии можете да използвате схемата на свързване на матрицата на фиг. 1. В този случай матрицата, свързана към порт D, е с размер 4*4=16 бутона (4 реда r0…r3 и 4 колони с0…с3). Линиите PD0…PD3, които са линии r0…r3, винаги са конфигурирани за вход и се изтеглят към захранващата шина от резистори R (типична номинална стойност 4,7…10 kOhm). От тях се отчита състоянието на бутоните SB1-SB16. На линиите PD4 ... PD7 (колони c0 ... c3) на свой ред се генерира сигнал за логическа нула. Първоначално ниското ниво се задава в колоната c0, а във всички останали колони - Z-състоянието. Сега, само когато бутоните на тази колона (SB1…SB4) са натиснати на редовете на редовете r0…r3, може да възникне ниско логическо ниво. След това се задава логическа 0 в колона c1 и група бутони SB5 ... SB8 се сканират и т.н. Абсолютно същият алгоритъм за запитване на бутони се използва за всяка друга матрична клавиатура, независимо от броя на редовете и колоните. Като цяло броят на бутоните n е произведението на броя на редовете и колоните. Така, например, матрица 2*2 (4 реда) ще съдържа 4 бутона. Но от друга страна, същият брой входно-изходни линии ще са необходими за директно свързване на същия брой бутони. По този начин запазването на изходите започва да се появява, когато броят на бутоните надвишава 4 ... 6, и става още по-значително с увеличаване на броя им.

Фиг.1 Матрична схема на свързване на бутони

Елементите VD1 ... VD4 и R1 ... R4 не са задължителни на диаграмата. Диодите служат за защита срещу късо съединениемежду линиите на ред и колона. Ако, например, когато натиснете бутона SB1 (по време на сканиране на колона c0), линията на реда r0 внезапно се окаже настроена на изход и има високо логическо ниво, тогава ще започне неприемливо голям ток да тече през веригата c0r0. Въпреки че логиката на програмата не позволява този режим на работа, по различни причини това все още може да се случи. Следователно, поне при отстраняване на грешки в програма, диодите няма да бъдат излишни. Ако монтажният капацитет, даден на щифтовете PD3 ... PD0, не е твърде голям, тогава издърпващото съпротивление към захранващата шина може да бъде заменено с вътрешни „издърпващи“ резистори. За да направите това, трябва да зададете подходящите битове в регистъра PORTD, когато линиите са конфигурирани за въвеждане.

Пример за рутинно сканиране на матрична клавиатура

Бутон Def = R16 ;Регистриране с код на натиснат бутон.def temp = R17 ;Регистриране за междинни операции ldi temp,high(RAMEND) ;Инициализация на стека от SPH,temp ldi temp,low(RAMEND) от SPL,temp . clr temp ;задаване на порт D линии за въвеждане на DDRD,temp ldi temp, (1<< PD0)|(1 << PD1)|(1 << PD2)|(1 << PD3) out PORTD,temp . rcall btn_pol . ; Подпрограмма опроса матричной клавиатуры; R16 – номер нажатой кнопки на выходе из подпрограммы, ; если ни одна кнопка не нажата, то R16=0; ; если нажаты две и более кнопок, то R16=0xFF ; R17 – регистр для определения номера строки; R18 – регистр для задания номера столбца; R19 – счётчик столбцов; R20 – регистр для промежуточных операций btn_pol: clr R16 ;обнуляем регистры с кодом нажатой clr R19 ;кнопки и номером столбца ldi R18,0x0F ;очищаем регистр данных PORTD порта D out PORTD,R18 ldi R18,0x00010000 bp1: out DDRD,R18 ;настраиваем на вывод линию соответствующего nop ;столбца через регистр DDRD порта D in R17,PIND ;считываем состояние строк из регистра PIND com R17 andi R17,0x0F ;выделяем значение 4-х строк ldi R20,0 ;если ни одна кнопка в столбце не нажата, breq bp5 ;перемещаемся на следующий столбец cpi R17,0x01 ;если нажата кнопка в строке c0, ldi R20,1 ;то вычисляем её номер breq bp2 cpi R17,0x02 ;если нажата кнопка в строке c1, ldi R20,2 ;то вычисляем её номер breq bp2 cpi R17,0x04 ;если нажата кнопка в строке c2, ldi R20,3 ;то вычисляем её номер breq bp2 cpi R17,0x08 ;если нажата кнопка в строке c3, ldi R20,4 ;то вычисляем её номер brne bp3 ;если нажато более одной кнопки, завершаем опрос bp2: tst R16 ;если в предыдущих столбцах были нажаты breq bp4 bp3: ldi R16,0xFF ;кнопки, то завершаем опрос с кодом 0xFF ret bp4: push R19 ;иначе вычисляем номер кнопки, как lsl R19 ;N = 4*column + row + 1 = 4*R19 + R20 + 1 lsl R19 add R20,R19 mov R16,R20 pop R19 bp5: inc R19 lsl R18 cpi R19,4 ;повторяем цикл опроса пока не будут brne bp1 ;опрошены все 4 столбца ret

С всички предимства матричната схема на свързване има един недостатък. С негова помощ е трудно да се реализира четенето на комбинации от бутони. В случай, че на такава клавиатура се натиснат три бутона, които образуват прав ъгъл между тях (например SB1, SB2, SB5), тогава програмата за анкета ще запише фалшиво натискане на бутон, разположен в свободния ъгъл на правоъгълник (в този случай SB6). В определен сценарий такъв бутон „фантом“ може да бъде всеки бутон на клавиатурата.

Списък на радио елементи

Обозначаване Тип Деноминация Количество ЗабележкарезултатМоят бележник
DD1 MK AVR 8-битов

ATmega8

1 Към бележника
VD1-VD4 Диод 4 Към бележника
Р, Р, Р, Р Резистор 4

Почти никой продукт с микроконтролер не е пълен без бутони. Тази тема вече е изтъркана и широко известна. Като пиша тази статия, не се опитвам да преоткрия колелото. Просто реших да събера цялата информация за схемите заедно. Мисля, че материалът ще бъде полезен за начинаещи.За да не ви объркам, фигурите по-долу не показват схемите за захранване, нулиране и часовник на микроконтролерите.

Метод първи - традиционен

fig1a fig1b

Ако има малко бутони и няма недостиг на микро-щифтове, ние използваме традиционния метод на свързване.

При отпускане на бутона изходът на микрона чрез резистор се свързва към “плюса” на захранването (фиг. 1а). При натискане на бутона микроизходът е свързан към маса. Издърпващият резистор R1 ограничава тока във веригата на превключвателя. Ако не беше там, тогава при натискане на бутона просто щяхме да дадем накъсо източника на захранване.

Повечето съвременни микроконтролери имат вградени подтягащи резистори, така че външните могат да бъдат пропуснати (фиг. 1b). В програмата на микроконтролера ще трябва да конфигурирате използвания щифт към входа и да активирате вътрешния издърпващ резистор.

Какво се случва, ако щифтът на микроконтролера е в изходен режим? Това ще зависи от състоянието на този щифт. Ако изходът е "логическа нула", няма да се случи нищо лошо, защото - в първия случай (фиг. 1а) количеството на входящия ток е ограничено от резистор R1, а във втория случай (фиг. 1b) няма да тече ток изобщо. При натискане на бутона също няма да се случи нищо, тъй като потенциалната разлика между изхода и „земята“ в този случай ще бъде равна на нула.

Ако на изхода има „логическа единица“ и бутонът е натиснат, тогава през изхода на микроконтролера към земята ще тече ток от няколко десетки милиампера и изходът на порта може да „изгори“. Максимално допустимият ток за изхода на микроконтролера AVR според документацията е 40 mA. Затова понякога не е излишно между изхода на МК и бутона да поставите резистор с номинална стойност няколкостотин ома, например 330 (фиг. 1в). Така например бутоните на платката за отстраняване на грешки STK500 са свързани. Това се прави, за да се гарантира, че потребителят няма случайно да изгори микроконтролера по време на своите експерименти.

За вашите оформления обаче можете да се справите без този резистор.

Вторият начин - с помощта на диоди

Използва се, когато има повече от два бутона и искате да запазите заключенията. В този случай всеки бутон има свой собствен цифров код и броят на бутоните, които могат да бъдат окачени по този начин на N пина mk \u003d 2 N - 1. Тоест 7 бутона могат да бъдат окачени на три пина, 15 на четири , и така нататък ... но не бих окачил повече от 7. Броят на допълнителните външни компоненти се увеличава, схемата и програмата на микрокомпютъра се усложняват. В допълнение, за голям брой бутони има и други схеми за превключване. На диаграмата не са показани издърпващи резистори, предполага се, че се използват вътрешни.

Между другото, чрез диоди все още е възможно да се изпращат сигнали от бутони към изхода на прекъсване на външен контролер (фиг. 3). Когато натиснете който и да е бутон, изходът за външно прекъсване през диода ще се скъси със земята и ще предизвика прекъсване (разбира се, при условие че е конфигуриран и активиран). По този начин контролерът няма да има нужда постоянно да анкетира бутоните, тази процедура ще се задейства само от външно прекъсване.

Тази схема не е приложима за всички AVR микроконтролери, тъй като при някои модели микроконтролери може да възникне външно прекъсване при всяка промяна на който и да е щифт. (например в ATmega164P)

Третият начин е за матричната клавиатура

Тази опция за свързване обикновено се използва за блокове от няколко бутона, които са структурно комбинирани и електрически свързани в матрична верига. Но никой не забранява използването на тази схема за включване на обикновени бутони, но дава ли реални спестявания с броя на бутоните? 9.

Изходите PC0, PC1, PC2, PC3 са редовете на матрицата, изходите PB0, PB1, PB2 са колоните на матрицата. Бутоните могат да бъдат анкетирани по ред или по колона. Да кажем, че ги питаме колона по колона. Процесът на гласуване ще изглежда така: Първоначалното състояние на всички изводи е вход с включен издърпващ резистор. Задайте щифт PB0 в режим на изход и го задайте на нула. Сега натискането на бутоните S1, S2, S3, S4 ще затвори изходите PC0, PC1, PC2, PC3 до 0 мощност. Разпитваме тези изходи и определяме дали някой бутон е натиснат в момента. Задайте щифта PB0 в изходен режим и включете издърпващия резистор. Настройте изхода PB1 на изходен режим и го настройте на нула. Отново разпитваме заключенията PC0, PC1, PC2, PC3. Сега натискането на бутоните S5, S6, S7, S8 ще затвори изходите PC0, PC1, PC2, PC3. Разпитваме последната колона с бутони по същия начин.

Редовете на матрицата могат да бъдат изведени чрез диоди към изхода на външно прекъсване. Тогава логиката на програмата може да се изгради така. Ако клавиатурата не се използва няколко минути, микроконтролерът влиза в режим на ниска мощност. В този случай изходите PB0, PB1, PB2 са конфигурирани като изходи с нулево логическо ниво. При натискане на един от бутоните изходът за прекъсване на диода се затваря до нула. Това задейства външно прекъсване, микроконтролерът се събужда и стартира таймер, на който се сканира клавиатурата. Успоредно с това се стартира брояч на време, който се нулира при натискане на някой от бутоните. Веднага щом препълни, микроконтролерът отново преминава в режим на ниска мощност.

Време е да ви кажем как да организирате проучване на такава Клаудия. Нека ви напомня, че clave се състои от редове, висящи на портове и колони, които се сканират от друг порт. Кодът е написан за контролера ATMega8535, но поради факта, че всичко е посочено там под формата на макроси, той може бързо да бъде пренесен към всеки друг клас контролер мега, както и под повечето съвременни Мъничък. Въпреки че в случай на Мъничъкможе да има запушване поради непълния набор от команди, които имат. Ще трябва да го пооправиш малко с файл.

Накратко, по-близо до кода. Веднага ще направя резервация, че взех модата да разделям един проект на дузина малки файлове и след това да ги свързвам, ако е необходимо. Първо, той рязко структурира кода, което улеснява навигацията в него, и второ, кодът става модулен и неговите части могат да се използват като готови библиотеки в други програми. Просто ощипни малко. По същата причина правя всички дефиниции чрез макроси, така че да не се налага да редактирам целия код, а е достатъчно само да променя няколко реда в конфигурационния файл.

Сега накратко за файловете:
keyboard_define.inc— конфигурационен файл на клавиатурата.
Този файл съхранява всички дефиниции на макроси, използвани от клавиатурата. Тук задаваме кои пинове на микроконтролера към коя линия са свързани. Една тънкост - заключенията по колоните ( сканиране на порт) трябва да бъде сериен набор от линии на един и същи порт. Това е, например, краката 0,1,2,3 или 4,5,6,7 , или 3,4,5,6 . Няма значение кой порт, основното е да сте последователни.
С дефиницията на краката мисля, че няма да има проблеми, но за параметъра КЛЮЧОВА МАСКАИскам да кажа нещо специално.
Това е маската, по която ще бъде разпределен сканираният порт. Трябва да съдържа 6 единици и една 0. Нулата е зададена в най-дясната позиция на порта за сканиране.

Пример:
Моят порт за сканиране виси на битове 7,6,5,4, крайният десен бит на порта за сканиране е бит 4, следователно маската е 0b11101111 - нулата е на 4-та позиция. Ако сканиращите линии висят на крака 5,4,3,2, тогава маската вече ще бъде 0b11111011 - нула във втората позиция. Защо е всичко това ще бъде обяснено по-долу.

Има и маска на активните линии на порта за сканиране - SCANMSK. В него единиците са само срещу линиите на колоните. Моите колони са настроени на най-високата тетрада на порта, така че маската за сканиране изглежда така 0b11110000.

В секцията за инициализация не забравяйте да настроите краката на порта за сканиране към изхода и краката на порта за четене към входа с издърпване. И след това поставете кода на манипулатора на клавиатурата някъде под формата на обикновена подпрограма. Лесен е за използване - извикваме подпрограмата за четене от клавиатурата и когато се върнем, имаме сканиран код на клавиша в регистър R16.

Ето как изглеждаше моят тестов код:

Основен: SEI ; Разрешаваме прекъсвания.

RCALL KeyScan; Сканиране на клавиатурата
CPI R16.0; Ако се върне 0, тогава не е имало щракване
BREQ Главен; В този случай преминете към началото
Генериране на RCALL код; Ако сканираният код се върне, преведете го на
; ASCII код.

MOV R17, R16; Зареждане в приемния регистър на LCD манипулатора
RCALL DATA_WR; Ние показваме.

Основен RJMP; Зацикляме всичко.

Професионалист LCDдисплей, все още няма да кажа нищо, тъй като процедурите все още не са се сетили, но те ще бъдат публикувани и дъвкани в близко бъдеще.

Сега ще ви кажа как работи процедура за сканиране на ключове

Деф. БРОЯ = R18
KeyScan: LDI COUNT,4 ; Сканирайте 4 колони
LDI R16,КЛЮЧОВА МАСКА ; Заредете маската при сканиране 0 на колоната.

Първо подготвяме маската за сканиране. Факт е, че не можем просто да вземем и прехвърлим данни към порта по този начин. В крайна сметка линиите висят само на последните четири бита, а на първия може да има всичко, така че основното нещо за нас при никакви обстоятелства не е да променяме състоянието на битовете на долната тетрада на порта.

KeyLoop: IN R17,COL_PORT; Взимаме предишната стойност от порта
ORI R17,SCANMSK ; Задаваме битовете на сканираната част на 1.


първо зареждане на данни от порт регистъраза да разполагате с първоначалната конфигурация на порта. Също така трябва да настроим всички сканиращи битове на порта на 1, това става чрез операцията ИЛИчрез сканираща маска. В частта, където са стояли блоковете след операцията ИЛИчрез маска 11110000 (моето значение SCANMASK) всички битове ще станат единици, а където е имало нула, ще останат непроменени.

И R17,R16; Нулирайте бита на сканираната колона
OUT COL_PORT,R17; Извеждаме генерирания байт от порта.


Сега налагаме генерирания байт маска на активната колона. В него първо нула на първа позиция и всички останали. В резултат на това други стойности на порта няма да се променят, но в първата колона ще се появи 0. След това маската ще се премести и цялата операция ще се повтори отново. В резултат на това нула вече ще бъде в следващата колона и т.н. По този начин организираме „текуща“ нула в порта за сканиране, докато други, външни битове на порта остават непроменени. И след това генерираното число се зарежда в порт регистъра и краката поемат съответните нива на напрежение.

NOP ; Забавяне на превключването на краката.
NOP
NOP
NOP

SBIS ROW0_PIN,ROW0; Проверете кой ред е щракнат
RJMP bt0

SBIS ROW1_PIN, ROW1
RJMP bt1

SBIS ROW2_PIN, ROW2
RJMP bt2

SBIS ROW3_PIN, ROW3
RJMP bt3


Серия NOPнеобходимо, за да се даде време на етапа преди проверка, за да вземе желаното ниво. Факт е, че една реална верига има някаква стойност на капацитет и индуктивност, което прави Невъзможна моментална промяна на нивотовсе още има малко забавяне. И при скорост от 8 MHz и по-висока, процесорът щраква команди с такава скорост, че напрежението на крака все още не е намаляло и ние вече проверяваме състоянието на изхода. Затова направих няколко празни операции. На 8 MHz всичко работи добре. При по-висока честота вероятно ще е необходимо да поставите още пет или шест NOPили залепете прост цикъл. Тук обаче трябва да погледнете какво ще бъде по-икономично по отношение на байтовете.
След примките има четири проверки на ред. И преминаването към подходяща обработка на събития.

ROL R16 ; Преместете маската за сканиране
DEC БРОЙ ; Намаляване на броя на колоните
BRNE KeyLoop; Ако все още не всичко е подредено, правим още една итерация

CLR R16 ; Ако няма кликвания, върнете 0
RET
.undef БРОЙ

Тук маската се измества наляво чрез командата за циклично изместване ROL. След това намаляваме брояча на итерации (първоначално равен на четири, тъй като имаме четири колони). Ако нямаше щраквания, тогава в края на всичките четири итерации излизаме от цикъла, нулираме регистъра R16и се връщаме.


bt0: ANDI R16,SCANMSK; Ние генерираме код за сканиране
ORI R16.0x01 ; Връщаме го в регистър 16
RET

И ето един от възможните окончания при натискане. Тук се генерира код за сканиране, който ще бъде върнат в регистъра R16.Реших да не се занимавам, но както винаги, захвана дузина байта и го направих възможно най-бързо и кратко. И така, какво имаме при пристигането в тази част от кода. И имаме една от опциите за порта за сканиране ( 1110,1101,1011,0111 ), и също така знаем номера на реда, чрез който сме стигнали до тук. По-конкретно, тази част може да бъде достъпна само от първия ред чрез команда RJMP bt0.
Така че нека направим код за сканиране от комбинация от сканиране и номер на ред! Казано, сторено! Първо, трябва да извлечем комбинация за сканиране от стойността на порта - съхраняваме я в регистъра R16, така че няма нужда да го изваждате от порта. Прокарваме операцията И стойността R16през SCANMASKи всичко, което беше под единици, премина без промени, а където имаше нули, изчезна. Opa, и ние показахме сканираща фигура - високия нибъл. Сега поставяме номера на реда там - по операцията ИЛИ. Веднъж получихме конструкция на формата [сканиране][низ]
Тук го оставяме в регистъра R16и да излизаме! По същия начин и с останалите редове. Вижте източника, няма да ги дублирам тук.

Декодиране на сканиран код.
Страхотно, има сканиран код, но какво да правя с него? Не го залепвайте никъде. Знаем, че тази шняга на вида 01110001 това е кодът на един и няколко LCDекран или стандартен терминал ще направи ужасно грачене пред нас и ще ни каже всичко, което мисли за нашата нотация - виждате ли ASCIIдай го. Добре, ще бъде ASCII.

Как да бъдем? Изпълнете цялата структура СЛУЧАЙкъде да зададете код за всяко сканиране ASCIIМачка ме жаба - ето колко проверки трябва да направите! Ето колко байта ще отидат за цялата тази треяхомудия? И паметта ни не е гумена, мизерните осем килобайта, а два байта на команда, това е в най-добрия случай. Мога да направя всичко това направо в манипулатора на клавиатурата. НЕ!!! ДО ГОРЕ!!! Ние ще вървим по своя път.
Добре, какво имаме на склад? Методът на преходната таблица не работи, поради ужасното разстройство на сканираните кодове. Почесах тиквата, порових из апартамента ... и тогава ми светна. Разбира се!!! Груба сила!!!

Код за сканиране с груба сила.
И така, имаме ужасно несвързан код за сканиране, както и тънка маса ASCIIгерои. Как да кръстосате змия с таралеж? Да, всичко е просто! Нека поставим в паметта таблицата със символи в група [сканира код]:и след това ще прекараме всеки желан сканиран код през тази таблица и, ако съвпада, ще заменим желания в изхода ASCIIот куп. Класически пример за програмиране - изгубен във времето, но спечелен в паметта.

Ето как изглежда:

CodeGen:LDI ZH,High(Code_Table*2) ; Качен адрес на кодовата таблица
LDI ZL,Low(Code_Table*2) ; високи и ниски байтове

Тук заредихме адреса на нашата таблица в индексния регистър. Умножете по две, така че адресът да е в байтове, защото в средата на компилатора кодовото пространство се адресира с думи.

Груб: LPM R17,Z+ ; Взех първия знак от таблицата - скан код

CPI R17.0xFF ; Ако краят на масата
BREQ CG_Изход; След това излизаме

CPI R16.0; Ако е нула,
BREQ CG_Изход; тогава тръгваме

CP-R16,R17; Сравних го със скан кода на ключа.
BREQ Равно; Ако е равен, отидете на заместващ ascii код

Зареждаме първия сканиран код от таблицата и го поставяме в регистъра R17, като същевременно увеличава адреса в регистъра З(избирайки следващата клетка от таблицата) и първо я сравнете с FFе кодът за края на таблицата. Ако масата свърши, излезте оттук. Ако не сме преминали през цялата таблица, тогава започваме да сравняваме входната стойност (в регистъра R16) в началото с нула (без натискане), ако се излезе и от нула. И със сканиран код от таблицата. Ако сканирането на таблицата съвпада с входното сканиране, отидете на Равен.

LPM R17,Z+; Увеличете Z с 1
RJMP Brute ; Повторение на цикъла

И ако нищо не се намери, тогава извикваме отново командата LPM R17,Z+само за да стане по-голям Здо един - трябва да прекрачим ASCIIкод и вземете следващия сканиран код от таблицата. Просто I.N.C. Zняма да работи, т. к Зние имаме двубайтов. ЗЛ и ЗХ. В някои случаи е достатъчно INC ZL, но това е случаят, когато сме сигурни, че адресът не е далеч от началото и няма да възникне препълване на малкия байт (в противен случай вместо адреса 00000001: 00000000 просто ще получим 00000000: 0000000, което е фундаментално погрешно ), и командата LPMще направи всичко за нас, така че тук спестихме още няколко байта. След това ще се върнем в началото на цикъла и ще има отново LPMкойто ще зареди следващия код за сканиране.

Равен: LPM R16,Z ; Зареждане на ASCII код от паметта.
RET ; Връщаме се

Ако имаше съвпадение, тогава в резултат LPM Z+ние имаме Зсочи към следващата клетка ASCIIкод. Качваме го в регистъра R16и излизаме навън.

CG_Изход: CLR R16; нулиране 0 = връщане 0
RET ; Връщаме се

И в случай на нулев резултат, когато или таблицата е свършила, и кодът за сканиране не е намерен, или нулата е била в регистър R16 на входа, ние се връщаме със същата нула на изхода. Това е.



; СТАТИЧНИ ДАННИ
;========================================
Кодова таблица: .db 0x71,0x31;1
.db 0xB1,0x32 ;2
.db 0xD1,0x33 ;3
.db 0x72.0x34 ;4
.db 0xB2,0x35 ;5
.db 0xD2,0x36 ;6
.db 0x73.0x37 ;7
.db 0xB3,0x38 ;8
.db 0xD3,0x39 ;9
.db 0x74.0x30 ;0
.db 0xFF,0 ;КРАЙ

Това е просто плоча със статични данни, на ръба на паметта. Както можете да видите, данните са групирани по два байта - scancode / ASCII

Ето, чрез такива извращения, цялата програма, с обработка на клавиатурата, декодиране на сканирания код, четене / запис на LCD индикатора и нулиране на RAM (необходимо е, за да сте сигурни, че паметта е нула) отне общо 354 байта. Кой може по-малко?

На страниците на този сайт вече е представена работа по създаването и използването на клавиатурата, но тя беше чувствителна на допир. Тези, които искат по-опростен вариант, са по-склонни да изберат стандартни клавиатури, в които бутоните са свързани с матрица. Тази връзка на бутоните ви позволява да намалите броя на щифтовете, необходими за свързване към микроконтролера.

Най-често срещаните клавиатури са 3х4 и 4х4 съответно с 12 и 16 бутона. Имах клавиатура 4x4 в ръцете си. Сега ще обмислим да работим с нея.

Имах такава клавиатура с мембранни контакти. Добър е, защото е с дебелина само 1 мм и лесно може да се залепи към желаните повърхности.

Натискайки бутоните, използвайки мултиметър, настройвам как са свързани бутоните вътре в клавиатурата.


В Bascom-AVR има специална функция за сканиране на матрични клавиатури Getkbd() . Тази команда е пригодена за клавиатури 4x4, така че използва всичките 8 пина на един порт на микроконтролера. И в случай на използване на клавиатури с по-малко бутони, това трябва да се вземе предвид.

Конфигурирането на командата се състои в задаване на порта, към който ще бъде свързана клавиатурата, времето за преминаване на отскачането на контакта и забавянето след засичане на натискане.

например в следния ред:

конфиг Kbd = Portd, Дебоунс= 20 , Закъснение= 100

конфигурирана връзка на клавиатурата към PortD, време за отскачане, зададено на 20 ms, време на забавяне след натискане 100 ms

Тази команда се грижи за цялата работа по сканирането на линиите на клавиатурата и връща номера на натиснатия клавиш от 0 до 15 на променливите бутони.

В примера по-долу клавиатурата се сканира при 10 Hz и е в основния програмен цикъл. Резултатът от натискането се показва на LCD дисплея.

$regfile = "m8def.dat"
$кристал = 1000000

"конфигурация на дисплея
конфиг Lcdpin = Pin, Rs = Portc. 0, E = Portc. 1, Db4 = Portc. 2, Db5 = Portc. 3, Db6 = Portc. 4, Db7 = Portc. 5
конфиг lcd= 20 * 4
Курсор Изкл
Cls

"Конфигурация на клавиатурата
конфиг Kbd = Portd, Дебоунс= 20 , Закъснение= 100


"променливи
Dim Key_char Катобайтове"брой натиснати клавиши
Dim Key_str Катониз* 1 "знак на натиснатия клавиш на клавиатурата
Dim резултат Катониз* 20 "резултат от натискане на клавиатурата

резултат= ""

„Основен цикъл на програмата
Направи

Key_char= Getkbd() "клавишът не е натиснат и функцията връща стойност 16 на променливата

Ако Key_char<> 16 Тогава"ако променливата не е равна на 16, тогава бутонът е натиснат
Key_str= Lookupstr(key_char, Keyboard_data) "издърпайте знака на натиснатия клавиш
резултат= резултат + key_str
край Ако

Намерете 1 , 1

lcd резултат "покажете резултата от натискането

Чакайте 100

цикъл

край

Keyboard_data:
Данни "1" , "4" , "7" , "*" , "2" , "5" , "8" , "0"
Данни "3", "6", "9", "#", "A", "B", "C", "D"

И ето тестовата верига, според която са свързани дисплея и клавиатурата:

Няма да навреди да добавите резистори за ограничаване на тока към линията на клавиатурата с номинална стойност 100-150 ома във веригата. За всеки случай, но ще свърши работа за теста (основното е да не натискате няколко бутона наведнъж)

Свързваме, мигаме, натискаме бутоните и виждаме резултата - символите на натиснатите клавиши се показват на дисплея:


По-късно ще добавя демо видео, веднага щом намеря нещо за снимане с прилично качество.

Междувременно можете да изтеглите архива, който съдържа файла за симулацията в Proteus и фърмуера.