A plataforma Arduino tem suas qualidades e seus defeitos, mas sem entrar nesse mérito, uma coisa é inegável: A plataforma que 'pegou'. É fácil de encontrar para comprar, e qualquer um pode programar facilmente plataforma, usando seu computador, seja ele um PC ou Mac, sem a necessidade de hardware de programação especial.
Sendo assim, eu resolvi refazer o adaptador de Nunchuck para MSX mas desta vez usando um Arduino como plataforma.
Eu chamo de refazer pois já havia implementado o adaptador utilizando um 68HC908 em encapsulamento TSSOP, mas veio a dúvida: quantas pessoas poderiam replicar um adaptador assim? Daí a escolha do Arduino.
Segue abaixo o diagrama de conexão:
Eis o circuito em funcionamento:
Mais fotos no Álbum do Picasa.
O código encontra-se abaixo. Ainda é a versão básica, que mapeia somente os analógicos e os botões de tiro, mas é fácil adaptar para os acelerômetros, acrescentar calibração, etc....
O adaptador para o Wii nunchuck pode ser feito em casa ou então comprado.
//
// Play on MSX with Wii Nunchuck and Arduino By Danjovic, 2012
// Based nunchuck libraries by Michael Dreher and Tim Hirzel
//
/*
MSX Joystick
Activates sequentially the following directions from an MSX/Atari Joystick
UP, DOWN, LEFT, RIGHT, TRIGGER A, TRIGGER B
CONNECTIONS
Function DB-9 Arduino AVR
UP 1 Pin 2 (PD2)
DOWN 2 Pin 3 (PD3)
LEFT 3 Pin 4 (PD4)
RIGHT 4 Pin 5 (PD5)
+5VCC 5 +5V +Vcc
TRG A 6 Pin 6 (PD6)
TRG B 7 Pin 7 (PD7)
GND 9 GND GND
*/
// adapt to your hardware config
#define POWER_VIA_PORT_C2_C3 1 // use port pins port C2 and C3 as power supply of the Nunchuck (direct plug using wiichuck adapter)
#define USE_NEW_WAY_INIT 1 // use "The New Way" of initialization <http://wiibrew.org/wiki/Wiimote#The_New_Way>
#define WII_IDENT_LEN ((byte)6)
#define WII_TELEGRAM_LEN ((byte)6)
#define WII_NUNCHUCK_TWI_ADR ((byte)0x52)
#include <Wire.h>
//#include <string.h>
#include <utility\twi.h>
#undef int
#include <stdio.h>
uint8_t outbuf[WII_TELEGRAM_LEN]; // array to store arduino output
int cnt = 0;
int ledPin = 13;
int Up_Pin = 2; // LED connected to digital pin 13
int Down_Pin = 3; // LED connected to digital pin 13
int Left_Pin = 4; // LED connected to digital pin 13
int Right_Pin = 5; // LED connected to digital pin 13
int TrgA_Pin = 6; // LED connected to digital pin 13
int TrgB_Pin = 7; // LED connected to digital pin 13
void setup ()
{
// initialize Pin directions
pinMode(Up_Pin, INPUT);
pinMode(Down_Pin, INPUT);
pinMode(Left_Pin, INPUT);
pinMode(Right_Pin, INPUT);
pinMode(TrgA_Pin, INPUT);
pinMode(TrgB_Pin, INPUT);
// initialize Buffer output buffers
digitalWrite(Up_Pin, LOW);
digitalWrite(Down_Pin, LOW);
digitalWrite(Left_Pin, LOW);
digitalWrite(Right_Pin, LOW);
digitalWrite(TrgA_Pin, LOW);
digitalWrite(TrgB_Pin, LOW);
#ifdef POWER_VIA_PORT_C2_C3 // power supply of the Nunchuck via port C2 and C3
PORTC &=~ _BV(PORTC2);
PORTC |= _BV(PORTC3);
DDRC |= _BV(PORTC2) | _BV(PORTC3); // make outputs
delay(100); // wait for things to stabilize
#endif
Wire.begin(); // initialize i2c
// we need to switch the TWI speed, because the nunchuck uses Fast-TWI
// normally set in hardware\libraries\Wire\utility\twi.c twi_init()
// this is the way of doing it without modifying the original files
#define TWI_FREQ_NUNCHUCK 200000L
TWBR = ((CPU_FREQ / TWI_FREQ_NUNCHUCK) - 16) / 2;
nunchuck_init(0); // send the initialization handshake
}
// params:
// timeout: abort when timeout (in ms) expires, 0 for unlimited timeout
// return: 0 == ok, 1 == timeout
byte nunchuck_init (unsigned short timeout)
{
byte rc = 1;
#ifndef USE_NEW_WAY_INIT // look at <http://wiibrew.org/wiki/Wiimote#The_Old_Way> at "The Old Way"
Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR); // transmit to device 0x52
Wire.send (0x40); // sends memory address
Wire.send (0x00); // sends sent a zero.
Wire.endTransmission (); // stop transmitting
#else
// disable encryption
// look at <http://wiibrew.org/wiki/Wiimote#The_New_Way> at "The New Way"
unsigned long time = millis();
do {
Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR); // transmit to device 0x52
Wire.send (0xF0); // sends memory address
Wire.send (0x55); // sends data.
if(Wire.endTransmission() == 0) // stop transmitting
{
Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR); // transmit to device 0x52
Wire.send (0xFB); // sends memory address
Wire.send (0x00); // sends sent a zero.
if(Wire.endTransmission () == 0) // stop transmitting
{
rc = 0;
}
}
}
while (rc != 0 && (!timeout || ((millis() - time) < timeout)));
#endif
return rc;
}
// params:
// ident [out]: pointer to buffer where 6 bytes of identification is stored. Buffer must be at least 6 bytes long.
// A list of possible identifications can be found here: <http://wiibrew.org/wiki/Wiimote#The_New_Way>
// return: 0 == ok, 1 == error
byte readControllerIdent(byte* pIdent)
{
byte rc = 1;
// read identification
Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR); // transmit to device 0x52
Wire.send (0xFA); // sends memory address of ident in controller
if(Wire.endTransmission () == 0) // stop transmitting
{
byte i;
Wire.requestFrom (WII_NUNCHUCK_TWI_ADR, WII_TELEGRAM_LEN); // request data from nunchuck
for (i = 0; (i < WII_TELEGRAM_LEN) && Wire.available (); i++)
{
pIdent[i] = Wire.receive(); // receive byte as an integer
}
if(i == WII_TELEGRAM_LEN)
{
rc = 0;
}
}
return rc;
}
void clearTwiInputBuffer(void)
{
// clear the receive buffer from any partial data
while( Wire.available ())
Wire.receive ();
}
void send_zero ()
{
// I don't know why, but it only works correct when doing this exactly 3 times
// otherwise only each 3rd call reads data from the controller (cnt will be 0 the other times)
for(byte i = 0; i < 3; i++)
{
Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR); // transmit to device 0x52
Wire.send (0x00); // sends one byte
Wire.endTransmission (); // stop transmitting
}
}
void loop ()
{
Wire.requestFrom (WII_NUNCHUCK_TWI_ADR, WII_TELEGRAM_LEN); // request data from nunchuck
for (cnt = 0; (cnt < WII_TELEGRAM_LEN) && Wire.available (); cnt++)
{
outbuf[cnt] = nunchuk_decode_byte (Wire.receive ()); // receive byte as an integer
digitalWrite (ledPin, HIGH); // sets the LED on
}
clearTwiInputBuffer();
// If we recieved the 6 bytes, then go print them
if (cnt >= WII_TELEGRAM_LEN)
{
do_output ();
}
// send the request for next bytes
send_zero ();
delay (10);
}
// Drive the Joystick pins
// accel data is 10 bits long but only 8 MSBs are being considered
// Z axis is not mapped to anything
void do_output ()
{
int joy_x_axis = outbuf[0];
int joy_y_axis = outbuf[1];
int accel_x_axis = outbuf[2];
int accel_y_axis = outbuf[3];
int accel_z_axis = outbuf[4];
int C_Z_buttons = outbuf[5]; // byte outbuf[5] contains bits for z and c buttons
// Up Direction
if (joy_y_axis > 192)
{
pinMode(Up_Pin, OUTPUT); // Unassert pin
}
else
{
pinMode(Up_Pin, INPUT); // Assert pin
}
// Down Direction
if (joy_y_axis < 64)
{
pinMode(Down_Pin, OUTPUT); // Unassert pin
}
else
{
pinMode(Down_Pin, INPUT); // Assert pin
}
// Right Direction
if (joy_x_axis > 192)
{
pinMode(Right_Pin, OUTPUT); // Unassert pin
}
else
{
pinMode(Right_Pin, INPUT); // Assert pin
}
// Left Direction
if (joy_x_axis < 64)
{
pinMode(Left_Pin, OUTPUT); // Unassert pin
}
else
{
pinMode(Left_Pin, INPUT); // Assert pin
}
// Trigger B
if (C_Z_buttons & 1)
{
pinMode(TrgB_Pin, INPUT); // Unassert pin
}
else
{
pinMode(TrgB_Pin, OUTPUT); // Assert pin
}
// Trigger A
if (C_Z_buttons & 2)
{
pinMode(TrgA_Pin, INPUT); // Unassert pin
}
else
{
pinMode(TrgA_Pin, OUTPUT); // Assert pin
}
}
// Decode data format that original Nunchuck uses with old init sequence. This never worked with
// other controllers (e.g. wireless Nunchuck from other vendors)
char nunchuk_decode_byte (char x)
{
#ifndef USE_NEW_WAY_INIT
x = (x ^ 0x17) + 0x17;
#endif
return x;
}
2 comentários:
Cara bacana vou testar no meu hotbit
Cara ta dando erro pra mim numa linha do pgm, "TWBR = ((CPU_FREQ / TWI_FREQ_NUNCHUCK) - 16) / 2;"
'CPU_FREQ'was not declared in this scope.
???
Postar um comentário