Sim, procurei nos fóruns do Arduino.cc e aqui. Sim, encontrei os artigos relacionados à biblioteca ps2dev. Sim, li (ok, alguns foram os que li) o artigo definitivo da interface PS / 2 neste site . Sim, eu tenho esse trabalho, meio. Preciso de algumas idéias para dar o salto para o pleno funcionamento. :)
Não, não posso simplesmente emular um teclado USB HID e deixá-lo assim - ele precisa ser uma emulação de teclado PS / 2. Sim, estou enviando sinais adequados de fabricação e interrupção - ele até lida com combinações de teclas muito complicadas. Como está agora, tenho um código escrito para o meu Arduino, como publicado abaixo (tecnicamente um Freeduino 1.22), e enviei pressionamentos de tecla pelo Serial Monitor ou pelo terminal PuTTY, além de um prático wrapper / driver Python que envia mensagens reais. As informações do scancode do PS / 2 - e geralmente facilitam minha vida - também diminuindo parte da carga do Arduino.
No momento, tenho um esboço em execução no Arduino que emula um teclado PS / 2. Naturalmente, tenho que inicializar minha máquina "alvo" (máquina na qual o PS / 2 Plug entra) e vejo o "aperto de mão". Inicialize no WinDoze, abra o bloco de notas e pressione as teclas pressionadas na tela (com sucesso) usando o meu "driver" do Python. (O driver simplesmente ocorre no terminal Serial Monitor / PuTTY e lê / grava na porta serial usando um módulo chamado PySerial.) Isso tudo é feito em um "destino" da placa-mãe AMD na ASUS.
Agora, o objetivo é fazê-lo funcionar na minha Intel na placa-mãe Intel "target", eu conecto, inicializo e não dou dados. Então, modifiquei um pouco o esboço para tentar me informar do que realmente está acontecendo com meu pequeno amigo Ardy. A versão após os mods é exibida abaixo. Pelo que entendi (o código foi "emprestado" de outra postagem no fórum do Arduino.cc, aqui ) Ele tentará estabelecer uma conexão com o "destino" no PS / 2 primeiro, piscando o LED integrado em um período de 0,5 segundo até o conexão estabelecida. O destino da Intel não passa dos 0,5 segundo período piscando e a conexão serial nunca é estabelecida com o "host".
Minha pergunta é a seguinte: existe uma grande diferença na maneira como os teclados ps / 2 estabelecem comunicação com a máquina de destino? É realmente uma diferença de design ou devo procurar algo mais básico que seja o problema aqui? Ouvi algo sobre a necessidade de resistores pull-up nas entradas de dados / relógio, mas isso deve ser tratado no código, especialmente porque está FUNCIONANDO em outro alvo, mas não no que eu preciso trabalhar.
Alguma ideia? Eu adoraria fazer isso funcionar o mais rápido possível - continuarei fazendo a depuração, quaisquer sugestões ou sugestões serão muito apreciadas. Todos serão levados em consideração porque preciso de novos olhos sobre esse assunto. Talvez seja necessária uma melhor implementação na biblioteca ps2dev?
#include "ps2dev.h" // to emulate a PS/2 device
// 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;
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) {
Serial.print('A'); // send a capital A
delay(300);
}
}
void setup() {
pinMode(13, OUTPUT);
//establish serial connection with host
Serial.begin(9600);
// establish ps/2 connection with target
while(keyboard.write(0xAA)!=0){
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
delay(500);
}
delay(100);
connectHost();
Serial.println("\nSerial Host Connected");
Serial.flush();
}
void loop() {
unsigned char c;
if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
if(digitalRead(3)==LOW){
Serial.println("pin 3 is LOW");
} else {
Serial.println("pin 2 is LOW");
}
while(keyboard.read(&c));
kbdCmd(c);
Serial.print("Target: 0x");
Serial.println(c, HEX);
}
else {//if host device wants to send a command:
//echo ASCII code from terminal and write to ps/2
if(Serial.available() > 0) {
incomingByte = Serial.read();
keyboard.write(incomingByte);
Serial.print("Host: 0x");
Serial.print(incomingByte, HEX);
Serial.print(" ");
Serial.print(incomingByte);
Serial.print(" ");
Serial.println(incomingByte, BIN);
}
}
}
Respostas:
Pelo que entendi, você conecta seu Arduino a duas máquinas-alvo diferentes e, em uma, ela funciona e, na outra, não.
Portanto, parece que há uma diferença entre os requisitos de inicialização das duas máquinas. Em desta página na parte inferior há uma listagem de uma seqüência de inicialização possível. Comece comparando sua inicialização àquela.
Será muito mais fácil usar um analisador lógico. Estou usando o Intronix Logicport , mas existem os mais baratos e os melhores, embora não ao mesmo tempo.
Bater em um barramento de coletor aberto é um pouco complicado, porque você não vê qual dispositivo está falando. No entanto, se você colocar um resistor em série no final, onde o pullup não está , poderá saber pelo nível de tensão qual dispositivo está pressionando o barramento. Todo barramento de coletor aberto (como PS / 2) precisa de resistores de pullup, geralmente eles são embutidos no PC. Você pode ver os diferentes níveis de tensão facilmente em um DSO. Com apenas um LA, você deve gravar duas vezes com tensões de limiar diferentes.
fonte
Dado que seu projeto funciona com uma placa-mãe e não com outra, você parece ter um caso clássico de "conformidade parcial de especificações" - em seu projeto e talvez até em uma das placas-mãe. Mas a maioria dos teclados funciona com qualquer placa-mãe, portanto, uma implementação robusta deve ser portátil. O desafio é que você terá que descobrir por que o seu não é.
Você pode fazer isso apenas olhando para o problema e pensando em como ele deve funcionar (talvez depois de um intervalo - ou um dia a resposta o acerte no chuveiro), mas será mais eficaz se puder monitorar o que está acontecendo. Para questões elétricas que significam um escopo, para protocolos um analisador lógico. Existem algumas opções baratas disponíveis nessa área, por exemplo, a placa "barramento pirata", que possui alguma capacidade específica para protocolo de teclado ou algo baseado em FPGA, que pode ter um buffer de captura mais longo (consulte sump.org).
Outra coisa que você poderia tentar seria usar outro dispositivo, um microcontrolador ou um FPGA, para criar um host de teclado e usá-lo para testar seu projeto dentro dos limites da especificação.
fonte
Eu não olhei para a biblioteca ps2dev para ver exatamente como ela funciona, mas uma coisa me impressiona.
No momento, é feita uma única tentativa de conexão com o computador "host". Quando isso falha, um segundo inteiro é aguardado (LED aceso 0,5s, LED apagado 0,5s) antes de outra tentativa.
Se a placa-mãe da Intel não estiver aguardando o tempo suficiente para a detecção do teclado, ela poderá nunca estar recebendo a tentativa de conexão antes de continuar sua sequência de inicialização.
Se você diminuir o tempo de espera para dizer 0,1s (altere as linhas de atraso (500) para atraso (50)), poderá ter alguma sorte.
Caso contrário, tente ainda mais rápido. Inferno, até tente sem demora e veja como isso acontece.
fonte