Wii Classic Controller

Hello, I have a wii classic controller talking to my arduino, I was able to make it so using this code http://www.arduino.cc/playground/Main/WiiClassicController Im not a good programmer at all, so I need a bit of help.

I'm able to press any button on the controller, and have it set an output pin to HIGH, the only problem is it will stay HIGH, unless I have it turn LOW after a delay, I want it to keep the pin HIGH for as long as the button is pressed, and I have been unsuccessful, I tried using the "if" "else" statements, but it doesn't seem to work, I feel I'm a bit over my head, but if I can't get pass this hurdle I will have completed my project!

Does anyone have any clue how to fix this? I looked at "WiiClassic.h" and I don't really understand how its communicating with the Controller, I also can't tell if its listening to how long a button has been pressed, or just weather its been pressed at all.

thanks for any help, most appreciated.

-joe

A typical approach would look like this:

update controller and get states
update output with the recieved states (or at least update the changed states)

or this:

while the controller is in a hit state wait until (state) change

It would’ve been easier to help if you posted your current code. :slight_smile:

Here is my version of the Classic Controller Code, I didn’t really change too much, instead of having it print the button pressed to the serial, I had it turn a pin to HIGH.
If I don’t add the “digitalWrite(dpadLeft, LOW)” then the pin will stay on HIGH and never go off.

thanks for the help
-joe

/*
WiiClassic Test Code

This code prints the current controller status to the serial port.
Button pressed calls poll whether the button was pressed since the last update call.
as a result, it will just briefly print the last button pressed once.

Tim Hirzel May 2008

*/


#include "Wire.h"

#include "WiiClassic.h"

WiiClassic wiiClassy = WiiClassic();

int AButton = 11;
int BButton = 10;
int XButton = 13;
int YButton = 12;
int dpadDown = 8;
int dpadUp = 6;
int dpadRight = 9;
int dpadLeft = 7;


void setup() {
Wire.begin();
Serial.begin(9600);
wiiClassy.begin();
wiiClassy.update();


  pinMode(AButton, OUTPUT);      
  pinMode(BButton, OUTPUT);
  pinMode(XButton, OUTPUT);
  pinMode(YButton, OUTPUT);
  pinMode(dpadDown, OUTPUT);
  pinMode(dpadUp, OUTPUT);
  pinMode(dpadLeft, OUTPUT);
  pinMode(dpadRight, OUTPUT);
  


}

void loop() {
delay(1); // 1ms is enough to not overload the wii Classic, 100ms seems to ease the serial terminal a little
wiiClassy.update();

// 
/*
// PRINT RAW BYTES FOR DEBUG
// STATUS IS FIRST FOUR BYTES
for (int i = 0; i < 4; i ++) {
for (int j = 7; j >= 0; j--) {
if ((wiiClassy.getRawStatus()[i] & (1 << j)) == 0) {
Serial.print("0");
}
else{
Serial.print("1");
}
}
Serial.println();
}
// BUTTONS IS NEXT TWO BYTES
for (int i = 0; i < 2; i ++) {
for (int j = 7; j >= 0; j--) {
if ((wiiClassy.getRawButtons()[i] & (1 << j)) == 0) {
Serial.print("0");
}
else{
Serial.print("1");
}
}
Serial.println();
}
Serial.println("---");
*/

///Serial.print("Buttons:");


if (wiiClassy.leftShoulderPressed()) {
 
  //Serial.print("LS.");
}
if (wiiClassy.rightShoulderPressed()) {
  
  //Serial.print("RS.");
}
if (wiiClassy.lzPressed()) {

  
  //Serial.print("lz.");
}
if (wiiClassy.rzPressed()) {

  //Serial.print("rz.");
}

if (wiiClassy.leftDPressed()) {
   digitalWrite(dpadLeft, HIGH);
   delay(100);
   digitalWrite(dpadLeft, LOW);
   delay(100);
  
  //Serial.print("LD.");
}

if (wiiClassy.rightDPressed()) {
   digitalWrite(dpadRight, HIGH);
delay(100);


     digitalWrite(dpadRight, LOW);
   delay(100);
  
  //Serial.print("RD." );
}

if (wiiClassy.upDPressed()) {
   digitalWrite(dpadUp, HIGH);
   delay(100);
   digitalWrite(dpadUp, LOW);
   delay(100);
  
//Serial.print("UD.");
}
if(wiiClassy.downDPressed()) {
   digitalWrite(dpadDown, HIGH);
   delay(100);
 
  digitalWrite(dpadDown, LOW);
  delay(100);
    //Serial.print("DD.");
}

if (wiiClassy.selectPressed()) {
Serial.print("select.");
}

if (wiiClassy.homePressed()) {
Serial.print("home.");
}
if (wiiClassy.startPressed()) {
Serial.print("start.");
}

if (wiiClassy.xPressed()) {
   digitalWrite(YButton, HIGH);
   delay(100);
   digitalWrite(YButton, LOW);
   delay(100);

  
  //Serial.print("x.");
}

if (wiiClassy.yPressed()) {
   digitalWrite(XButton, HIGH);
   delay(100);
   digitalWrite(XButton, LOW);
   delay(100);
  
  //Serial.print("y.");
}

if (wiiClassy.aPressed()) {
   digitalWrite(BButton, HIGH);
   delay(100);
   digitalWrite(BButton, LOW);
   delay(100);
    
//Serial.print("a.");
}

if (wiiClassy.bPressed()) {
   digitalWrite(AButton, HIGH);
   delay(100);
   digitalWrite(AButton, LOW);
   delay(100);
  //Serial.print("b.");
}



  
  
/*Serial.println();
Serial.print("right shoulder: ");
Serial.println(wiiClassy.rightShouldPressure());
Serial.print(" left shoulder: ");

Serial.println(wiiClassy.leftShouldPressure());
Serial.print(" left stick x: ");

Serial.println(wiiClassy.leftStickX());
Serial.print(" left stick y: ");

Serial.println(wiiClassy.leftStickY());
Serial.print(" right stick x: ");

Serial.println(wiiClassy.rightStickX());
Serial.print(" right stick y: ");

Serial.println(wiiClassy.rightStickY());
Serial.println("---");
*/
//pulse = (int)500+8*wiiClassy.leftStickX();
//updateServo();
}

Try this quick 'n' dirty hack:

/* WiiClassic Test Code

This code prints the current controller status to the serial port. Button pressed calls poll whether the button was pressed since the last update call. as a result, it will just briefly print the last button pressed once.

Tim Hirzel May 2008 */

include "Wire.h"

include "WiiClassic.h"

int AButton = 11; int BButton = 10; int XButton = 13; int YButton = 12; int dpadDown = 8; int dpadUp = 6; int dpadRight = 9; int dpadLeft = 7;

void setup() { Wire.begin(); Serial.begin(9600); wiiClassy.begin(); wiiClassy.update();

pinMode(AButton, OUTPUT); pinMode(BButton, OUTPUT); pinMode(XButton, OUTPUT); pinMode(YButton, OUTPUT); pinMode(dpadDown, OUTPUT); pinMode(dpadUp, OUTPUT); pinMode(dpadLeft, OUTPUT); pinMode(dpadRight, OUTPUT);

}

void loop() { delay(1); // 1ms is enough to not overload the wii Classic, 100ms seems to ease the serial terminal a little wiiClassy.update();

//maybe make this into a function? while(wiiClassy.yPressed()) { digitalWrite(YButton, HIGH); wiiClassy.update(); } digitalWrite(YButton, LOW); }

Hmm, that didn’t work, it did the same thing as before. The pin is only on high for as long as I set the delay.
Holding down the button wasn’t acknowledged.

here is the code for WiiClassic.h

    * WiiClassic.h library 

/*
 * Wii Classic -- Use a Wii Classic Controller
 * by Tim Hirzel http://www.growdown.com
 *
 *
 * This code owes thanks to the code by these authors:
 * Tod E. Kurt, http://todbot.com/blog/
 *
 * The Wii Nunchuck reading code is taken from Windmeadow Labs
 * http://www.windmeadow.com/node/42
 *
 * and the reference document on the wii linux site:
 * http://www.wiili.org/index.php/Wiimote/Extension_Controllers/Classic_Controller
 */

#include <Wire.h>


#ifndef WiiClassic_h
#define WiiClassic_h


class WiiClassic {    
    private:
        byte cnt;
        uint8_t status[4];              // array to store wiichuck output
        byte averageCounter;
        //int accelArray[3][AVERAGE_N];  // X,Y,Z

        uint8_t buttons[2];
        uint8_t lastButtons[2];


    public:

        void begin()
        {
            Wire.begin();
            cnt = 0;
            averageCounter = 0;
            Wire.beginTransmission (0x52);      // transmit to device 0x52
            Wire.send (0x40);           // sends memory address
            Wire.send (0x00);           // sends memory address
            Wire.endTransmission ();    // stop transmitting
            lastButtons[0] = 0xff;
            lastButtons[1] = 0xff;
            buttons[0] = 0xff;
            buttons[1] = 0xff;

            update();        

        }


        void update() {

            Wire.requestFrom (0x52, 6); // request data from nunchuck
            while (Wire.available ()) {
                // receive byte as an integer
                if (cnt < 4) {
                    status[cnt] = _nunchuk_decode_byte (Wire.receive()); //_nunchuk_decode_byte ()
                } else {
                    lastButtons[cnt-4] = buttons[cnt-4];
                    buttons[cnt-4] =_nunchuk_decode_byte (Wire.receive());
                }
                cnt++;
            }
            if (cnt > 5) {
                _send_zero(); // send the request for next bytes
                cnt = 0;                  
            }
        }

        byte * getRawStatus() {
            return status;
        }

        byte * getRawButtons() {
            return buttons;
        }

        boolean leftShoulderPressed() {
            return _PressedRowBit(0,5);
        }

        boolean rightShoulderPressed() {
            return _PressedRowBit(0,1);
        }

        boolean lzPressed() {
            return _PressedRowBit(1,7);
        }

        boolean rzPressed() {
            return _PressedRowBit(1,2);
        }

        boolean leftDPressed() {
            return _PressedRowBit(1,1);
        }

        boolean rightDPressed() {
            return _PressedRowBit(0,7);
        }

        boolean upDPressed() {
            return _PressedRowBit(1,0);
        }

        boolean downDPressed() {
            return _PressedRowBit(0,6);
        }

        boolean selectPressed() {
            return _PressedRowBit(0,4);
        }

        boolean homePressed() {
            return _PressedRowBit(0,3);
        }

        boolean startPressed() {
            return _PressedRowBit(0,2);
        }

        boolean xPressed() {
            return _PressedRowBit(1,3);
        }

        boolean yPressed() {
            return _PressedRowBit(1,5);
        }

        boolean aPressed() {
            return _PressedRowBit(1,4);
        }

        boolean bPressed() {
            return _PressedRowBit(1,6);
        }

        int rightShouldPressure() {
            return status[3] & 0x1f; //rightmost 5 bits
        }

        int leftShouldPressure() {
            return ((status[2] & 0x60) >> 2) + ((status[3] & 0xe0) >> 5); //rightmost 5 bits
        }

        int leftStickX() {
            return  ( (status[0] & 0x3f) );
        }

        int leftStickY() {
            return  ((status[1] & 0x3f));      
        }

        int rightStickX() {
            return ((status[0] & 0xc0) >> 3) + ((status[1] & 0xc0) >> 5) +  ((status[2] & 0x80) >> 7);

        }

        int rightStickY() {
            return status[2] & 0x1f;   
        }


    private:
        boolean _PressedRowBit(byte row, byte bit) {
            byte mask = (1 << bit);
            return (!(buttons[row] & mask )) && (lastButtons[row] & mask);
        }


        byte _nunchuk_decode_byte (byte x)
        {
            x = (x ^ 0x17) + 0x17;
            return x;
        }

        void _send_zero()
        {
            Wire.beginTransmission (0x52);      // transmit to device 0x52
            Wire.send (0x00);           // sends one byte
            Wire.endTransmission ();    // stop transmitting
        }

};



#endif

Could the solution be in this code?
Is there anything else I could try?

I appreciate the help

thanks
-joe

This seems like quite a challenge.

It looks as if the wii/wiiclassic.h only logs hit event, not release.

This is why my code won’t work.

But, what happens if you change

boolean _PressedRowBit(byte row, byte bit) {
  byte mask = (1 << bit);
  return (!(buttons[row] & mask )) && (lastButtons[row] & mask);
}

to

boolean _PressedRowBit(byte row, byte bit) {
  byte mask = (1 << bit);
  return (!(buttons[row] & mask ));
}

Does this respond as expected to Y ?

#include "Wire.h"
#include "WiiClassic.h"

WiiClassic wiiClassy = WiiClassic();

byte YButton = 12;

void setup() {
 Serial.begin(9600);
 wiiClassy.begin();
 
 pinMode(YButton, OUTPUT);
}

void loop() {
 delay(1); // 1ms is enough to not overload the wii Classic, 100ms seems to ease the serial terminal a little
 wiiClassy.update();

 //maybe make this into a function?
 while (wiiClassy.yPressed()) {
   digitalWrite(YButton, HIGH);
   wiiClassy.update();
 }
 digitalWrite(YButton, LOW);
}

YES! that did the trick, thank you very much.

There is one issue now that I'm noticing, I it won't read in two buttons at the same time. It lets me hold them as long as I want, but I can't combine.

I'm going to toy with it, but if you know a solution, feel free :)

-joe

Just an idea:

[UNTESTED CODE]

include "Wire.h"

include "WiiClassic.h"

WiiClassic wiiClassy = WiiClassic();

//stores pin number and state in a byte struct wiiPin { byte pin:7; byte state:1; };

//declare buttons wiiPin XButton = { 12 , 0 }; wiiPin YButton = { 13 , 0 };

void setup() { Serial.begin(9600); wiiClassy.begin();

//pinModes pinMode(YButton.pin, OUTPUT); pinMode(XButton.pin, OUTPUT); }

void loop() { //UPDATE wiiClassy.update(); //update the wii classic

//SET STATES wiiClassy.yPressed() ? YButton.state = 1 : YButton.state = 0; wiiClassy.xPressed() ? XButton.state = 1 : XButton.state = 0;

//EXECUTE STATES digitalWrite(YButton.pin,YButton.state); digitalWrite(XButton.pin,XButton.state);

delay(1); // 1ms is enough to not overload the wii Classic, 100ms seems to ease the serial terminal a little }

That did it, I can now press and hold down the buttons, and press multiple buttons.

thanks for all the help

much appreciated

-joe