Ps2 клавиатура для arduino

PS2Keyboard

Раньше мыши и клавиатуры подключались к компьютерам через отдельный интерфейс PS/2. Сейчас их вытеснил USB-интерфейс, но возможно у кого-то ещё завалялись старые мыши и клавиатуры. У клавиатур штекер и гнездо фиолетового цвета, а у мышей зелёного. Но этот цветовой стандарт появился позже, до этого производители не заморачивались, поэтому можете встретить штекер без цветовой индикации.

Существует библиотека для связи клавиатуры на PS/2 с Arduino. О ней и пойдёт речь.

Для начала схема штекера и гнезда. Нас интересует в первую очередь распиновка штекера. Обращайте внимание на верх и низ штекера. У гнезда распиновка находится в зеркальном отображении. Гнездо вам понадобится, если вы будете собирать проект и подсоединять выводы к плате. В учебном примере я взял джамперы папа-мама и аккуратно воткнул их в штекер.

Установить библиотеку проще через Arduino IDE. Заходим в Sketch | Include Library | Manage Libraries и через поиск находим нужную библиотеку. Нажимаем кнопку Install и устанавливаем её. В разделе File | Examples появится новый раздел PS2Keyboard с двумя примерами: International и Simple_Test.

Simple_Test

В комментариях к скетчу написано, что для Arduino Uno следует использовать выводы 2 или 3 для прерываний. Первый вывод Data, выходящий из вывода клавиатуры, соединяем с выводом 8 на плате, третий вывод соединяем с GND, пятый — с выводом 2 на плате, четвёртый с 5V (питание). Второй и шестой выводы штекера не используются.

Запускаем скетч, открываем Serial Monitor и начинаем печатать. Кроме обычных символов в разных регистрах, печатаются также и служебные клавиши типа Стрелка Вверх, Page Up и т.д.

International

Второй пример поддерживает клавиатуры на других языках. На данный момент доступны французский и немецкие раскладки. В скетче нужно выбрать требуемый вариант.

Источник

Подключение PS/2 клавиатуры

Подключение клавиатуры к Arduino не представляет из себя ничего сложного. Для этого используется всего 4 линии: питание +5В, общий, данные и синхросигнал.

Помимо платы Arduino, понадобится разъем PS/2 Female. Я поступил просто — выпаял разъем из старой сгоревшей материнки. Получилось вот что:

Подключение следует производить согласно нижеприведенной распиновке:

1 — Данные (подключите к pin 2 Arduino)
3 — Общий (подключите к GND Arduino)
4 — Питание 5В (подключите к 5V Arduino)
5 — Синхросигнал (подключите к pin 3 Arduino)

После подключения клавиатуры, скачайте библиотеку PS2Keyboard и перепишите ее содержимое в папку Libraries->PS2Keyboard

Подключите контроллер и перезапустите среду разработки Arduino. Проверьте, чтобы в меню Sketch->Import Library и в File->Examples появилось PS2Keyboard. Если не появилось, то проверяйте пути.

Загрузите в среду разработки пример File->Examples->bitlash->PS2Keyboard и загрузите скетч в контроллер.

Откройте Serial Monitor и попробуйте понажимать клавиши на клавиатуре. В окне должны отображаться символы нажатых клавиш.

Вот и все. Как видите все очень просто. Какое применение можно найти — решать вам, к примеру можно прицепить все это к терминалу, использовать как аппаратный кейлоггер, управлять роботами или сделать MIDI клавиатуру.

Источник

Подключаем к Arduino клавиатуру PS/2

В данной статье рассматривается, как добавить к Arduino 106 кнопок ввода, а именно подключить к Arduino клавиатуру PS/2.

Подключаем к Arduino клавиатуру PS/2

Что нам понадобится:

Шаг 1: подключение клавиатуры

Ниже приведена распиновка разъема. От клавиатуры приходит 4 провода, их подключение к Arduino показано ниже:

  • 5В – выход Arduino 5V
  • Земля – Arduino GND
  • Тактовый сигнал – вывод 3 Arduino
  • Данные – вывод 8 Arduino

Печатная плата в клавиатуре PS/2 Распиновка разъема клавиатуры PS/2 Подключение клавиатуры PS/2 к Arduino

Шаг 2: код

Сначала добавьте в Arduino IDE библиотеку PS2Keyboard .

Шаг 3: тестирование

Итак, мы закончили написание кода. Загрузите его в Arduino и оставьте Arduino, подключенной к компьютеру. Затем откройте монитор последовательного порта в Arduino IDE и нажмите несколько клавиш на клавиатуре, подключенной к Arduino, и вы увидите, что она напечатает то, что вы набираете на этой клавиатуре. Вот и всё!

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.

Добрый день!
Проверить, на равенство коду 144.
Коды клавиш можно проверить тут — https://keycode.info/ , или можно самому вывести полученное от клавиатуры значение в монитор последовательного порта.
Если всё работает, то в файле PS2Keyboard.h можно определить еще одну константу, скажем

Добрый день!
А как отловить клавишу NumLock ?

Источник

PS2 клавиатура к Ардуино

Подключить PS/2 клавиатуру к Arduino совсем не сложно, но порой просто жизненно необходимо. Пытаетесь ввести данные в микроконтроллер? Не хотите «заморачиваться» с паянием кнопок? Увлекаетесь геймингом и заодно конструированием? В этих и других ситуациях на помощь вам придет компьютерная клавиатура и наша простая пошаговая инструкция по ее подключению.

Для работы нам понадобится следующее «железо»:

  • плата расширения Arduino Uno (как пример, можно и другие);
  • клавиатура PS/2;
  • разъем PS/2 Female (мама).

Для первого шага рекомендуем использовать нижеприведенные распиновку коннектора PS2 и схему подключения:

Второй этап – скачивание и добавление специализированной библиотеки PS2Keyboard для создания пользовательского объекта, приема ∕ считывания ∕ проверки и обработки нажатий. Ее желательно закидывать в папку Libraries> PS2Keyboard. Выбирайте последнюю версию ПО.

И, наконец, самое интересное – заливаем скетч в контроллер (копируем коды так, как есть, без изменений и корректировок):
Теперь следует протестировать функциональность подключенного устройства — открываем Serial Monitor в Ардуино IDE, нажимаем клавиши на клавиатуре. Если все сделано правильно, на экране выведется все написанное. Готово!

При желании можно подключить к нашей схеме дисплей ∕ светодиоды и проводить тесты другого плана (но тут вам понадобится докупить аппарат с интерфейсом I2C, инсталлировать еще одну библиотеку, а также запастись временем и терпением для настройки всего проекта).

Наш гайд получился супер-лаконичным по той простой причине, что подключение PS/2 клавиатуры к Arduino считается базовым уроком для новичков, а потому проблем возникнуть не должно. На этом пока всё. Хороших вам проектов!

Источник

Rukodelie-DS.ru

Форум магазина «Дамское счастье»

Эмулятор клавиатуры или мыши ps/2.

Эмулятор клавиатуры или мыши ps/2.

Сообщение dtvims » Чт сен 06, 2012 12:33 am

Появилась у меня задача сделать некоторое устройство, управляемое с одного компа, подключенное к другому как мышь или клавиатура. Попалась мне на глаза отладочная плата микроконтроллера arduino. В целом это готовое решение по работе с микроконтроллерами ATmel. Почитав про нее подробнее, я понял, что это то что мне надо. Для обучения работы с микроконтроллерами Arduino в самый раз. Многие скажут, что для моей задачи есть варианты и лучше, и со штатной поддержкой USB, но для начинающих лучше начинать с чего-то простого и хорошо раскрученного.
Итак я нашел кучу описаний как можно проэмулировать и клавиатуру и мышь на arduino благодаря библиотеке ps2dev найденную на сайте ардуинки http://arduino.cc/playground/componentLib/Ps2mouse. Там описание почти никакое, поэтому необходимо обратиться за помощью к бывалым:

На этом описание заканчивается, а проблемы нет!
1. Проблема аккуратности подключения провода с разъемом ps/2. Можно перепутать провода — это понятно. Можно получить плохой контакт, т.е. вроде он есть, но. Когда я просто взял провод от старой мышки и подключил его согласно схеме к ардуинке у меня от компа приходили постоянно reset и resend. Выходит, что arduino получает команды хоста, а отправить ответ правильно не может или не всегда отправляет. Проблема оказалась в плохом контакте, видать искрило. Кстати, я так и не понял нужно ли от порта ps/2 подключать к контролеру «Vcc +5», если контроллер питаетс от usb другого компа? Земля, разумеется общая, поэтому подключение обязательно, а vcc я оставил в итоге в воздухе, походу от нее скорее проблему будут, если конечно устройство не должно питаться от ps/2.
2. Данные вроде пошли верно, но устройство зависает, хотя инициализацию проходит. Стал разбираться. В описании протокола нашел следующее: «Контроллер материнской платы может сигнализировать устройству о невозможности приема опустив сигнал Clock в логический ноль. На практике этого по моему тоже никто не делает». Проверка путем подключения ардуинки к другому компу доказала мое предположение — тут все завелось сразу. Так в чем же дело? Демонстрационный скетч, который я использовал, выводил информацию чрез com-порт на ноутбук, которым я заодно и перепрошивал ардуинку. Одним из выводимых параметров был текст на каком Pin`е был опущен сигнал, когда программа начинает прием данных от хоста, а затем только принятый байт команды от хоста. Собственно, во время инициализации все шло хорошо, т.к. хост постоянно что-то запрашивал у устройства, а затем хост «Должен» поднимать clock и data, как бы говоря, что просто слушает порт. Но в поднятом состоянии оба pin`а находились всего пару секунд. Затем опускался clock и программа переходила в режим приема данных от хоста и все. Выходит это и есть тот самый случай, когда контроллер хоста запрещает передавать даные. Т.е. один мой комп постоянно слушает порт, а другой переиодически хочет отдохнуть — непорядок!
Смотрим код библиотеки ps2dev (C:\arduino-1.0.1\libraries\ps2dev\ps2dev.cpp), а главное команду read():

//wait for data line to go low
while (digitalRead(_ps2data) == HIGH) <

>
//wait for clock line to go high
while (digitalRead(_ps2clk) == LOW) <

Первая команда ожидает когда data будет опущен на землю, но поскольку хост и не собирался передавать данные, то это не происходит до тех пор, когда хосту действительно не понадобиться передать данные (например, при перезагрузке компа). Получается, что это и есть точка, где подвисает программа. Согласно протоколу, должен быть сперва опущен clock, затем data, затем, они оба поднимаются и ожидается подтверждение приема. Данный код подразумевает, что передача данных должна обязательно начаться, а вот нет. Нам надо, если data так и не опущен, а clock все-равно подняли — отменить прием данных.
Патчим бибилиотеку до:

//wait for data line to go low
while (digitalRead(_ps2data) == HIGH) <
if(digitalRead(_ps2clk) == HIGH) <
*value=0;
return 0;
>
>
//wait for clock line to go high
while (digitalRead(_ps2clk) == LOW) <

// Orange = 2
// Blue = 3
// Red = 5V (3 in)
// Black = GND (4 in)
// EXT Power, USB for COM only

PS2dev keyboard(3,2); // PS2dev object (2:data, 3:clock)
int enabled = 0; // pseudo variable for state of “keyboard”
boolean serialConnected = false;
int incomingByte = 0;
int tempint=0;

void ack() <
//acknowledge commands
while(keyboard.write(0xFA));
>

int kbdCmd(int command) <
unsigned char val;
switch (command) <
case 0xFF: //reset
ack();
//the while loop lets us wait for the host to be ready
while(keyboard.write(0xAA)!=0);
break;
case 0xFE: //resend
ack();
break;
case 0xF6: //set defaults
//enter stream mode
ack();
break;
case 0xF5: //disable data reporting
//FM
enabled = 0;
ack();
break;
case 0xF4: //enable data reporting
//FM
enabled = 1;
ack();
break;
case 0xF3: //set typematic rate
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
case 0xF2: //get device id
ack();
keyboard.write(0xAB);
keyboard.write(0x83);
break;
case 0xF0: //set scan code set
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
case 0xEE: //echo
//ack();
keyboard.write(0xEE);
break;
case 0xED: //set/reset LEDs
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
>
>

void connectHost() <
while (Serial.available() -‘0′ && c =’a’ && c =’a’ && c =’A’ && c 0) <
//incomingByte = Serial.read();
incomingByte=SerialreadHEX();
delay(5);
if(incomingByte>-1 && Serial.available() > 0) <
tempint=SerialreadHEX();
if (tempint>-1) <
incomingByte=(incomingByte*16)+tempint;
>
>
keyboard.write(incomingByte);
Serial.print(«ost: 0x»);
Serial.print(incomingByte, HEX);
Serial.print(» «);
Serial.print(incomingByte);
Serial.print(» «);
Serial.println(incomingByte, BIN);
>
>
delay(10);
>

Изначально код был написан неким автором (прошу прощения, потерял где взял) и доработан немного мной для более удобной отладки. Сперва устройство будет ждать инициализации com-порта, т.е. будет на него слать «а», до тех пор пока небудт получен ответ от порта в виде любого байта. Как-только в буфере контроллера окажется хоть один байт, наш эмулятор заработает. Включем испытуемый комп. Далее в «мониторе порта» мы видим как комп инициализирует клаву. Винда тоже будет ее инициализировать когда загрузится. Теперь мы можем тоже слать данные.
http://www.computer-engineering.org/ps2keyboard/scancodes2.html — тут мы видим коды клавишь. Разумеется они никак не соответсвуют кодировкам. Поэтому я сделал прием по два байта с com-порта, представляющих собой HEX код клавиши, которая будет отправлена хосту. Например вводим «1СА01С», будет проинтерпритировано как нажатие клавиши «a» (0х1C), и отпускание ее (0xF0, 0x1C). В открытом блокноте (если конечно его открыли), можно увидеть появившийся символ «a».

Вариантов использования море! Главное наконец заработало.
Далее добавлю скетч для тестирования мышки.

Эмулятор мыши ps/2 на arduino НЕ РАБОТАЕТ. РЕШЕНО.

Сообщение dtvims » Пн сен 10, 2012 3:12 pm

После всех мучений проблем с клавиатурой, с мышой проблем возникнуть не должно! Так думал я, загружая скетч примера эмуляции мыши. Но он не заработал ни на одном из имеющихся у меня компов.
Я стал проверять, может мои дороботки в библиотеке, что-то нарушили? Я брал доделки из скетча про клавиатуру и переносил в скетч мыши и получал что-то непонятное, хотя там все работало, а тут.
В итоге решил сделать снифер ps/2 порта и посмотреть как общается реальная мыша с компом — она работала без проблем на всех компах. Я разобрал мышку и подтянул от туда провода: clock (pin 3), data (pin 2) и gnd. Я их тупо отвел на контроллер. Поскольку gnd общий, а мне надо только слушать, то поидее никаких сложных схем подключения не требуется.
Первый скетч показал, что вывод стразу лога протокола ps/2 на com-порт — неработоспособен, поскольку передача через com-порт слишком долгая по времени, а между тактами clock проходит от 20 микросекунд и мне нельзя попустить ни одно изменение. Также, если все ходы просто писать в память, то памяти ATmega32 просто не хватит для этого.
В итоге получился такой скетч (кому интересно):

int stclk=0;
int stdat=0;
int i=0;
unsigned long tm[150];
int arclk[150];
int ardat[150];

void gohi(int pin)
<
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
>

void golo(int pin)
<
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
>

void setup() <
Serial.begin(9600);
Serial.println(«\nSerial Host Connected»);
Serial.flush();
gohi(2);
gohi(3);
>

void loop() <
int vl3;
int vl2;

Его основной недостаток, что если во время передачи логов на com-порт хост или устройство начнет передавать данные, то я не услышу (т.е. в логи это не попадет).
Так и вышло. Я получал? что хост отправил FF, мышь ответила FA, а дальше тишина, т.е. команд AA и 00, следующих далее от мыши я не получал. Как реально отвечает мыша я проверял по вот такому примеру http://robocraft.ru/blog/arduino/101.html. Однако я увидел там как работает реально протокол. Я увидел, что между командой хоста и ответом устройства проходит чуть более 100 микросекунд. А когда я продолжил эксперименты с эмулятором мыши, хост постоянно повторял одни и те же команды по много раз. Я сделал вывод, что хост ждет ответа несколько сотен микросекунд и если его не получает, то шлет запрос повторно. А вывод отладочной информации на com-порт занимает более 1 милисекунды — видимо тут один из косяков.
Что сделано:
1. В ps2dev в функциях read и write в конце скорректирована/добавлена задержка в 100 микросекунд. Я сделал расчет, что несколько микросекунд программа будет обрабатывать команду и запускать на выполнение команды ответа, то как раз получится задержка в 100 микросекунд с чуть-чутем.
2. Убрал из скетча все затормаживающие элементы между приемом/отправкой связанных данных, а оставил только уж по окончанию как факт о случившемся.
3. Поскольку в процессе отладки скетча, после первых двух доработок, хост продолжал повторно слать одни и те же команды, я проверил по документации http://www.computer-engineering.org/ps2mouse/ как именно должны отрабатываться устройством эти команды, т.е. добавил обработку команд, на которые в примере было ответом только подтверждение о приеме команды.
Вот что получилось:

PS2dev mouse(3,2); // 2 data 3clock

int delta_x = 0;
int delta_y = 0;
//we start off not enabled
int enabled =0;
int incomingByte=0;
int tempint=0;
int sr=20;
int rsl=0;
int oldcmd;

//ack a host command
void ack() <
while(mouse.write(0xFA)!=0);
>

void write_packet() <
char overflowx =0;
char overflowy =0;
char data[3];
int x,y;

if (delta_x > 255) <
overflowx =1;
x=255;
>
if (delta_x 255) <
overflowy =1;
y=255;
>
if (delta_y >8) & 1) >8)& 1) -‘0′ && c =’a’ && c =’a’ && c =’A’ && c 0) <
incomingByte=SerialreadHEX();
delay(5);
if(incomingByte>-1 && Serial.available() > 0) <
tempint=SerialreadHEX();
if (tempint>-1) <
incomingByte=(incomingByte*16)+tempint;
>
>
while(mouse.write(incomingByte)!=0);
Serial.print(«ost: 0x»);
Serial.print(incomingByte, HEX);
Serial.print(» «);
Serial.print(incomingByte);
Serial.print(» «);
Serial.println(incomingByte, BIN);
>
>
if (enabled) <
// move the mouse diagonally
delta_x = 1;
delta_y = 1;
write_packet();
>

О чудо — данный скетч заработал!

/*
* ps2dev.cpp — an interface library for ps2 host.
* limitations:
* we do not handle parity errors.
* The timing constants are hard coded from the spec. Data rate is
* not impressive.
* probably lots of room for optimization.
*/

#include «Arduino.h»
#include «ps2dev.h»

//since for the device side we are going to be in charge of the clock,
//the two defines below are how long each _phase_ of the clock cycle is
#define CLKFULL 40
// we make changes in the middle of a phase, this how long from the
// start of phase to the when we drive the data line
#define CLKHALF 20

/*
* the clock and data pins can be wired directly to the clk and data pins
* of the PS2 connector. No external parts are needed.
*/
PS2dev::PS2dev(int clk, int data)
<
_ps2clk = clk;
_ps2data = data;
gohi(_ps2clk);
gohi(_ps2data);
>

/*
* according to some code I saw, these functions will
* correctly set the clock and data pins for
* various conditions. It’s done this way so you don’t need
* pullup resistors.
*/
void
PS2dev::gohi(int pin)
<
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
>

void
PS2dev::golo(int pin)
<
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
>

int PS2dev::write(unsigned char data)
<
unsigned char i;
unsigned char parity = 1;

if (digitalRead(_ps2clk) == LOW) <
return -1;
>

if (digitalRead(_ps2data) == LOW) <
return -2;
>

golo(_ps2data);
delayMicroseconds(CLKHALF);
// device sends on falling clock
golo(_ps2clk); // start bit
delayMicroseconds(CLKFULL);
gohi(_ps2clk);
delayMicroseconds(CLKHALF);

for (i=0; i > 1;
>
// parity bit
if (parity)
<
gohi(_ps2data);
> else <
golo(_ps2data);
>
delayMicroseconds(CLKHALF);
golo(_ps2clk);
delayMicroseconds(CLKFULL);
gohi(_ps2clk);
delayMicroseconds(CLKHALF);

// stop bit
gohi(_ps2data);
delayMicroseconds(CLKHALF);
golo(_ps2clk);
delayMicroseconds(CLKFULL);
gohi(_ps2clk);
delayMicroseconds(CLKHALF);

delayMicroseconds(100);
return 0;
>

int PS2dev::read(unsigned char * value)
<
unsigned char data = 0x00;
unsigned char i;
unsigned char bit = 0x01;

unsigned char parity = 1;

//wait for data line to go low
while (digitalRead(_ps2data) == HIGH) <
if(digitalRead(_ps2clk) == HIGH) <
*value=0;
return 0;
>
>
//wait for clock line to go high
while (digitalRead(_ps2clk) == LOW) <

delayMicroseconds(CLKHALF);
golo(_ps2clk);
delayMicroseconds(CLKFULL);
gohi(_ps2clk);
delayMicroseconds(CLKHALF);

Мне говорили, что USB сложнее, но по USB полно примеров, а вот по ps/2 очень мало. Видимо это следствие того, что ps/2 стал вытеснятся usb. Однако, если еще не так давно с материнских плат стали исчезать порты ps/2, то на последних они стали возвращаться. Зачем? Видимо из-за использования свичей для переключения между системными блоками, в которых использоваться может что-то одно и если свитч на ps/2-ные мышь и клаву, то через эти порты они и должны подключаться на каждом системнике. Мышь и клава давно научились поддерживать одновременно оба интерфейса, а вот свичи нет. Т.о. ps/2 — это, хоть и устаревший интерфейс, но жизнестойкий!

Вариант использования:
На различных предприятих очень жесткие правила политики безопасности, могут быть ограничены права пользователя в системе, может быть заблокировано использование внешних устройств (например USB флешек и т.п.) и не отключаемый скринсейвер, а может и лог присутствия на рабочем месте. А ведь даже для работы бывает необходимо что-то включить, а скринсейвер сбивает работу. Или необходимо симулировать свое присутствие на рабочем месте. Была такая история, что кому-то необходимо было обойти скринсейвер, для этого прицепили провод мыши к cd-rom`у и написали простенькую прогу для открывания закрывания привода cd-rom. На ПО может не хватить прав, чтобы обойти такую защиту. Механические системы вроде цепляния к проводу мышки к cd-rom`у не надежны. А Ps/2 обычно ни чем не защищен, поэтому нам ничто не мешает нацепить на него эмулятор мышки.

Re: Эмулятор клавиатуры или мыши ps/2.

Сообщение dtvims » Вт сен 11, 2012 9:22 am

В добавлении к протоколу PS/2.
Нашел некие обсуждения на форумах:
1. Работа мышки перебивает работу клавиатуры.
2. При передачи от устройства к хосту присутствует сигнал ack от хоста, что данные получены.

1. Мы в реальных условиях такого ни разу не замечали. Разумеется, что если передавать данные не глядя, то можно попасть на режим, когда хост запрещает передачу данных опуская clock на землю и тогда данные не дойдут.
Судя по рассуждениям форумчан, не смотря на независимость работы портов мыши и клавиатуры, они не могут обрабатываться независимо и поэтому, во время работы одного из них на втором хост опускает clock. Таким образом, если проверять свободу на линии, то потерь передачи данных не должно возникнуть.
2. Согласно описанию протокола сигнал ack присутствует только при передаче от хоста к устройству. Обратно такого нет. Это же подтверждает исследование снифером. Однако возможна ситуация, что сразу после передачи данных хост может опускать clock на землю, просто ради того чтобы устройство прекратило временно передачу. Данный сигнал очевидно нельзя принимать за ack.

Клавиатура и Мышь одновременно на одном контроллере.

Сообщение dtvims » Пн сен 24, 2012 3:50 pm

Клавиатура и Мышь одновременно на одном контроллере.
Стоит заметить, что на предложенной библиотеке не сделать адекватно работающие одновременно сразу 2 устройства ps/2. Не смотря на то, что я раннее писал, что хосты на материнской плате ПК вещают в разное время, т.е. конфликтовать не должны. Оказалось, что хост для мыши начинает создавать запрос, опускает на землю сперва clock (отработано заглушкой выше), а затем опускает data, что согласно протоколу является началом передачи данных. Но реально данные начинают передаваться только когда хост отпустит data. Даже если реально данных никаких хост не отправит, согласно протоколу, устройство данный сигнал воспримет как FF. Самое интересно, что на FF обязательно последует ответ, а если ответ не будет получен хостом, то он тихо воспримет это как полное отсутсвие устройства. Одним словом, замкнуты круг. Можно, наверное поставить еще одну заглужку. НО! Для нормальной инициализации клавы или особенно мышки, важно отвечать ровно как хост запросит информацию. Далее я выяснил, что все задержки между приемом и передачей данных устройством должны быть минимальны и снова, НО! Оказалось, что хост делает запрос, а затем держит clock опущенным некоторое время (где-то до 1 милисекунды, притом что протокол ps/2 делает перерывы между итерациями 20-40 микросекунд). Т.о. получается, что нам надо срочно передавать данные, да еще и ждать, когда можно будет передавать, а во время ожидания может пройти запрос и на другое устройство, а ведь может и пользователь со своей командой встрять.
Как правильно решить данную проблему?
Опытные программисты, скажут, что надо вешаться на прерывания таймера и обрабатывать запросы в несколько потоков.
Как настроить таймер — это вообще отдельная тема, вроде и документации много, а как сделать то что я хочу не совсем ясно. Тут у меня возникли непонятки почему при одних и техже настройках таймер в одном случае вызывает прерывание через 40мкс, а вдругом 20мкс (как мне и надо было).
В общем я добился прерываний раз в 20мкс. это необходимо как минимальное время бездействия по потоколу (например, мы поднимем clock, ждем 20мкс, задаем data, ждем 20мкс и опускаем clock).
Далее опишу в общих словах алгоритм, что происходит внутри прерывания раз в 20 микросекунд:
1. В самых первых строках я через порты устанавлию/снимаю сигнал с clock и data, просто снимаю состояние и сохраняю в памяти, а затем сразу ставлю значения, которые до этого уже были расчитаны за ранее. Если расчеты делать перед установкой значений, сразу после срабатывания прерывания, то не возможно будет соблюсти точность сигнала с паузами в ровно 20микросекунд.
2. Для реализации протокола я создал, наверное, несколько конечных автоматов (или один). 1-й автомат меняет основные состояния устройства. Проверка хоста, хочет ли он что нам сказать? Прием данных от хоста. Передача данных хосту. И наконец служебный контроллер для определения, нужен ли ответ хосту дать или принять от хоста настройки. Т.е. есть 4 состояния.
2.1 Проверка на передачу данных от хоста осуществляется простыми проверками состояний сигналных контактов, см п.1. Тут также посчет времени, а сколько у нас держался clock? и т.п.
2.2. Если хост проинициировал передачу данных, то отправляемся в следующее состояние «прием».
2.3. «Прием» (абсолютно аналогично «передача») осуществляется итерационно (2-й автомат). Сперва ожидание когда хост отпустит data. Затем начинаем расчитывать, что при будетследующей итерации (вспоним, что в п.1 устанавливатся состояния контактов согласно за ранее расчитанным позициям). Нужно начать генерить сигнал синхронизации clock. И далее в нужный момент начинаем снимать стояние data (устанавливать, если передаем). Каждое новое состояние — новая итерация по протоколу (как-то так).
2.4. Поле приема отправлем на служебный контроллер.
2.5. Контроллер смотрит что была за команда принята, а в нем забиты действия вроде «отправить ACK, принять байт, отправить ACK».
2.6. Передача данных (3-й автомат). Аналогично приему расчитывает за ранее следующую итерацию. После пердачи, снова на контроллер.
2.7. Если контроллер отследил, что запрос хоста отработан верно, т.е. все необходимые ответы отправлены и настройки получены, то переводит в состояние по п.2.1.
3. Если никаких данных от хоста принимать не следует, то можно заняться обработкой пользовательских запросов. После проверок состояний п.2.1. вставляем пользовательский контроллер, который считывает данные из буфера на передачу и отправит данные на хост с помощью п.2.3.

Все пункты реализованы в одном прерывании таймера одновременно. Сперва считываются/устанавливаются состояния на пинах мыши и клавиатуры, затем для них расчитывается, что делать дальше.

На этот раз обойдусь без исходников, скажу только, что алгоритм работает. Его можно доработать в плане настройки пирема параметров от хоста, т.к. там еще много мелких тонкостей осталось. Таже есть возможность ошибок буфера данных, если пользователь будет пытаться передавать команды мыши во время инициализации мыши, но это мало вероятных случай, хотя возможен (ошибка может возникнуть из-за того, что пакет данных от мыши состоит из 3-х байтов и, если хост их будет принимать начиная со второго, то получит что-то иное нежели хотел пользователь.

Источник

Adblock
detector