![](https://habrastorage.org/webt/zk/ez/qz/zkezqzro6zevpknzozpbrnnk-f4.jpeg)
В качестве продолжения своей предыдущей статьи об IBM PC и его особенностях я решил реализовать KeybJr – небольшой открытый проект, позволяющий подключать к PCjr клавиатуру через проводное соединение или ИК-порт. Натолкнуло меня на это отсутствие в системе возможности для подключения нормальной клавиатуры за исключением редких и дорогостоящих сторонних решений.
А ведь Junior, в наши дни ставший уже чисто гиковским устройством, представляет собой не более чем раритетное украшение, который не будет работать без родной клавиатуры. Будь то оригинальная чиклетная «Freeboard» или ее последующая разновидность с более традиционной раскладкой, оба варианта оставляют желать лучшего, когда дело доходит до хлипкой работы их скрипучих резиновых колпачков. И если вы даже отыщете такую, но горестно обнаружите в ней потекшие батареи, то почему бы не подключить к PCjr клавиатуру Model M?
Подключение XT/AT-клавиатуры со 101 клавишей через ИК-интерфейс в режиме эмуляции XT:
В текущей ревизии KeybJr позволяет подключать XT, AT, PS/2 или старые USB-клавиатуры. Нажатия клавиш обрабатываются согласно ожиданиям PCjr, после чего передаются ему как через ИК-интерфейс, так и по проводному соединению. Подключается клавиатура через гнездо “K” сзади, что избавляет от необходимости ее нахождения в радиусе видимости ИК-приемника.
Тем не менее посредством ИК-интерфейса KeybJr может соединить подходящую клавиатуру с PCjr, у которого контакты гнезда повреждены – то есть, когда оригинальные и дорогие клавиатурные адаптеры не работают. Причем олдскульные пользователи могут помнить, насколько легко контактные штыри Junior сгибались и отламывались.
Чтобы вписать проект KeybJr в одни выходные, я выбрал популярную и недорогую платформу – Arduino Uno и ее клона на базе ATmega328P.
![](https://habrastorage.org/webt/zk/ez/qz/zkezqzro6zevpknzozpbrnnk-f4.jpeg)
Сам проект можно скачать в виде исходного кода, совместимого с Arduino IDE, либо как двоичный файл, содержащий необходимый загрузчик, код и настройки битов блокировки, который затем можно записать через специальный программатор или ICSP-разъем ATmega328P. Структурно исходный код довольно понятен. В зависимости от используемого протокола вызывается либо простой обработчик прерываний для XT-клавиатуры, либо форк библиотеки
PS2KeyAdvanced
для AT. PS/2 или USB-клавиатуры (в сочетании с адаптером). После этого клавиатура начинает опрашиваться, и программа выполняет необходимый перевод скан-кода, согласно техническому руководству PCjr. Далее код стробирует ИК-светодиоды и при необходимости отправляет данные по кабелю. Затем весь цикл повторяется.
Тем не менее, поскольку при передаче в коде используется прямой доступ к портам AVR с целью реализации ускоренной техники bit-banging вместо ардуиновской
digitalWrite()
(клавиатура во время передачи блокируется, а значит работать должна максимально быстро), то любые отклонения цепи для портов ввода-вывода, использованные в схеме, должны быть адресованы в коде заранее.![](https://habrastorage.org/webt/c-/yc/bv/c-ycbvkp5hbraja8bfa-97uwfts.png)
Имейте ввиду, что некоторые очень редкие и старые XT-клавиатуры, например первые ревизии IBM Model F (использовалась в 5150 или XT), после подачи питания могут потребовать «аппаратного сброса» через линию контакта DIN №3 (
/RESET
). В схеме это не отражено, но если такое случится – подключите эту линию к PD7 на ATmega (контакт 13 на DIP), и KeybJR при включении/перезагрузке микроконтроллера сделает все остальное. Если же вы используете AT, PS/2 или старую USB-клавиатуру через адаптер, то Keybjr задействует библиотеку PS2KeyAdvanced, которая поддерживает внешний код. Протокол PS/2 по умолчанию двунаправленный, однако, ради простоты и удобства я управляю клавиатурой в синхронном режиме. Это значит, что во время передачи сигнала на Junior прерывания клавиатуры и сигнал
clock
блокируются во избежании проблем с таймингом.После этого обработанное нажатие клавиши стирается из внутреннего буфера клавиатуры, и цикл повторяется. А сигнал нажатой клавиши, полученный с клавиатуры PS/2, через таблицу перевода преобразуется в XT-совместимый скан-код. Все дело в том, что PCjr ожидает скан-код XT, пусть даже передаваемый в виде иного сигнала или в отличающемся для некоторых нажатий клавиш формате.
![](https://habrastorage.org/webt/-r/wi/2p/-rwi2ptst65ifjfawrxpacoapuu.jpeg)
Техническое руководство неплохо описывает, в какой форме PCjr ожидает ввод с клавиатуры. Принцип передачи через ИК-приемник и проводное соединение почти одинаков и предполагает лишь пару отличий. Каждый бит данных кодируется в двухфазном импульсе длиной 440 миллисекунд. Логическая
1
устанавливается в первой половине (220мс) импульса и сбрасывается во второй. Логический 0
ожидает 220мс, устанавливается на последующие 220мс и после этого сбрасывается. При передаче данных по кабелю вход инвертируется, то есть 5 вольт представляют логический
0
. В случае же ИК-передачи двухфазная продолжительность остается такой же, то есть 220 + 220мс. Но при этом вместо установки цифрового выхода на всю продолжительность полуфазы ИК-приемник для каждой установки ожидает стробирования квадратной волной на частоте 40КГц с коэффициентом заполнения 50% в течение 62.5мс, после чего полуфазу завершает простой продолжительностью 157.5мс.![](https://habrastorage.org/webt/ad/dt/mt/addtmtm8dxepuyu94_slbuof4f0.png)
При использовании этого протокола передачи сигнала отправка одного нажатия или отпускания клавиши (каждое из которых представлено один байтом скан-кода) на PCjr включает один стартовый бит, 8 бит данных скан-кода, где первым идет младший байт, бит четности и одиннадцать пустых стоп-бит. Их задача просто дать NMI время на обработку всего этого в обработчике прерываний (INT 48).
Каждое валидное нажатие клавиши – это байт значения в диапазоне от 1 до
0x3A
, плюс 0x54
обозначает клавишу Fn, а 0x55
фантомную клавишу, то есть команду для PCjr отбросить содержимое буфера. То же касается и отпускания клавиш, о котором сигнализирует break code, только для них устанавливается старший бит – то есть ИЛИ с 0x80
. После этого скан-коды XT нельзя непосредственно отправить PCjr без дополнительной подготовки, поскольку тогда правильно будет обработана только буквенно-цифровая часть. Дело в том, что в PCjr для обработки нажатий функциональных клавиш, навигационных, Pause/Break, Printscreen и так далее используется клавиша Fn. Даже конкретные скан-коды, согласующиеся между XT и AT, необходимо передавать на Junior нестандартным способом. Речь идет, к примеру, об обратном слэше (Alt+прямой слэш), тильде (Alt+правая скобка), точке (Shift+Delete) и так далее.
![](https://habrastorage.org/webt/mq/jv/mr/mqjvmrbvmcyhynd8avfjq9rhch0.jpeg)
Вместо использования ИК-порта плата подключена к гнезду “K”
Естественно, есть здесь и несколько подвохов, почти все из которых связаны с односторонним характером связи между PCjr и клавиатурой. Сюда относится KeybJr и любой другой аналог, подключенный хоть через ИК-порт, хоть проводом.
Основная проблема в том, что ввиду своего дизайна PCjr в случае занятости системы даже при подключении оригинальной клавиатуры будет терять сигналы нажатых клавиш, например во время обращения к диску или последовательному интерфейсу. В связи с этим KeybJr пытается конвертировать для PCjr все возможные нажатия, так что, естественно, не стоит ожидать, что будут работать клавиши SysRq, Windows, контекстного меню, веб или мультимедиа. По дизайну правые и левые Control/Alt не различаются, а F11 и F12 вообще не будут регистрироваться.
При перезагрузке системы обратной связи на клавиатуру не поступает, и она об этом событии не узнаёт. Поэтому, если вы используете не XT-клавиатуру, то состояния CapsLock и ScrollLock (светодиоды) при перезагрузке системы (а также при отключении, если вы запитываете KeybJr от внешнего источника питания, а не от PCjr) рассинхронизируются.
В качестве примера еще добавлю, если вы включите Caps Lock или Scroll Lock и перезагрузите или отключите питание KeybJr, не отключая PCjr, то светодиоды погаснут, но система будет работать так, будто они активны. Здесь есть одно исключение: состояние NumLock будет сохранено. Дело в том, что эту клавишу KeybJr обрабатывает внутренне, а не передает в виде кода системе. Почему я так сделал? Все просто, потому что PCjr клавишу NumLock не поддерживает.
Также перед подачей питания на микросхему убедитесь в надежном подключении клавиатуры. KeybJr не поддерживает подключение нагорячую, и соответствующий протокол AT/XT должен выбираться до подачи питания (для этого пин PD4 остается висеть в воздухе либо замыкается на GND с помощью перемычки и т.п.) или, хотя бы, после сброса микроконтроллера кнопкой.
Схему я успешно протестировал на старой USB-клавиатуре Microsoft, а именно Chicony PS/2, LogoStar (Copam) K-450 с переключением XT/AT, а также на оригинальной XT-клавиатуре IBM Model F. Если у вас вдруг возникнут сложности при использовании KeybJr с USB-клавиатурой, то попробуйте взять более старую, которая с большей вероятностью будет поддерживать протокол PS/2. Проверить это можно с помощью переходника USB-PS/2 на компьютере, оснащенным портом PS/2.
На этом, дорогие друзья, все!
![](https://habrastorage.org/webt/ou/g5/kh/oug5kh6sjydt9llengsiebnp40w.png)