Wii傳統手把(Classic Controller)連接Arduino

Wii傳統手把和左手把一樣,都採用標準的I2C通訊協議,因此能輕易地和Arduino整合在一起。我購買的Wii傳統控制器是2006年推出的第一代,外型就像超級任天堂手把般的小巧,底下是和GameCube手把的對照:

GameCube手把與Wii傳統手把的對照

任天堂後來在2009年推出手感與按鍵配置更佳的「Wii傳統手把Pro」版,兩者的控制訊號格式都一樣。

下圖是傳統手把的按鈕與接腳名稱:

Wii傳統手把的按鈕與接腳名稱

因為Wii的控制器採用特殊的接頭,讀者可以購買「Wii手把延長線」來裁剪接頭,或者Wii連接器的專用PCB板,甚至改造舊的桌上型電腦介面卡,以便和Arduino相連。

下圖是筆者使用舊的電腦介面卡改造的Wii連接器外觀(請參閱《超圖解Arduino互動設計入門》11-19頁):

使用電腦介面卡改造的Wii連接器

和左手把一樣,傳統手把的I2C位址也是0x52,每次也都會傳回6個位元組的資料,裡面包含類比搖桿和所有按鈕的狀態訊息,其數據格式如下:

傳統手把的資料格式

位於肩部兩側的L和R,也是具備壓力感測的類比式按鈕(註:類比搖桿與類比按鈕的內部,各連接一個30K的可變電阻,內部照片和相關說明,請參閱WiiBrew.org的”Wiimote/Extension Controllers/Classic Controller“這篇文章說明);程式也能透過位元組4的第5和第1位元,讀取L和R鈕的開或關狀態(數位按鈕模式)

左類比搖桿的資料長度是6個位元(可能值為十進位0~63),精確度比較高,右類比搖桿與L、R鍵的資料長度都是5個位元(可能值為十進位0~31)。筆者實際測試所得到的數值範圍如下:

類比搖桿與按鈕的數值範圍

Arduino的Wii傳統手把程式庫與程式範例

Tim Hirzel寫了一個Wii Classic Controller Arduino程式庫,請將網頁裡的程式複製到記事本,或者Arduino的程式編輯器中,並命名成“WiiClassic.h”(或按此連結下載),存入Arduino的Libraries路徑底下的“WiiClassic”資料夾:

WiiClassic.h程式庫的存檔路徑

底下的範例程式碼,可在「序列埠監控視窗」顯示所有數位按鈕的狀態:


#include "Wire.h"
#include "WiiClassic.h"	// 引用Wii傳統手把的程式庫

WiiClassic wiiClassy = WiiClassic();

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

void loop() {
  delay(100);
  wiiClassy.update();

  if (wiiClassy.leftShoulderPressed()) {
    Serial.println("L");   // L被按下
  }
  if (wiiClassy.rightShoulderPressed()) {
    Serial.println("R");	// R被按下
  }
  if (wiiClassy.lzPressed()) {
    Serial.println("LZ");	// LZ被按下
  }
  if (wiiClassy.rzPressed()) {
    Serial.println("RZ");	// RZ被按下
  }
  if (wiiClassy.leftDPressed()) {
    Serial.println("LD");	// 十字左被按下
  }

  if (wiiClassy.rightDPressed()) {
    Serial.println("RD");	// 十字右被按下
  }

  if (wiiClassy.upDPressed()) {
    Serial.println("UD");	// 十字上被按下	
  }
  if (wiiClassy.downDPressed()) {
    Serial.println("DD");	// 十字下被按下
  }

  if (wiiClassy.selectPressed()) {
    Serial.println("select");  // SELECT (-)被按下
  }

  if (wiiClassy.homePressed()) {
    Serial.println("home.");	// HOME被按下
  }
  if (wiiClassy.startPressed()) {
    Serial.println("start.");	// START (+)被按下
  }

  if (wiiClassy.xPressed()) {
    Serial.println("x");	// x被按下
  }

  if (wiiClassy.yPressed()) {
    Serial.println("y");	// y被按下
  }

  if (wiiClassy.aPressed()) {
    Serial.println("a");	// a被按下
  }

  if (wiiClassy.bPressed()) {
    Serial.println("b");	// b被按下
  }
}

底下的範例程式碼,可在「序列埠監控視窗」顯示左類比搖桿的X, Y軸值:


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

WiiClassic wiiClassy = WiiClassic();

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

void loop() {
  delay(100);
  wiiClassy.update();

  Serial.print("x: ");
  // 改成wiiClassy..rightStickX()可傳回右搖桿的x軸值
  Serial.print(wiiClassy.leftStickX());
  Serial.print("y: ");
  // 改成wiiClassy..rightStickY()可傳回右搖桿的x軸值
  Serial.println(wiiClassy.leftStickY());
  Serial.println("------------------");
}

底下的範例程式碼,可在「序列埠監控視窗」顯示L和R的類比值:


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

WiiClassic wiiClassy = WiiClassic();

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

void loop() {
  delay(100);
  wiiClassy.update();

  Serial.print("L: ");
  Serial.print(wiiClassy.leftShouldPressure());
  Serial.print("R: ");
  Serial.print(wiiClassy.rightShouldPressure());
  Serial.println("------------------");
}

解析Wii手把資料的補充說明

傳統手把程式庫的程式碼,類似解析Wii左手把的程式庫,只是傳統手把的數據格式比較複雜一些。

從上文的Wii傳統手把數據表可得知,類比右搖桿的X軸值,分散在三個位元組。程式庫將接收到的6個位元組資料存入status陣列,因此,經過底下的運算步驟,即可獲得類比右搖桿的X軸數值:

解析類比右搖桿的X軸值

實際的程式碼片段如下:


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

以上的+運算,可用「邏輯或」(OR)代替(指令寫成一條豎線 | ):


int rightStickX() {
	return ((status[0] & (byte)0xc0) >> 3) | ((status[1] & (byte)0xc0) >> 5) | ((status[2] & (byte)0x80) >> 7);
}
Posts created 468

8 thoughts on “Wii傳統手把(Classic Controller)連接Arduino

  1. Hi 版主
    請問,假設我要用單晶片跟wii手把做聯結
    我想要手把按下什麼按鈕,單晶片的LCM就顯示什麼
    問題來了,如果在這構想之下
    那不就是單晶片要一直讀取手把的值
    這樣程式不就很沒有效率?

    1. hi scott:

      我覺得還好,反正它開機也是閒著沒事。

      若有必要,可以設置一個按鈕,按一下讓它睡眠或者喚醒它。

      thanks,
      jeffrey

  2. 不好意思,我用副廠pro搖桿可是完全讀不到,請問可能是什麼原因?
    謝謝!!

    1. Wii傳統手把和Wii左手把(nunchuk)的I2C位址都是0x52,為了方便對照與確認程式和接線,如果可能,你可以先用左手把測試看看。

      have fun!
      jeffrey

    1. 某些Arduino控制板,例如,採用Atmega32u4微控器的
      Arduino Pro Micro和Leonardo,微控器本身具備USB埠,可程式化成各種USB裝置,包含遊戲控制器在內。Arduino IDE本身有內建一些範例程式。

      thanks,
      jeffrey

  3. 不好意思~您指的(桌上型電腦介面卡)是指顯示卡嗎?可以有詳細的作法解說甚至照片、圖解解說嗎?。我想在電腦上玩WII模擬器並使用WII傳統手把,雖然有其他手把可以用(例如仿PS的USB手把),但感覺就是差了一點,如果可以連接WII傳統手把就更好了~。有爬文說可以用WII傳統手把連接藍芽後就可以接電腦藍芽了,但我的藍芽已經使用在耳機上,WIN10一台電腦也只能連接一個藍芽設備,常常更換手把的電池也蠻麻煩的,又花錢又非常不環保,可以改成USB直接插在電腦上就好了~

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top