Introduction: Wireless NES Controller With Data Display

BRINGING YOUR NES CONTROLLER, BACK TO THE FUTURE!

This project integrates an xbee, arduino, data display and generic nes controller to create a remote control for any arduino + xbee project.  The display allows you to get feedback from what you are controlling/communicating with.  The prototype pictured, is currently used to control a small rover-bot.  Commands are executed by the rover, and sensor data is displayed on the screen. 

*select and start buttons are not pictured, but the schematic accounts for the option.  the stl's can be edited to include them as well :)

Bill of materials:

-Generic NES controller, available from http://jameco.com (think twice before altering a real one!)
-Arduino Pro 5v (this is an arbitrary choice, but it 's diminutive size is nice)
-Newhaven NHD-0220D3Z-NSW-BBW-V3, available from http://mouser.com (though many displays follow the same protocol)
-USB-FTDI interface
-Max Stream Xbee (you'll want 2 to talk to anything else!)
-Sparkfun xbee explorer
-LM7805 voltage regulator.
-10k resistor x 8 (or equivalent sip)
-course screws (#4x1/2" & 6-32x3/8"
-wirewrap wire, or 20+ guage
-standard male headers (for the arduino pro 5v and xbee explorer)
-schmart female jumpers (for easy header to header connections) http://www.schmartboard.com/
-9v battery clip
-breadboard, big and small help!
-9v battery (you'll want a stock of these!)

Machines:

-3D printer (makerbot replicator 2 here)

Tools:
-soldering iron
-precision screwdriver set
-wireclippers
-DMM (always nice for testing!)
-xacto knife


Step 1: BREADBOARD IT!

1)  Solder the headers to the arduino pro 5v, and xbee explorer.
1)  Following the schematic, assemble the circuit. 

The pictured breadboard differs slightly than the schematic, in that the "select" and "start" buttons aren't used.  There are also some small buttons to test the circuit, without cracking open the NES controller.  You may want to do step 5 now, and program, the arduino.

Step 2: DISSASSEMBLE THE CONTROLLER

***FYI, below is a non-finessed way of repurposing the controller.  You could probably reverse engineer the plug connections...

1)  Remove the case screws
2)  Pop-the board out (setting the buttons aside), and desolder the resistor and wire
3) Identify the trace which feeds power to all of the contacts/buttons using a DMM, this is our 5V rail.
4) Identify the traces that come from each button to indicate a press/closure.  These should all terminate in the black-blob ic.  Using an xacto knife, cut these traces before they hit the blob.
5)  Solder a 20+ gauge wire to the 5v rail.  Wirewrap wire works great.
6)  Remember the traces you cut and identified?  Solder a 20+ gauge wire to each of them.  In many cases you'll be able to use the circular solder pads.  This will go easer if you name, or colorcode them!
7)  Use you DMM to test for closures i.e. continuity test from the 5v rail, to say, button 1.

FYI all buttons are all NO (normally open).

Step 3: PRINT OUT THE CONTROL

Well, you can make you own, or use these!  The 3 .stl files form a bottom, a top, and an impromptu battery clip.  The cm or inches setting may need to be altered, depending on what software you are using.  The design is mostly taken from the original casing, and could certainly use some extra work.  These models don't have the select or start buttons.  And for example the lip is only on two sides of the bottom piece, mostly to save printing time :)

Inventor was used for the modeling.

1)  Load the .stl's into your slicer of choice (replicatorg, makerware)
2)  Load the sliced files into yr printer, and print!

Step 4: PUT IT ALL TOGETHER!

1)  Use the course  #4x 1/2"screws and 1/4" standoffs to attach the display to the top.
2)  Insert the saved buttons into the case, followed by the nes pcb.  The holes should register and align the board.
3)  Affix the rest of the electronics.  How you do this will either enhance, or kill the durability!  The prototype below is not built to last.
4) Insert the battery clip and "battery box"
5)  Route all wires so that the top and bottom close with slight pressure.  You want pressure on the pcb, but not on the wires.
6)  Use course 6-32x 3/8" screws to fasten the top to the bottom.

***i've cheated here and used some tape as well...

Step 5: CODE and Go!!

 And here's some code to get you going!  Be careful, its not cleaned up :)

1)  Make sure you have SoftwareSerial.h.  This allows us to run two serial instances at once!
2)  Upload the code your arduino
3)  Start pressing buttons for feedback
4)  You may want to change the xbee ID.  These values are written everytime the arduino is powered up.
5)  GO FIND SOMETHING TO CONTROL!

arduino pro 5v code with newhaven control protocol:


#include

SoftwareSerial xbeeSerial(12, 13); // RX, TX
//variables
int i = 0;
int j = 0;
int m = 0;
int dChange = 0;
int sChange =0;
int stChange=0;
int ret = 0;
int execute = 0;
int inByte = 0;

int up = 3;
int down = 4;
int left = 5;
int right = 6;
int select = 7;
int start = 8;

int commands[100];//for util
int input[6]= {up,down,left,right,select,start};
int buttonState[6];
char* directions[]={"FORWARD", "REVERSE", "LEFT", "RIGHT", "SELECT", "START"};
char* dlist[]={"F ", "R ", "< ", "> ", "sel", "sta"};
byte xbeeSend[4]={0x31,0x32,0x33,0x34};

char roverData[ ] = "";


//newhaven NHD-0220D3Z-NSW-BBW-V3 commands
byte program = 0xFE;
byte displayOn = 0x41;
byte displayOff = 0x42;
byte cursorPos = 0x45; //1 Byte Set
byte cursorHome = 0x46;
byte underlineOn = 0x47;
byte underlineOff= 0x48;
byte cursorLeft = 0x49;
byte cursorRight = 0x4A;
byte blinkingOn = 0x4B;
byte blinkingOff = 0x4C;
byte backspace = 0xFE;
byte clearScreen = 0x51;
byte setContrast = 0x52;//1 byte set
byte setBrightness = 0x53; //1 byte set
byte custom = 0x54;
byte displayLeft = 0x55;
byte displayRight = 0x56;
byte firmware = 0x70;
/*
0xFE 0x61 1 Byte Change RS‐232 BAUDrate 3mS
0xFE 0x62 1 Byte Change I2C address 3mS
0xFE 0x70 None Display firmware version number 4mS
0xFE 0x71 None Display RS‐232 BAUDrate 10mS
0xFE 0x72 None Display I2C address 4mS
*/


void setup() 
{
  // Open serial com and define inputs
  Serial.begin(9600);
  xbeeSerial.begin(9600);

    for(i=3;i<9;i++){
    pinMode(i, INPUT);
    }

    lcdCommand(program,clearScreen);
    delay(500);
  //

  // put the radio in command mode:
  xbeeSerial.print("+++");
  // wait for the radio to respond with "OK\r"
  //char thisByte = 0;
  //while (thisByte != '\r') {
   // if (xbeeSerial.available() > 0) {
    //  thisByte = xbeeSerial.read();
//   }
// }
  // set the destination address with 16-bit addressing. This radio's
  // destination should be the other radio's MY address and vice versa:
  xbeeSerial.print("ATDH0, DL1234\r");
  xbeeSerial.print("ATMY5678\r");   // set my address (16-bit addressing)
  // set the PAN ID. If you're in a place where many people
  // are using XBees, choose a unique PAN ID
  xbeeSerial.print("ATID1111\r");
  xbeeSerial.print("ATCN\r");
  xbeeListen();






}

void xbeeListen() {
    char thisByte = 0;
    if (Serial.available() > 0) {
      thisByte = Serial.read();
    }
}

void loop() //LOOPY!
{









  lcdCommand(program,cursorHome);
  lcdCommand(program,blinkingOn);
  lcdCommand(program,setContrast);
  Serial.write(0x28);

readDpadInput();
readSelInput();

lcdCommand(program,cursorRight);

Serial.print("Command:");
Serial.print(j);
Serial.print("?");
lcdCommand(program,cursorPos);
Serial.write(0x40);



while(dChange ==1){

directionFeedback();
delay(500);
commands[j]=ret;
j++;


lcdCommand(program,clearScreen);
dChange = 0;
}
delay(500);

}


///serial





///command protocol:
int lcdCommand(byte address, int value){
    Serial.write(address);//CORRECT syntax for lcd commands
    Serial.write(value);
}

///read input
int readDpadInput(){ 
for (i=0;i<4;i++){
  buttonState[i]=digitalRead(input[i]);
  dChange=buttonState[i]+dChange;
}
}
int readSelInput(){ 

  buttonState[4]=digitalRead(input[4]);
  sChange=buttonState[4]+sChange;
}

int readStartInput(){ 

  buttonState[5]=digitalRead(input[5]);
  stChange=buttonState[5]+stChange;
}




///display directions
int directionFeedback(){
for (i=0;i<4;i++){
switch(buttonState[i]){
   case 0: lcdCommand(program,cursorHome);
   break;
   case 1:
      lcdCommand(program,blinkingOff);
      lcdCommand(program,cursorPos);
      Serial.write(0xC);
      Serial.print(directions[i]);     
      xbeeSerial.print(i+1);
       handleSerial();
       delay(1000);

     // xbeeSerial.write("\r");


      ret = i;
   break;
  }
}
}


int handleSerial() {
  //xbeeSerial.print(56);
   if(xbeeSerial.available() > 0) {
    inByte = xbeeSerial.read();
     Serial.print(inByte);
     } 
}

Battery Powered Contest

Participated in the
Battery Powered Contest

3D Printing Contest

Participated in the
3D Printing Contest

Epilog Challenge V

Participated in the
Epilog Challenge V