SparkFun Forums 

Where electronics enthusiasts find answers.

General project discussion area - What have you built with your Micro View

Moderators: marcus@geekammo, Help@GeekAmmo

By kgrr
A Wii Nunchuk has two buttons (C and Z), a two axis proportional joystick and a three-axis accelerometer all built into a hand-sized package. It has an I2C interface that can be used to read all of this sensor data. Sparkfun makes a little adapter board to bring the four wires out to breadboard pins

Here's a couple of ideas ...
- Can we use the nunchuk to drive a game of Asteroids?
- Can we use the nunchuk and two servos to aim a laser pointer remotely?
By kgrr
I hooked up the WiiChuck adapter like this:

MicroView Pin -- Color Wire -- WiiChuck pin

Pin 2 SCL -- Yellow -- [C]
Pin 3 SDA -- Green -- [D]
Pin 8 GND -- Black -- [-]
Pin 15 +5V -- Red -- [+]

The WiiChuck Adapter's pins are in this order from left to right:
[Black -][Red +][Green D][Yellow C]

Then, after hooking it up, I used the I2C scanner tool to determine if my wiring was correct and that my nunchuck was running.

The nunchuck's I2C bus responds to address 0x52.

Here's what the setup looks like. Sorry the picture is a little out of focus.

By kgrr
This sketch reads the nunchuck and displays the state of 3-axis accelerometer, the joystick and the two buttons C and Z.

Code: Select all
#include <MicroView.h>
#include <Wire.h>
#include "nunchuck.h"

WiiChuck chuck = WiiChuck();
int angleStart, currentAngle;
int tillerStart = 0;
double angle;

void setup() 
  uView.setFontType(0); // set font to the smallest font
  uView.begin();	    // init and start MicroView
  uView.clear(PAGE);	// erase the memory buffer

void loop() 

  uView.clear(PAGE);	// erase the memory buffer

  uView.print(" X:");
  uView.print(" Y:");  
Code: Select all
 * Nunchuck -- Use a Wii Nunchuck
 * Tim Hirzel
 notes on Wii Nunchuck Behavior.
 This library provides an improved derivation of rotation angles from the nunchuck accelerometer data.
 The biggest different over existing libraries (that I know of ) is the full 360 degrees of Roll data
 from teh combination of the x and z axis accelerometer data using the math library atan2.

 It is accurate with 360 degrees of roll (rotation around axis coming out of the c button, the front of the wii),
 and about 180 degrees of pitch (rotation about the axis coming out of the side of the wii).  (read more below)

 In terms of mapping the wii position to angles, its important to note that while the Nunchuck
 sense Pitch, and Roll, it does not sense Yaw, or the compass direction.  This creates an important
 disparity where the nunchuck only works within one hemisphere.  At a result, when the pitch values are
 less than about 10, and greater than about 170, the Roll data gets very unstable.  essentially, the roll
 data flips over 180 degrees very quickly.   To understand this property better, rotate the wii around the
 axis of the joystick.  You see the sensor data stays constant (with noise).  Because of this, it cant know
 the difference between arriving upside via 180 degree Roll, or 180 degree pitch.  It just assumes its always
 180 roll.

 * This file is an adaptation of the code by these authors:
 * Tod E. Kurt,
 * The Wii Nunchuck reading code is taken from Windmeadow Labs
 * Conversion to Arduino 1.0 by Danjovic
 * Included the Fix from Martin Peris by Leopold Klimesch

#ifndef WiiChuck_h
#define WiiChuck_h

#include "Arduino.h"
#include <Wire.h>
#include <math.h>

// these may need to be adjusted for each nunchuck for calibration
#define ZEROX 510  
#define ZEROY 490
#define ZEROZ 460
#define RADIUS 210  // probably pretty universal

#define DEFAULT_ZERO_JOY_X 124
#define DEFAULT_ZERO_JOY_Y 132

//Set the power pins for the wiichuck, otherwise it will not be powered up
#define pwrpin PORTC3
#define gndpin PORTC2

class WiiChuck {
        uint8_t cnt;
        uint8_t status[6];              // array to store wiichuck output
        uint8_t averageCounter;
        //int accelArray[3][AVERAGE_N];  // X,Y,Z
        int i;
        int total;
        uint8_t zeroJoyX;   // these are about where mine are
        uint8_t zeroJoyY; // use calibrateJoy when the stick is at zero to correct
        int lastJoyX;
        int lastJoyY;
        int angles[3];

        bool lastZ, lastC;


        uint8_t joyX;
        uint8_t joyY;
        bool buttonZ;
        bool buttonC;
        void begin()
			//Set power pinds
            DDRC |= _BV(pwrpin) | _BV(gndpin);

            PORTC &=~ _BV(gndpin);

            PORTC |=  _BV(pwrpin);

            delay(100);  // wait for things to stabilize   

            //send initialization handshake
            cnt = 0;
            averageCounter = 0;
            // instead of the common 0x40 -> 0x00 initialization, we
            // use 0xF0 -> 0x55 followed by 0xFB -> 0x00.
            // this lets us use 3rd party nunchucks (like cheap $4 ebay ones)
            // while still letting us use official oness.
            // only side effect is that we no longer need to decode bytes in _nunchuk_decode_byte
            // see
            Wire.beginTransmission(0x52);       // device address

            for (i = 0; i<3;i++) {
                angles[i] = 0;
            zeroJoyX = DEFAULT_ZERO_JOY_X;
            zeroJoyY = DEFAULT_ZERO_JOY_Y;

        void calibrateJoy() {
            zeroJoyX = joyX;
            zeroJoyY = joyY;

        void update() {

            Wire.requestFrom (0x52, 6); // request data from nunchuck
            while (Wire.available ()) {
                // receive byte as an integer
                status[cnt] = _nunchuk_decode_byte (; //
            if (cnt > 5) {
                lastZ = buttonZ;
                lastC = buttonC;
                lastJoyX = readJoyX();
                lastJoyY = readJoyY();
                //averageCounter ++;
                //if (averageCounter >= AVERAGE_N)
                //    averageCounter = 0;

                cnt = 0;
                joyX = (status[0]);
                joyY = (status[1]);
                for (i = 0; i < 3; i++)
                    //accelArray[i][averageCounter] = ((int)status[i+2] << 2) + ((status[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2)));
                    angles[i] = (status[i+2] << 2) + ((status[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2)));

                //accelYArray[averageCounter] = ((int)status[3] << 2) + ((status[5] & B00110000) >> 4);
                //accelZArray[averageCounter] = ((int)status[4] << 2) + ((status[5] & B11000000) >> 6);

                buttonZ = !( status[5] & B00000001);
                buttonC = !((status[5] & B00000010) >> 1);
                _send_zero(); // send the request for next bytes


    //byte * getStatus() {
    //    return status;

    float readAccelX() {
       // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;
        return (float)angles[0] - ZEROX;
    float readAccelY() {
        // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;
        return (float)angles[1] - ZEROY;
    float readAccelZ() {
        // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;
        return (float)angles[2] - ZEROZ;

    bool zPressed() {
        return (buttonZ && ! lastZ);
    bool cPressed() {
        return (buttonC && ! lastC);

    // for using the joystick like a directional button
    bool rightJoy(int thresh=60) {
        return (readJoyX() > thresh and lastJoyX <= thresh);

    // for using the joystick like a directional button
    bool leftJoy(int thresh=60) {
        return (readJoyX() < -thresh and lastJoyX >= -thresh);

    int readJoyX() {
        return (int) joyX - zeroJoyX;

    int readJoyY() {
        return (int)joyY - zeroJoyY;

    // R, the radius, generally hovers around 210 (at least it does with mine)
   // int R() {
   //     return sqrt(readAccelX() * readAccelX() +readAccelY() * readAccelY() + readAccelZ() * readAccelZ());  
   // }

    // returns roll degrees
    int readRoll() {
        return (int)(atan2(readAccelX(),readAccelZ())/ M_PI * 180.0);

    // returns pitch in degrees
    int readPitch() {        
        return (int) (acos(readAccelY()/RADIUS)/ M_PI * 180.0);  // optionally swap 'RADIUS' for 'R()'

        uint8_t _nunchuk_decode_byte (uint8_t x)
            //decode is only necessary with certain initializations
            //x = (x ^ 0x17) + 0x17;
            return x;

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


Last edited by kgrr on Sun Aug 24, 2014 1:02 pm, edited 2 times in total.
By kgrr
Thanks for the tweet.

Next, I want to implement the 15 sliding piece puzzle.


Wikipedia article about the 15-puzzle:

The puzzle will start in a random state with the pieces mixed-up.
The joystick selects which tile will move into the blank space.
The selected tile's number will be bolded. Only tiles that can move to the blank space can be "bolded".
The Z button causes the selected tile to move.
The C button resets the game.
The puzzle is solved when the tiles are in numerical order.

"Extra credit":
1) Is there room in the display to track the number of moves? Maybe you can display the number of moves at the end when the puzzle is solved.
2) Can you animate the sliding of the tile instead of "popping" it over to the blank space?
3) Can you make the puzzle suggest the best move for you with artificial intelligence?

Can you write the program? I will give my solution by the end of the week.
Last edited by kgrr on Mon Sep 01, 2014 2:50 am, edited 1 time in total.
long long title how many chars? lets see 123 ok more? yes 60

We have created lots of YouTube videos just so you can achieve [...]

Another post test yes yes yes or no, maybe ni? :-/

The best flat phpBB theme around. Period. Fine craftmanship and [...]

Do you need a super MOD? Well here it is. chew on this

All you need is right here. Content tag, SEO, listing, Pizza and spaghetti [...]

Lasagna on me this time ok? I got plenty of cash

this should be fantastic. but what about links,images, bbcodes etc etc? [...]