Um Pouco de História
O teclado do PC IBM original utilizou um conector DIN de 5 pinos e uma comunicação serial unidirecional (do teclado para o PC) usando dois sinais (dado e clock). No PC AT o conector foi mantido, porém o protocolo foi alterado para permitir comunicação bidirecional. Por último, nos computadores PS/2 o conector foi trocado por um DIN de 6 pinos de dimensão menor.
Porque Usar Um Teclado PS/2?
A interface e o protocolo são simples (principalmente comparados com USB) e ainda se encontra uma quantidade grande destes teclados em boas condições. O conector DIN fêmea pode dar um pouco de trabalho para achar (eu comprei no eBay), mas sempre existe a opção de cortar a ponta do cabo e colocar um conector diferente.
A Interface Elétrica e o Protocolo
Do ponto de vista elétrico temos apenas dois sinais (fora a alimentação e terra): Dado e Clock. Estes sinais são do tipo "coletor aberto", ou seja, normalmente estão flutuando (pullups garantem um nível alto) e podem ser colocados em nível baixo por qualquer um dos lados.
Na situação de repouso os dois sinais estão "soltos" e portanto em nível alto.
Para enviar um byte, o teclado inicia a transmissão conferindo que o clock está no nível alto e colocando o sinal de dados em nível baixo. A partir daí são enviados 11 bits (a começar por este zero); o sinal de dados é posicionado enquanto o clock está alto e depois o teclado força o clock para baixo para indicar que o bit pode ser lido. Os 11 bits correspondem a um start (sempre 0), 8 bits de dados, 1 bit de paridade (impar) e um stop (sempre 1).
O teclado envia, na maioria dos casos, um byte quando uma tecla é apertada (o scancode). Quando a tecla é solta, ele envia dois bytes: F0 e o scancode. Algumas teclas (extended keys) geram dois bytes quando apertadas (E0 scancode) e três quando soltas (E0,F0 scancode).
Para o PC (ou outro host) enviar dados para o teclado, ele deve primeiro segurar o clock em nível baixo, para inibir transmissões pelo teclado. Em seguida o sinal de dados deve ser colocado em nível baixo (start) e o sinal de clock deve ser solto. A partir daí a linha de clock será controlada pelo teclado, que a colocará em nível baixo quando o PC deve controlar a linha de dados. O PC enviará 11 bits (start, dados, paridade, stop) e em seguida aguardar um bit de confirmação do teclado.
Referência (e origem das figuras acima): https://www.avrfreaks.net/sites/default/files/PS2%20Keyboard.pdf
Software para o Arduino
Uma biblioteca simples para tratar a conexão de um teclado PS/2 ao Arduino é descrita nem https://playground.arduino.cc/Main/PS2Keyboard, e o código mais recente está em https://github.com/PaulStoffregen/PS2Keyboard.
Uma biblioteca mais sofisticada pode ser vista em https://github.com/techpaul/PS2KeyAdvanced.
O princípio básico de ambas é o mesmo: o sinal de clock é conectado a um pino do Arduino capaz de gerar uma interrupção quando o sinal passar do nível alto para o baixo. Na PS2Keyboard é tratado apenas a recepção e a rotina de interrupção lê o sinal de dados e monta o código recebido. A PS2KeyAdavanced suporta comunicação bidirecional. Portanto a rotina de interrupção irá ler ou posicionar o sinal de dados conforme a operação.
Uma vez recebido um código do teclado, é preciso decodificá-lo, tomando o cuidado de manter o estado das teclas modificadoras (shift, caps lock, control e alt).
Para um teste rápido, vamos fazer as seguintes ligações entre um teclado PS/2 e um Arduino Uno ou Nano:
- Clock do teclado no pino 3 do Arduino
- Dado do teclado no pino 2 do Arduino
- +5V do teclado no +5V do Arduino
- GND do teclado no GND do Arduino
/* * Teste de interface com teclado PS/2 * * Dados do teclado no pino 2 e clock no pino 3 */ // fila para os códigos recebidos const byte tamfila = 16; byte poe = 0; byte tira = 0; byte fila[tamfila]; void setup() { // iniciar os pinos pinMode (2, INPUT_PULLUP); pinMode (3, INPUT_PULLUP); pinMode (13, OUTPUT); digitalWrite(13, LOW); // vamos mostrar os códigos na serial Serial.begin(9600); Serial.println("Pronto"); // assumir a interrupção do sinal de clock attachInterrupt(digitalPinToInterrupt(3), kbdint, FALLING); } void loop() { // verifica se tem algum código na fila if (poe != tira) { // mostra Serial.println (fila[tira], HEX); // tira da fila byte prox = tira+1; if (prox == tamfila) { tira = 0; } else { tira = prox; } } } // Trata a interrupção do teclado void kbdint(void) { static byte cod = 0; static byte nbit = 0; // le o bit de dados int dado = digitalRead(2); // despreza start, paridade e stop if ((nbit > 0) && (nbit < 9)) { cod = cod >> 1; if (dado == HIGH) { cod |= 0x80; } } nbit++; if (nbit == 11) { // coloca na fila fila[poe] = cod; byte prox = poe+1; if (prox == tamfila) { prox = 0; } if (prox != tira) { poe = prox; } nbit = cod = 0; } }
08/02/20: Corrigida a figura com a pinagem dos conectores.
19/05/21: Corrigida a conexão ao Arduino (dado e clock estavam invertidos)
3 comentários:
Belo post. Mas a busca que estou fazendo e o que me pergunto se é possível, é se, poderíamos fazer o Arduino trabalhar como um teclado. Quero fazer um hack para jogos, onde de tempos em tempos, o Arduino "apertaria" certa tecla do PC. Não muda nada em sua busca,mas sigo na minha. =D Belo blog.
Olicheski, nunca vi isto, mas com certeza dá para simular um teclado PS/2 com um Arduino. Se você quiser simular um teclado USB, de uma procurada por "usb rubber ducky arduino". Eu já fiz uma experiência usando um microcontrolador ATtiny85 para "digitar" as leituras do ADC: http://dqsoft.blogspot.com/2012/08/attiny-4585-ligado-usb.html e http://dqsoft.blogspot.com/2012/09/attiny-4585-ligado-usb-colocando-para.html.
Isso é verdade.
Postar um comentário