O Super Nintendo, juntamente com o Megadrive (ou Gênesis) foram os consoles representantes da era 16-bits. Eu tive o Megadrive, mas joguei um bocado em Super Nintendo também.
Já joguei bastante em emuladores, um monte deles, incluindo os de Super Nintendo. Eu não acho que eu jogo mal no teclado, mas eu prefiro usar controles, ainda melhor se os controladores são os do console emulado. Por falar nisso, algum tempo atrás, eu construí um adaptador para ligar controladores SNES para PC a partir das instruções nesse site de Raphaël Assénat’, usando um ATmega 8 e a biblioteca VUSB. Achei que a implementação USB difícil de entender, então eu apenas segui as instruções. O que posso dizer? Funcionou.
Eu queria jogar Super Mario, mas não tinha esse adaptador mais. No entanto, eu tinha um Arduino Micro e placa perfurada. A coisa especial sobre o Arduino Micro, é que como o Leonardo, ele possui USB nativa, sendo capaz de ser reconhecido pelo PC como um teclado, um mouse, um joystick, ou o quer que seja. O Arduino Leonardo é provavelmente adequado para esse propósito também, como também possui uma porta USB nativa.
Nota: Os outros modelos Arduino geralmente usam outro ATmega para lidar com o protocolo USB, enquanto o chip maior é usad0 para o código. Normalmente, o usuário pode nem perceber que a placa tem dois processadores. Os modelos Micro e Leonardo tem uma porta USB no ATmega utilizado (32u4), e apenas um chip é usado para a comunicação USB e código em geral.
Hardware
Eu tive que conectar os controles no Arduino. Para isso eu usei uma veroboard e pinos macho, basicamente. Você pode ver os detalhes abaixo:


A pinagem do controle de Super Nintendo é :
Eu conectei da seguinte forma, mas os pinos podem ser editados em código.
Controle Arduino
5v 5v
data D7
clock D4
latch D5
GND GND
Nota: Cada linha é compartilhada entre os controles, exceto a linha data, isto significa que latch, clock, 5v e GND são os mesmos pros controles conectados, enquanto as linhas de dado devem ser separadas, eu usei o pino D6 para a linha data do segundo joypad. A leitura do código pode esclarecer isso um pouco.
Biblioteca
Eu ainda não sei muito sobre o protocolo USB e sua forma de comunicação, e sempre digo a mim mesmo que vou estudar, mas nunca checo. A questão era que eu queria concluir o projeto em uma tarde. Então fui procurar uma biblioteca.
Opa, eu assumo que você tem a última versão do software Arduino, porque a biblioteca não funciona com a versão 1.6.5 ou abaixo. Se você não tiver a versão 1.6.6, por favor atualize para que possamos continuar. :)
Ok, voltando para o código. A biblioteca eu encontrei funciona muito bem, foi codificada por Matthew Heironimus, e pode ser encontrado aqui. Basta baixá-la e extrair na pasta bibliotecas dos arquivos da IDE do Arduino .
Com esta biblioteca, você pode fazer o Arduino aparecer no computador como até 3 controles. Assim, você pode programar a placa para receber os estados dos botões no controlade e enviá-los para o PC como um controlador USB HID. Eu optei por usar o código para dois controles, pois eu só tinha dois joypads de SNES de qualquer maneira.
Protocolo do controle de SNES
O protocolo de controle de SNES é bastante simples. No conector do controle, têm-se duas linhas de alimentação (5V e terra), e outras três linhas, uma para clock, um para a saida serial(data), e o outro é a linha latch. Para ler os botões, o procedimento é:
- Pulso em alto no pino de latch por 12uS. Isso instrui o controle a guardar o estado dos botões para a leitura.
- O primeiro bit(button B state) já vai estar no pino data, esse bit é lido.
- Troca-se o estado da linha de clock de baixo pra alto, lê-se o bit, e tráz-se a pra estado baixo novamente.
- Repete-se o passo 3 pra os outros 14 bits(16 bits são lidos, mas alguns sempre são ‘1’).
Como dito antes, muito simples. Mais informações podem ser encontradas nesse documento.
Código Arduino.
Finalmente. Se você já instalou a biblioteca e conectou tudo, só gravo o código abaixo e seu adaptador está pronto. Yay!
#include "Joystick2.h" int clk = 4, data1 = 7, data2 = 6, latch = 5; //two data lines, one for each controller. uint16_t buttons1 = 0, buttons2 = 0;//the variables for each controller state const bool testAutoSendMode = false;//we choose when to send the values over USB void setup() { Joystick[0].begin(false);//Initialise the controllers Joystick[1].begin(false); // Pin config pinMode(latch, OUTPUT); pinMode(clk, OUTPUT); pinMode(data1, INPUT); pinMode(data2, INPUT); } int readControllers() { digitalWrite(latch, HIGH);//latch pulse, lock the state of the buttons in the register delayMicroseconds(12); digitalWrite(latch, LOW); delayMicroseconds(6); buttons1 = 0;//zero the variables to receive new values. buttons2 = 0; buttons1 |= (digitalRead(data1) << 0); //first bit read before clock. buttons2 |= (digitalRead(data2) << 0); for (int i = 1; i < 16; i++) {//clock &read digitalWrite(clk, HIGH); delayMicroseconds(6); buttons1 |= (digitalRead(data1) << i);//the values are stored for each bit buttons2 |= (digitalRead(data2) << i); digitalWrite(clk, LOW); delayMicroseconds(6); } buttons1 = ~buttons1; //workaround, a button pressed is read as a '0'(pull ups), jus inversing them to my taste. buttons2 = ~buttons2; } void loop() { readControllers(); //Controller 1 if (buttons1 & (1 << 0)) { Joystick[0].pressButton(0); //B } else { Joystick[0].releaseButton(0); } if (buttons1 & (1 << 1)) { Joystick[0].pressButton(1); //Y } else { Joystick[0].releaseButton(1); } if (buttons1 & (1 << 2)) { Joystick[0].pressButton(2); //Select } else { Joystick[0].releaseButton(2); } if (buttons1 & (1 << 3)) { Joystick[0].pressButton(3); //Start } else { Joystick[0].releaseButton(3); } if (buttons1 & (1 << 4)) { Joystick[0].setYAxis(-127); //Up and Down, -127=total up, 127= total down } else if (buttons1 & (1 << 5)) { Joystick[0].setYAxis(127); } else { Joystick[0].setYAxis(0); //the value zero, means the stick is stopped } if (buttons1 & (1 << 6)) { Joystick[0].setXAxis(-127); //Right left } else if (buttons1 & (1 << 7)) { Joystick[0].setXAxis(127); } else { Joystick[0].setXAxis(0); } if (buttons1 & (1 << 8)) { Joystick[0].pressButton(4); //A } else { Joystick[0].releaseButton(4); } if (buttons1 & (1 << 9)) { Joystick[0].pressButton(5); //X } else { Joystick[0].releaseButton(5); } if (buttons1 & (1 << 10)) { Joystick[0].pressButton(6); //L } else { Joystick[0].releaseButton(6); } if (buttons1 & (1 << 11)) { Joystick[0].pressButton(7); //R } else { Joystick[0].releaseButton(7); } //Controller 2 if (buttons2 & (1 << 0)) { Joystick[1].pressButton(0); //B } else { Joystick[1].releaseButton(0); } if (buttons2 & (1 << 1)) { Joystick[1].pressButton(1); //Y } else { Joystick[1].releaseButton(1); } if (buttons2 & (1 << 2)) { Joystick[1].pressButton(2); //Select } else { Joystick[1].releaseButton(2); } if (buttons2 & (1 << 3)) { Joystick[1].pressButton(3); //Start } else { Joystick[1].releaseButton(3); } if (buttons2 & (1 << 4)) { Joystick[1].setYAxis(-127); //Up Down } else if (buttons2 & (1 << 5)) { Joystick[1].setYAxis(127); } else { Joystick[1].setYAxis(0); } if (buttons2 & (1 << 6)) { Joystick[1].setXAxis(-127); //Right left } else if (buttons2 & (1 << 7)) { Joystick[1].setXAxis(127); } else { Joystick[1].setXAxis(0); } if (buttons2 & (1 << 8)) { Joystick[1].pressButton(4); //A } else { Joystick[1].releaseButton(4); } if (buttons2 & (1 << 9)) { Joystick[1].pressButton(5); //X } else { Joystick[1].releaseButton(5); } if (buttons2 & (1 << 10)) { Joystick[1].pressButton(6); //L } else { Joystick[1].releaseButton(6); } if (buttons2 & (1 << 11)) { Joystick[1].pressButton(7); //R } else { Joystick[1].releaseButton(7); } if (testAutoSendMode == false) { Joystick[0].sendState(); //send the state to the computer. Joystick[1].sendState(); } }
Projeto completo!
É isso, espero que tenha gostado. Obrigado pela leitura e até o próximo artigo o/
The post Controle de Super Nintendo no PC com Arduino Micro. appeared first on Dragão sem Chama.