Подключение клавиатуры PS/2 к БК11М
С одной стороны адаптер принимает нажатия клавиш от стандартной PS/2 клавиатуры, а с другой манипулирует входными линиями микросхемы 1801ВП1-014 притворяясь матрицей клавиш. Количество выходов AtMega8 увеличено с помощью сдвигового регистра. Прошивка написана на диалекте Forth muforth
PS/2
Я не буду переписывать здесь полные описания протокола и электрического соединения PS/2, а также сканкоды клавиш. Это можно посмотреть здесь и здесь. Две картинки чтобы напомнить:
Вот как я подключаю PS/2 разъём:
R7 и R6 обеспечивают формирование сигналов для выходов с открытым коллектором у клавиатуры, цепи с диодами (D1, D2, D3 и D4) и резисторами R3 и R5 образуют простую защиту от статического электричества. D2 (INT0) подключен к линии CLK, таким образом используется прерывание для синхронизации с клавиатурой при чтении данных. D3 используется как линия DATA.
Питание придётся брать прямо с разъёма БК.
INT0 настраивается для срабатывания по спаду.
%01 equ ISC00 %10 equ ISC01 code init-ps2 ( ISC00=0, ISC01=1 -- the falling edge of INT0 generates an interrupt request) MCUCR h0 lds ISC00 invert h0 andi ISC01 h0 ori MCUCR h0 sts PS2CLK DDRD cbi PS2CLK PORTD cbi PS2DATA DDRD cbi PS2DATA PORTD cbi ret ;c
Один из таймеров используется для обнаружения таймаута при обмене с клавиатурой: если с последнего прерывания по линии CLK прошло значительное время, то я считаю, что произошёл сбой и начинаю приём байта с самого начала. Стартовый бит, бит чётности и стоповые биты игнорируются. Полученный байт записывается в кольцевой буфер.
=========================================================================== INT0 handler. Read data. Ignore start, parity and stop bits. After receiving BITS-PER-PACKET bits decode byte. =========================================================================== code INT0-handler r0 push x pushw h0 push r0 clr -- PS2 wait not expired "ff tl ldi TIFR h0 in TOV0 h0 sbrs always tl clr 1 TOV0 << h0 ldi TIFR h0 out then -- tl = 0 -- PS2 timeout -- tl = ff -- no PS2 timeout -- X = bitcount addr bit-count >hilo xl ldi xh ldi -- timeout? tl tst .Z if BITS-PER-PACKET h0 ldi x@ h0 st then -- reset timeout timer 256 PS2-WAIT-PERIOD - h0 ldi TCNT0 h0 out -- read bit if 2 < bitcount < BITS-PER-PACKET x@ h0 ld 3 h0 cpi -- C = 0 if bit-count >= 3 -- C = 1 if bit-count < 3 .C not if BITS-PER-PACKET h0 cpi -- C = 0 if bit-count >= BITS-PER-PACKET -- C = 1 if bit-count < BITS-PER-PACKET .C if -- read bit. Note bit C is set now! PS2DATA PIND sbis clc byte-read tl lds tl ror byte-read tl sts then then x@ h0 ld h0 dec -- h0 = bit-count 1- .Z if -- input-write input-wptr tl lds tl th mov th inc input-wptr th sts -- input-wptr++ BUFFER-LEN 1 - tl andi -- mask ptr input-buffer >hilo xl ldi xh ldi tl xl add r0 xh adc byte-read tl lds x@ tl st BITS-PER-PACKET h0 ldi then bit-count h0 sts h0 pop x popw r0 pop ret ;c
Кольцевой буфер на 32 байта устроен очень просто: указатели для чтения и для записи увеличиваются до переполнения 16-ти битного слова, а для чтения/записи применяется маска. Слово для записи в буфер закомментировано поскольку в процедуре обработки прерывания от клавиатуры используется ассемблерный вариант.
=========================================================================== Simple ring buffer. Uses two free pointers, which masked during access only. =========================================================================== 32 equ BUFFER-LEN -- Note: need 10 bytes for PrtScreen press/release BUFFER-LEN var input-buffer 1 var input-rptr 1 var input-wptr : init-input-buffer 0 dup input-rptr c! input-wptr c! ; code input-mask ( n - n) BUFFER-LEN 1- tl andi ret ;c : input-empty? ( - f) input-wptr c@ input-rptr c@ = ; ( return ptr value and increment ptr) : advance-ptr ( a - n) dup c@ swap over 1+ swap c! ; comment XX : input-write ( b) input-wptr advance-ptr input-mask input-buffer + c! ; XX : input-read ( - b) input-rptr advance-ptr input-mask input-buffer + c@ ;
Матрица переключателей
Матрица имеет 10 столбцов , 8 строк ( всегда подключен к земле) и несколько служебных сигналов. имеют pullup резисторы 22K, - pulldown резисторы 180K. Служебные линии, кроме СТОП, имеют pullup резисторы 3.3K.
В начальном состоянии соответствующие линии микросхемы 1801ВП1-014 работают на вход, резисторы обеспечивают высокий уровень на и низкий уровень на . При нажатии клавиши происходит следующее:
- получает выскоий уровень с получающегося делителя 22K/180K.
- переключается в режим выхода с низким уровнем.
- получает низкий уровень.
Что мне нужно для электрической имитации матрицы?
- всегда находятся в режиме ввода, значит можно не волноваться о токоограничивающих резисторах.
- Имеется pullup резистор, значит можно не подавать высокий уровень, а просто переходить в высокоимпедансное состояние.
- работают как на вход так и на выход, так что нужно ограничить ток.
Линии (кроме ) подключены напрямую к выходам микроконтроллера, линии подключены через токоограничивающие резисторы R8-R14. Оставшиеся сигнальные линии и из-за исчерпания выводов AtMega8 подключены к сдвиговому регистру через оптопары. Технически оптопары не обязательны, ну разве что для STOP линий, однако они были под рукой:)
Управление и :
=========================================================================== Manipulate bk input lines X lines is switched between input and output. PortX alwayse quals 0. Y lines is switched between 0 and 1. DdrY is always output. X connects to input with 22k pullup so no need for current limiting (5/22e3 = 0.227mA). Y may be connected to the GND through open collector so it's better to use resistors. Max 200mA for all 11 pins. 200mA/11 = 18mA per pin, 5/18e-3 = 275 Ohm min. -- input lines X0-9 = 9 pins (-x2) PS2 (data/clock) = 2 pins -- output lines Y1-7 = 7 pins su + ar2 + zagl + str + pr + space + stop + x2 = 4 pins 74HC595 (7) total: 23 pins PS pins = 2 x 10k Y1-7 pins = 7 x 330 74HC595 pins = no resistors X0-9 = no resistors =========================================================================== =========================================================================== x0 - d0, x1 - d1, x3 - d4 x4 - c5, x5 - c4, x6 - c2, x7 - c1, x8 - c0, x9 - c3 =========================================================================== code x3-3dstate 4 DDRD cbi ret ;c code x3-0 4 DDRD sbi ret ;c code y1-1 1 PORTB sbi ret ;c code y1-0 1 PORTB cbi ret ;c
Перекодировка
Всё начинается с конечного автомата, переход по ребру XXX приводит к имитации нажатия STOP, переходы по ребрам scancode приводят к проверке на особые клавиши а затем к считыванию команды из одной из таблиц функций. Команда представляет собой битовый набор, в котором указывается какими линиями нужно манипулировать и каким образом.
=========================================================================== Normal key pressed =========================================================================== : NORMAL ( b) dup "f0 = if drop 2release ^ then dup "e0 = if drop 2extended ^ then dup "e1 = if drop 2pause ^ then dup normal-modifiers? if drop ^ then dup normal-quirks? if drop ^ then .ifdef DEBUG "c log! .then call-decode ; =========================================================================== Normal key released =========================================================================== : RELEASE ( b) dup "f0 = if drop 2normal ^ then dup "e0 = if drop 2normal ^ then dup release-modifiers? if drop 2normal ^ then dup release-quirks? if drop 2normal ^ then .ifdef DEBUG "d log! .then call-release-decode 2normal ; =========================================================================== Extended key pressed =========================================================================== : EXTENDED ( b) dup "f0 = if drop 2rel-ext ^ then dup "e0 = if drop 2normal ^ then dup extended-modifiers? if drop 2normal ^ then dup extended-quirks? if drop 2normal ^ then .ifdef DEBUG "e log! .then call-decode 2normal ; =========================================================================== Extended key released =========================================================================== : REL-EXT ( b) dup "f0 = if drop 2normal ^ then dup "e0 = if drop 2normal ^ then dup ext-release-modifiers? if drop 2normal ^ then dup ext-release-quirks? if drop 2normal ^ then .ifdef DEBUG "f log! .then call-release-decode 2normal ; =========================================================================== Pause key pressed =========================================================================== ( Pause send next bytes: E1,14,77,E1,F0,14,F0,77 there is no reason to store first E1 therefore we store remaining bytes) 7 equ PAUSE-CHARS-LEN name pause-chars "14 c, "77 c, "e1 c, "f0 c, "14 c, "f0 c, "77 c, .even : PAUSE ( b) ['] pause-chars pause-char-ptr c@ + asm{ { t z movw th clr pmz tl ld } } = invert if 2normal ^ then pause-char-ptr c@ 1+ dup PAUSE-CHARS-LEN < if pause-char-ptr c! ^ then drop mod-stop-p send-mod mod-stop-r send-mod 2normal ;
Часть таблицы функций:
=========================================================================== Recode tables for x/y lines [0..ff] =========================================================================== ( normal/release lat) name lat-normal ( 00 01:F9 02 03:F5 04:F3 ) key-nop c, key-sbr-p c, key-nop c, key-|==>-p c, key-=|=>-p c, ( 05:F1 06:F2 07:F12 08 09:F10 ) key-povtor-p c, key-kt-p c, key-nop c, key-nop c, key-nop c, ( 0a:F8 0b:F6 0c:F4 0d:tab 0e:`) key-shag-p c, key-indsu-p c, key-|<==-p c, key-tab-p c, key-nop c, ( 0f 10 11:LAlt 12:LShift 13 14:LCtrl) key-nop c, key-nop c, key-nop c, key-nop c, key-nop c, key-nop c, ( 15:q 16:1 17 18 19 1a:z) key-q-p c, key-1-p c, key-nop c, key-nop c, key-nop c, key-z-p c,
Скачивание
- Исходник ядра - Forth яро.
- Исходник монитора - монитор предназначенный для обмена командами и данными по последовательной линии, нужен для начальной инициализации Форта.
- Исходник прошивки - основная программа.
- Скомпилированная прошивка - образ прошивки.
Фьюзы: E:FF, H:DE, L:E4
Микроконтроллер можно перепрошивать прямо на плате, вот таблица для подключения программатора:
Контакт | Назначение |
---|---|
6 - XT2 (J5) | SCK |
9 - XT2 (J5) | MOSI |
10 - XT2 (J5) | MISO |
12 - XT1 (J2) | GND |
2 - J3 | RESET |
Клавиши
PS/2 клавиша | БК клавиша |
---|---|
Esc | КТ |
F1 | ПОВТ |
F2 | КТ |
F3 | =|=> |
F4 | |<== |
F5 | |==> |
F6 | ИНДСУ |
F7 | БЛОКРЕД |
F8 | ШАГ |
F9 | СБР |
Pause | СТОП |
App | ВС |
Insert | ВС |
Delete | |<== |
Shift | ПР |
Ctrl | СУ |
Alt | АР2 |
Left Win | РУС |
Right Win | ЛАТ |
Home | ВС+ left |
End | ВС+ right |
PageUp | АР2+ up |
PageDown | АР2+ down |