雷精灵 发表于 2015-5-28 16:55:11

arduino + v-usb + Wii Classic Controller = USB手柄

不得不说v-usb真强大,只需要两个稳压管+三个电阻就可以把arduino变成USB hid设备。
有了USB的协议,剩下的就是arduino和其他设备的通信了。





改天再用万能线路板把元件焊上。

雷精灵 发表于 2015-5-28 17:02:50

本帖最后由 雷精灵 于 2015-5-28 17:38 编辑

核心代码如下:
#include <Wire.h>
#include "WiiClassicController.h"
extern "C"{
#include <usbconfig.h>
#include <usbdrv.h>
};


PROGMEM const char usbHidReportDescriptor = {
        0x05, 0x01,                  // USAGE_PAGE (Generic Desktop)
        0x09, 0x05,                  // USAGE (Game Pad)
        0xa1, 0x01,                  // COLLECTION (Application)
        0xa1, 0x00,                  //   COLLECTION (Physical)
        0x05, 0x01,                  //   USAGE_PAGE (Generic Desktop)
        0x09, 0x30,                  //   USAGE (X)
        0x09, 0x31,                  //   USAGE (Y)
        0x09, 0x32,                  //   USAGE (Z)
        0x09, 0x33,                  //   USAGE (Rx)
        0x09, 0x34,                  //   USAGE (Ry)
        0x09, 0x35,                  //   USAGE (Rz)
        0x15, 0x81,                  //   LOGICAL_MINIMUM (-127)
        0x25, 0x7f,                  //   LOGICAL_MAXIMUM (127)
        0x95, 0x06,                  //   REPORT_COUNT (6)
        0x75, 0x08,                  //   REPORT_SIZE (8)
        0x81, 0x02,                  //   INPUT (Data,Var,Abs)
        0x05, 0x09,                  //   USAGE_PAGE (Button)
        0x19, 0x01,                  //   USAGE_MINIMUM (Button 1)
        0x29, 0x10,                  //   USAGE_MAXIMUM (Button 16)
        0x15, 0x00,                  //   LOGICAL_MINIMUM (0)
        0x25, 0x01,                  //   LOGICAL_MAXIMUM (1)
        0x95, 0x10,                  //   REPORT_COUNT (16)
        0x75, 0x01,                  //   REPORT_SIZE (1)
        0x81, 0x02,                  //   INPUT (Data,Var,Abs)
        0xc0,                        //   END_COLLECTION
        0xc0                           // END_COLLECTION
};


#define LED        13


static NormalizedWiiData wiiData;

// not used for game pads
static unsigned char idleRate;


#ifdef __cplusplus
extern "C"{
#endif
unsigned char usbFunctionSetup(unsigned char data){
        usbRequest_t* rq = (usbRequest_t*)data;

        // there are several request types but we only need to handle
        // 3 cases of the "class" type
        if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) /* class request type */
        {
                if (rq->bRequest == USBRQ_HID_GET_REPORT) /* wValue: ReportType (highbyte), ReportID (lowbyte) */
                {                       
                        usbMsgPtr = (unsigned char*)&wiiData;
                        return sizeof(wiiData);
                }
                else if (rq->bRequest == USBRQ_HID_GET_IDLE)
                {
                        usbMsgPtr = (unsigned char*)&idleRate;
                        return 1;
                }
                else if (rq->bRequest == USBRQ_HID_SET_IDLE)
                {
                        idleRate = rq->wValue.bytes;
                }
        }
        else
        {
                // no vendor specific requests implemented
        }
       
        return 0;
}
#ifdef __cplusplus
} // extern "C"
#endif

static int parity(int16_t value){
        int16_t a = 0;
        while(value){
                a ^= value;
                value >>= 1;
        }
        return a & 1;
}

void setup(){
        /* add setup code here */
        pinMode(LED, OUTPUT);        // For Test ONLY!!!


        WiiClassicController.init();

        cli();                // Disable Interrupt
        usbInit();        // Start v-usb
        usbDeviceDisconnect();        // Enforce USB re-enumeration, do this while interrupts are disabled!
        delay(250);
        usbDeviceConnect();
        sei();                // Enable Interrupts
}

void loop(){
        /* add main program code here */
        usbPoll();

        WiiClassicController.update();

        WiiClassicController.read(&wiiData);

        digitalWrite(LED, parity(*((int16_t*)&wiiData.buttons)));        // Use on-board LED to see the parity of buttons.

/*
        if(wiiData.buttons.a)Serial.println("A pressed.");
        if(wiiData.buttons.b)Serial.println("B pressed.");
        if(wiiData.buttons.x)Serial.println("X pressed.");
        if(wiiData.buttons.y)Serial.println("Y pressed.");
        if(wiiData.buttons.left)Serial.println("LEFT pressed.");
        if(wiiData.buttons.right)Serial.println("RIGHT pressed.");
        if(wiiData.buttons.up)Serial.println("UP pressed.");
        if(wiiData.buttons.down)Serial.println("DOWN pressed.");
        if(wiiData.buttons.l)Serial.println("L pressed.");
        if(wiiData.buttons.r)Serial.println("R pressed.");
        if(wiiData.buttons.zl)Serial.println("ZL pressed.");
        if(wiiData.buttons.zr)Serial.println("ZR pressed.");
        if(wiiData.buttons.plus)Serial.println("- pressed.");
        if(wiiData.buttons.home)Serial.println("HOME pressed.");
        if(wiiData.buttons.minus)Serial.println("+ pressed.");
*/
       
        // Wait until endpoint is ready
        while(!usbInterruptIsReady())usbPoll();

        // Send report
        usbSetInterrupt((unsigned char*)(&wiiData), sizeof(wiiData));
}
使用了板载LED作为输入按键的状态显示。如果有奇数个按键按下,LED就亮起来。用来监视手柄工作状态挺不错的。
页: [1]
查看完整版本: arduino + v-usb + Wii Classic Controller = USB手柄