LoginSignup
8
2
この記事誰得? 私しか得しないニッチな技術で記事投稿!

X68000Z 用のゲームコントローラーとコンバーターを作る

Last updated at Posted at 2023-06-13

はじめに

『X68000Z』で動作するゲームコントローラーとしては、『メガドライブミニ/2』用の『ファイティング 6B』を所持していましたが、X68000 のゲームは格ゲーを除けば 8 方向 + 2 ボタンのゲームコントローラーで動作するものが殆どで、連射装置も欲しい所でした。

X68000Z はゲームコントローラーのボタンをカスタマイズする機能を持っておらず、公式に対応しているのはゲーム機ミニシリーズ用のコントローラーです。

『X68000Z PRODUCT EDITION (BLACK MODEL)』には専用コントローラー『X68000 Z ジョイカード (ZKJC-009-BK)』が付属します。単体でも販売されています。

それ以外の多ボタンコントローラーでは、とんでもない位置のボタンに A ボタンと B ボタンが割り当てられる事があります (2 ボタンなら大丈夫)。『Logicool F310r』のように全く動作しないコントローラーもあります。

image.png

連射機能付きのコントローラーで X68000Z と相性が良さそうだったのは『HORI ターボパッド for PCエンジン mini』でしたが、気付いた時には終売&プレミア価格でした。

本記事は自身のゲームコントローラー事情をどうにかしようと、X68000Z のコミュニティサイトである 「Z-CLUB」 に投稿した内容のダイジェスト版です。

Z-CLUB の記事はログインしないと閲覧もできません。

ゲームコントローラーとコンバーター

プレイするゲームは『GRADIUS』を想定しています。

■ フットスイッチ

最初は自作の USB フットスイッチに連射機能を付けてみました。USB フットスイッチのマイコンボードは『Da Vinci 32U』です。

image.png

HID キーボードとして振る舞い、ペダルを踏んでいる間 〔X〕(ショット) と 〔C〕(ミサイル) を連射するものです。ゲームコントローラーは別に接続してあり、自機の移動とパワーアップはそちらで行ないます。

スケッチ

KEY_TURBO.ino
#include<Keyboard.h>

/* DIGITAL PIN */
const int BTN_PIN_POWERUP =  2;
const int BTN_PIN_SHOT    =  3;
const int BTN_PIN_MISSILE =  4;

void setup() {
  pinMode(BTN_PIN_POWERUP , INPUT_PULLUP);
  pinMode(BTN_PIN_SHOT    , INPUT_PULLUP);
  pinMode(BTN_PIN_MISSILE , INPUT_PULLUP);
  Keyboard.begin();
}

void loop() {
  /* KEY SEND */
  if (digitalRead(BTN_PIN_SHOT   ) == LOW)
    Keyboard.press('x');
  if (digitalRead(BTN_PIN_MISSILE) == LOW)
    Keyboard.press('c');
  delay(8);
  Keyboard.releaseAll();
  delay(8);
}

■ コンバーター

X68000Z や MSX で使っていた連射パッドを発掘したので、これを接続できるコンバータを作る事にしました。

image.png

マイコンボードには『Pro Micro (5V / 16MHz)』を使う事にしました。

結線は次の通りです。最初のテストに『Arduboy』を使ったため、それに倣っています。

DSUB9 Arduino
1 A0
2 A3
3 A2
4 A1
5 5V
6 D7
7 D8
8 GND
9 GND

3D プリンタでケースも作りました。

image.png

実機の連射パッドが使えていい感じです。

image.png

原材料費は USB ケーブル抜きで 1,000円くらいでしょうか。

スケッチ

・スケッチのコンパイルには『Arduino Joystick Library 2.x』が必要です。

JOY_CONV.ino
#include <Joystick.h>

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 2, 1, 
                   false, false, false, false, false, false, 
                   false, false, false, false, false);
    
/* PINS */
const int PIN_UP    = A0;
const int PIN_DOWN  = A3;
const int PIN_LEFT  = A2;
const int PIN_RIGHT = A1;
const int PIN_A     = 7;
const int PIN_B     = 8;

const int16_t Angles[16] = {
    JOYSTICK_HATSWITCH_RELEASE, 180, /* Down */             
    270, /* Left */             225, /* Left-lower */       
     90, /* Right */            135, /* Right-lower */      
    JOYSTICK_HATSWITCH_RELEASE, JOYSTICK_HATSWITCH_RELEASE,  
      0, /* Up */               JOYSTICK_HATSWITCH_RELEASE, 
    315, /* Left-upper */       JOYSTICK_HATSWITCH_RELEASE,  
     45, /* Right-upper */      JOYSTICK_HATSWITCH_RELEASE, 
    JOYSTICK_HATSWITCH_RELEASE, JOYSTICK_HATSWITCH_RELEASE};

void setup() {
  pinMode(PIN_UP   , INPUT_PULLUP);
  pinMode(PIN_DOWN , INPUT_PULLUP);
  pinMode(PIN_LEFT , INPUT_PULLUP);
  pinMode(PIN_RIGHT, INPUT_PULLUP);
  pinMode(PIN_A    , INPUT_PULLUP);
  pinMode(PIN_B    , INPUT_PULLUP);
  Joystick.begin();
}

void loop() {
  /* Arrows */
  int HatState = (!digitalRead(PIN_UP)   << 3) |
                 (!digitalRead(PIN_RIGHT)<< 2) |
                 (!digitalRead(PIN_LEFT) << 1) |
                 (!digitalRead(PIN_DOWN)     );
  Joystick.setHatSwitch(0, Angles[HatState]);
  /* Buttons */
  Joystick.setButton(0, !digitalRead(PIN_A));
  Joystick.setButton(1, !digitalRead(PIN_B));
}

上下の同時押し、左右の同時押しはできないようになっています。

「テストに Arduboy を使った」と書きましたが、このスケッチを『Arduboy』に転送すると『Arduboy』をゲームコントローラーとして使う事ができるようになります (操作性はイマイチですが)。

X68000 / MSX 用ゲームパッドをお持ちの方にオススメですが、『マジカルパッド』等はこのスケッチでは変換できません。

■ ゲームコントローラー

コンバーターでは基本的に 2 ボタンしか使えないので、ゲームコントローラー自体を作る事にしました。マイコンボードには『Pro Micro (5V / 3.3V) 』を使う事にしました。ゲームコントローラーのガワは、調達が容易な『スーパーファミコン』用のコントローラーを使う事にしました。程度の良さそうなものがハードオフで一つ 330円でした。
image.png

中古のコントローラーは変色している?Retr0bright でキレイになります。

image.png

USB ケーブルと『ProMicro』を別途用意。『ProMicro』は現在 1,000円前後。

image.png

このコントローラーは初期型のようです。IC (W545) を剥がして、

image.png

『ProMicro』のコネクタを外して、そこへジュンフロン線をハンダ付け。

image.png

パターンを剥離してしまったら、リカバリーポイントに接続してください。

image.png

USB ケーブルと仮にハンダ付けして動作が確認できたら、ホットボンドで固定。USB ケーブルも熱収縮チューブを被せて本ハンダ付け。

image.png

基板側にハンダ付けして…

image.png

『Pro Micro』にもハンダ付けして…

image.png

プログラマブルな USB ゲームコントローラーの完成です!

image.png

原材料費は 1,800円くらいでしょうか。パッドのゴムを交換しても 2,000円チョイで済むと思います。

ベースがゲーム機用のコントローラーなので、操作性はバツグンです。

結線 (W545 の場合)

結線の詳細は次の通りです。

image.png

Button W545 Pin Pro Micro
UP ICA 3 A0
DOWN ICA 4 A3
LEFT ICA 5 A2
RIGHT ICA 6 A1
A ICB 1 7
B ICA 1 8
X ICB 13 9
Y ICA 13 10
L ICB 12 3
R ICB 11 4
SELECT ICA 12 5
START ICA 11 6
(GND) ICA 7 GND
(GND) ICB 7 GND

結線 (V520 の場合)

結線の詳細は次の通りです。

image.png

image.png

Button Pin Pro Micro
UP 19 A0
DOWN 1 A3
LEFT 2 A2
RIGHT 3 A1
A 15 7
B 14 8
X 16 9
Y 13 10
L 18 3
R 17 4
SELECT 4 5
START 5 6
(GND) 10 GND

リセットボタン

『Pro Micro』はトラブルが起きた時にリセットを行う必要があります。ケースを開けて RST と GND をショートするだけなのですが、コントローラーの実験を行っている際にいちいちケースを開けるのは非効率的です。そこでいくつか作ったコントローラーの一つにリセットボタンを付ける事にしました。

ボトムケースに 4mm の穴を開けます。場所は〇の位置ですが「あぁ、ここか」という位置なので間違える事はないでしょう。

image.png

タクトスイッチと取り付けステーを用意します。タクトスイッチを交換できるようにしたかったので 3D プリンタでステーを作りましたが、面倒であればホットボンドで固定すればいいと思います。

image.png

タクトスイッチを RST と GND に接続。

image.png

取り付けステーはこのように使います。

image.png

表面からみた所です。操作に支障をきたす事もありませんし、誤って押す事もありません。

image.png

ダブルリセット (リセットボタンの 2 回押しも簡単になります。

image.png

スケッチ (X68000Z 用)

X68000Z での利用に特化したゲームコントローラーのスケッチです。

・スケッチのコンパイルには『Arduino Joystick Library 2.x』が必要です。
・スケッチのコンパイルには『MsTimer2』(ライブラリの追加で検索してください) が必要です。

JOY_X68000Z.ino
#include <Keyboard.h>
#include <Joystick.h>
#include <MsTimer2.h>

// Numeric keypad
#define KEY_NUM_LOCK      0xDB
#define KEY_KP_SLASH      0xDC
#define KEY_KP_ASTERISK   0xDD
#define KEY_KP_MINUS      0xDE
#define KEY_KP_PLUS       0xDF
#define KEY_KP_ENTER      0xE0
#define KEY_KP_1          0xE1
#define KEY_KP_2          0xE2
#define KEY_KP_3          0xE3
#define KEY_KP_4          0xE4
#define KEY_KP_5          0xE5
#define KEY_KP_6          0xE6
#define KEY_KP_7          0xE7
#define KEY_KP_8          0xE8
#define KEY_KP_9          0xE9
#define KEY_KP_0          0xEA
#define KEY_KP_DOT        0xEB

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 2, 1, 
                   false, false, false, false, false, false, 
                   false, false, false, false, false);
    
/* PINS */
const int PIN_UP    = A0;
const int PIN_DOWN  = A3;
const int PIN_LEFT  = A2;
const int PIN_RIGHT = A1;
const int PIN_A     =  7;
const int PIN_B     =  8;
const int PIN_X     =  9;
const int PIN_Y     = 10;
const int PIN_L     =  3;
const int PIN_R     =  4;
const int PIN_SEL   =  5;
const int PIN_START =  6;

const int16_t Angles[16] = {
    JOYSTICK_HATSWITCH_RELEASE, 180, /* Down */             
    270, /* Left */             225, /* Left-lower */       
     90, /* Right */            135, /* Right-lower */      
    JOYSTICK_HATSWITCH_RELEASE, JOYSTICK_HATSWITCH_RELEASE,  
      0, /* Up */               JOYSTICK_HATSWITCH_RELEASE, 
    315, /* Left-upper */       JOYSTICK_HATSWITCH_RELEASE,  
     45, /* Right-upper */      JOYSTICK_HATSWITCH_RELEASE, 
    JOYSTICK_HATSWITCH_RELEASE, JOYSTICK_HATSWITCH_RELEASE};

static bool pressState   = false;
static bool prev_state_L = false;
static bool prev_state_R = false;
static bool state_L      = false;
static bool state_R      = false;

int gameMode = 0; // 汎用 (GameCard)

void setup() {
  pinMode(PIN_UP   , INPUT_PULLUP);
  pinMode(PIN_DOWN , INPUT_PULLUP);
  pinMode(PIN_LEFT , INPUT_PULLUP);
  pinMode(PIN_RIGHT, INPUT_PULLUP);
  pinMode(PIN_A    , INPUT_PULLUP);
  pinMode(PIN_B    , INPUT_PULLUP);
  pinMode(PIN_X    , INPUT_PULLUP);
  pinMode(PIN_Y    , INPUT_PULLUP);
  pinMode(PIN_L    , INPUT_PULLUP);
  pinMode(PIN_R    , INPUT_PULLUP);
  pinMode(PIN_SEL  , INPUT_PULLUP);
  pinMode(PIN_START, INPUT_PULLUP);
  delay(100);

  gameMode = (!digitalRead(PIN_START) << 5) |
             (!digitalRead(PIN_SEL)   << 4) |
             (!digitalRead(PIN_Y)     << 3) |
             (!digitalRead(PIN_X)     << 2) |
             (!digitalRead(PIN_B)     << 1) |
             (!digitalRead(PIN_A)         );
  
  Keyboard.begin();  
  Joystick.begin();

  MsTimer2::set(31, toggleSwitch);
  MsTimer2::start();  
}

void loop() {
  /* Arrows */
  int HatState = (!digitalRead(PIN_UP)   << 3) |
                 (!digitalRead(PIN_RIGHT)<< 2) |
                 (!digitalRead(PIN_LEFT) << 1) |
                 (!digitalRead(PIN_DOWN)     );
  Joystick.setHatSwitch(0, Angles[HatState]);
  /* Buttons */
  bool state_A     = !digitalRead(PIN_A);
  bool state_B     = !digitalRead(PIN_B);
  bool state_X     = !digitalRead(PIN_X);
  bool state_Y     = !digitalRead(PIN_Y);
  prev_state_L     = state_L;
       state_L     = !digitalRead(PIN_L);
  prev_state_R     = state_R;
       state_R     = !digitalRead(PIN_R);
  bool state_SEL   = !digitalRead(PIN_SEL);
  bool state_START = !digitalRead(PIN_START);
  
  if (state_X) { 
    Joystick.setButton(0, pressState);
  } else {  
    Joystick.setButton(0, state_A);
  }
  if (state_Y) { 
    Joystick.setButton(1, pressState);
  } else { 
    Joystick.setButton(1, state_B);
  }  

  // LR 同時押しでソフトリセット
  if (prev_state_L && prev_state_R && state_L && state_R) { 
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press(KEY_F11);
    Keyboard.press(KEY_DELETE);
    delay(100);
    Keyboard.releaseAll();
    delay(500);
    return;
  }

  switch (gameMode % 2){
    case 0: // 汎用 (GameCard) 
      // R でポーズメニュー
      if (prev_state_R && state_R) {
        Keyboard.press(96);
        Keyboard.releaseAll();
        delay(500);
        return;    
      }
      break;
    case 1: // [A] 汎用 (ポーズメニューなし)
      break;
  }
  
  switch (gameMode){
    case 2: // [B]    GRADIUS (GameCard) 
    case 3: // [B][A] GRADIUS (ポーズメニューなし)
      // START で一時停止/解除
      if (state_START) { 
        Keyboard.press(KEY_ESC);
        delay(100);
        Keyboard.releaseAll();
        delay(100);
        return;
      }
      // L でコンティニュー
      if (prev_state_L && state_L) { 
        Keyboard.press(KEY_KP_8);
        delay(100);
        Keyboard.releaseAll();
        Keyboard.press(KEY_KP_2);
        delay(100);
        Keyboard.releaseAll();
        Keyboard.press(KEY_KP_4);
        delay(100);
        Keyboard.releaseAll();
        Keyboard.press(KEY_KP_6);
        delay(100);
        Keyboard.releaseAll();
        Keyboard.press('x');
        delay(100);
        Keyboard.releaseAll();
        Keyboard.press('z');
        delay(100);
        Keyboard.releaseAll();
        Keyboard.press(KEY_KP_8);
        delay(100);
        Keyboard.releaseAll();
        Keyboard.press(KEY_KP_2);
        delay(100);
        Keyboard.releaseAll();
        delay(500);
        return;
      }
      break;
    case 4: // [X]    超連射68K (GameCard) 
    case 5: // [X][A] 超連射68K (ポーズメニューなし)
      // SELECT でメニューの選択
      if (state_SEL) { 
        Keyboard.press(KEY_TAB);
        delay(100);
        Keyboard.releaseAll();
        delay(100);
        return;
      }
      // START でメニューの決定、一時停止/解除
      if (state_START) { 
        Keyboard.press(KEY_ESC);
        delay(100);
        Keyboard.releaseAll();
        delay(100);
        return;
      }
      break;
  }
}

void toggleSwitch() {
  pressState = !pressState;
}

連射ボタン付きの 2 ボタンコントローラーとして認識されます。方向キー+2ボタン以外の機能は HID キーボードとして振る舞う事で実現しています。

ボタン 機能
十字キー 移動
A A ボタン
B B ボタン
X A ボタン連射
Y B ボタン連射
L+R ソフトリセット

USB コネクタを挿す際に特定のボタンを押しっぱなしにしていると、そのゲームに適したプロファイルが使われます。リセットボタンを実装しているのなら、特定のボタンを押しながらリセットボタンを押しても OK です。

No 起動時 対象 SELECT START L R
0 (なし) 汎用 ポーズメニュー
1 [A] 汎用
2 [B] GRADIUS 一時停止/解除 コンティニューコマンド ポーズメニュー
3 [B][A] GRADIUS 一時停止/解除 コンティニューコマンド
4 [X] 超連射68K メニューの選択 メニューの決定
一時停止/解除
ポーズメニュー
5 [X][A] 超連射68K メニューの選択 メニューの決定
一時停止/解除
6 [X][B] (未登録) ポーズメニュー
7 [X][B][A] (未登録)
8 [Y] (未登録) ポーズメニュー
9 [Y][A] (未登録)

ポーズメニューは〔BREAK〕キーで出るので、GameCard 起動でないゲームで [R] ボタンを押した場合には最悪ゲームが強制終了されてしまいます。例えば、[A] ボタンを押しながらケーブルを挿すと、[R] ボタンによるポーズメニューが出なくなり、事故を防止する事ができます。

スケッチ (X68000Z ジョイカード互換)

『X68000Z ジョイカード (ZKJC-009-BK)』互換の 12 ボタン (使えないボタンあり) コントローラーです。瑞起のミニ系ゲーム機用コントローラと同じ配置です。但し、方向キーは POV (Hat) で実装してあります。

・スケッチのコンパイルには『Arduino Joystick Library 2.x』が必要です。

JOY_X68000Z_COMPATIBLE.ino
#include <Joystick.h>
#include <MsTimer2.h>

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 12, 1, 
                   false, false, false, false, false, false, 
                   false, false, false, false, false);
    
/* PINS */
const int PIN_UP    = A0;
const int PIN_DOWN  = A3;
const int PIN_LEFT  = A2;
const int PIN_RIGHT = A1;
const int PIN_A     =  7;
const int PIN_B     =  8;
const int PIN_X     =  9;
const int PIN_Y     = 10;
const int PIN_L     =  3;
const int PIN_R     =  4;
const int PIN_SEL   =  5;
const int PIN_START =  6;

const int16_t Angles[16] = {
    JOYSTICK_HATSWITCH_RELEASE, 180, /* Down */             
    270, /* Left */             225, /* Left-lower */       
     90, /* Right */            135, /* Right-lower */      
    JOYSTICK_HATSWITCH_RELEASE, JOYSTICK_HATSWITCH_RELEASE,  
      0, /* Up */               JOYSTICK_HATSWITCH_RELEASE, 
    315, /* Left-upper */       JOYSTICK_HATSWITCH_RELEASE,  
     45, /* Right-upper */      JOYSTICK_HATSWITCH_RELEASE, 
    JOYSTICK_HATSWITCH_RELEASE, JOYSTICK_HATSWITCH_RELEASE};

static bool pressState = false;

void setup() {
  pinMode(PIN_UP   , INPUT_PULLUP);
  pinMode(PIN_DOWN , INPUT_PULLUP);
  pinMode(PIN_LEFT , INPUT_PULLUP);
  pinMode(PIN_RIGHT, INPUT_PULLUP);
  pinMode(PIN_A    , INPUT_PULLUP);
  pinMode(PIN_B    , INPUT_PULLUP);
  pinMode(PIN_X    , INPUT_PULLUP);
  pinMode(PIN_Y    , INPUT_PULLUP);
  pinMode(PIN_L    , INPUT_PULLUP);
  pinMode(PIN_R    , INPUT_PULLUP);
  pinMode(PIN_SEL  , INPUT_PULLUP);
  pinMode(PIN_START, INPUT_PULLUP);
  Joystick.begin();

  MsTimer2::set(31, toggleSwitch);
  MsTimer2::start();  
}

void loop() {
  /* Arrows */
  int HatState = (!digitalRead(PIN_UP)   << 3) |
                 (!digitalRead(PIN_RIGHT)<< 2) |
                 (!digitalRead(PIN_LEFT) << 1) |
                 (!digitalRead(PIN_DOWN)     );
  Joystick.setHatSwitch(0, Angles[HatState]);
  /* Buttons */
  bool state_A     = !digitalRead(PIN_A);
  bool state_B     = !digitalRead(PIN_B);
  bool state_X     = !digitalRead(PIN_X);
  bool state_Y     = !digitalRead(PIN_Y);
  bool state_L     = !digitalRead(PIN_L);
  bool state_R     = !digitalRead(PIN_R);
  bool state_SEL   = !digitalRead(PIN_SEL);
  bool state_START = !digitalRead(PIN_START);
  
  if (state_X) { 
    Joystick.setButton(2, pressState);
  } else {  
    Joystick.setButton(2, state_A);
  }
  if (state_Y) { 
    Joystick.setButton(1, pressState);
  } else { 
    Joystick.setButton(1, state_B);
  }  
  Joystick.setButton(4, state_L);
  Joystick.setButton(5, state_R);
  Joystick.setButton(8, state_SEL);
  Joystick.setButton(9, state_START);
}

void toggleSwitch() {
  pressState = !pressState;
}
ボタン 機能
十字キー 移動
A ボタン 3
B ボタン 2
L ボタン 5
R ボタン 6
SELECT ボタン 9
START ボタン 10

X / Y ボタンは A / B ボタンの連射となっています。

ボタン 機能
X A ボタン連射
Y B ボタン連射

スケッチ (汎用)

こちらは汎用の 8 ボタンコントローラーです。ボタンの動作テストにはこちらの方がいいかもしれません。

・スケッチのコンパイルには『Arduino Joystick Library 2.x』が必要です。

JOY_GENERAL.ino
#include <Joystick.h>

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 8, 1, 
                   false, false, false, false, false, false, 
                   false, false, false, false, false);
    
/* PINS */
const int PIN_UP    = A0;
const int PIN_DOWN  = A3;
const int PIN_LEFT  = A2;
const int PIN_RIGHT = A1;
const int PIN_A     =  7;
const int PIN_B     =  8;
const int PIN_X     =  9;
const int PIN_Y     = 10;
const int PIN_L     =  3;
const int PIN_R     =  4;
const int PIN_SEL   =  5;
const int PIN_START =  6;

const int16_t Angles[16] = {
    JOYSTICK_HATSWITCH_RELEASE, 180, /* Down */             
    270, /* Left */             225, /* Left-lower */       
     90, /* Right */            135, /* Right-lower */      
    JOYSTICK_HATSWITCH_RELEASE, JOYSTICK_HATSWITCH_RELEASE,  
      0, /* Up */               JOYSTICK_HATSWITCH_RELEASE, 
    315, /* Left-upper */       JOYSTICK_HATSWITCH_RELEASE,  
     45, /* Right-upper */      JOYSTICK_HATSWITCH_RELEASE, 
    JOYSTICK_HATSWITCH_RELEASE, JOYSTICK_HATSWITCH_RELEASE};

boolean pressState = false;

void setup() {
  pinMode(PIN_UP   , INPUT_PULLUP);
  pinMode(PIN_DOWN , INPUT_PULLUP);
  pinMode(PIN_LEFT , INPUT_PULLUP);
  pinMode(PIN_RIGHT, INPUT_PULLUP);
  pinMode(PIN_A    , INPUT_PULLUP);
  pinMode(PIN_B    , INPUT_PULLUP);
  pinMode(PIN_X    , INPUT_PULLUP);
  pinMode(PIN_Y    , INPUT_PULLUP);
  pinMode(PIN_L    , INPUT_PULLUP);
  pinMode(PIN_R    , INPUT_PULLUP);
  pinMode(PIN_SEL  , INPUT_PULLUP);
  pinMode(PIN_START, INPUT_PULLUP);
  Joystick.begin();
}

void loop() {
  /* Arrows */
  int HatState = (!digitalRead(PIN_UP)   << 3) |
                 (!digitalRead(PIN_RIGHT)<< 2) |
                 (!digitalRead(PIN_LEFT) << 1) |
                 (!digitalRead(PIN_DOWN)     );
  Joystick.setHatSwitch(0, Angles[HatState]);
  /* Buttons */
  Joystick.setButton(0, !digitalRead(PIN_A    ));
  Joystick.setButton(1, !digitalRead(PIN_B    ));
  Joystick.setButton(2, !digitalRead(PIN_X    ));
  Joystick.setButton(3, !digitalRead(PIN_Y    ));
  Joystick.setButton(4, !digitalRead(PIN_L    ));
  Joystick.setButton(5, !digitalRead(PIN_R    ));
  Joystick.setButton(6, !digitalRead(PIN_SEL  ));
  Joystick.setButton(7, !digitalRead(PIN_START));
}
ボタン 機能
十字キー 移動
A ボタン 1
B ボタン 2
X ボタン 3
Y ボタン 4
L ボタン 5
R ボタン 6
SELECT ボタン 7
START ボタン 8

スケッチ (XInput 連射)

X68000Z では使えませんが、XInput 方式の連射コントローラーです。Steam なんかで使えます。

・スケッチのコンパイルには『MsTimer2』(ライブラリの追加で検索してください) が必要です。
・コンパイルには『Arduino XInput Library』ライブラリが必要です。
・ボードマネージャで『SparkFun AVR Boards w/ XInput』をインストールする必要があります。
・2 回目以降の書き込みにはリセットのダブルクリックが必要です (要リセットボタン)。

JOY_XINPUT_TURBO.ino
#include <XInput.h>
#include <MsTimer2.h>

// Setup
const boolean UseLeftJoystick   = false;  // set to true to enable left joystick
const boolean InvertLeftYAxis   = false;  // set to true to use inverted left joy Y
const boolean UseRightJoystick  = false;  // set to true to enable right joystick
const boolean InvertRightYAxis  = false;  // set to true to use inverted right joy Y
const boolean UseTriggerButtons = true;   // set to false if using analog triggers

/* PINS */
const int PIN_UP    = A0;
const int PIN_DOWN  = A3;
const int PIN_LEFT  = A2;
const int PIN_RIGHT = A1;
const int PIN_A     =  7;
const int PIN_B     =  8;
const int PIN_X     =  9;
const int PIN_Y     = 10;
const int PIN_L     =  3;
const int PIN_R     =  4;
const int PIN_SEL   =  5;
const int PIN_START =  6;

static bool pressState   = false;

void setup() {
  pinMode(PIN_UP   , INPUT_PULLUP);
  pinMode(PIN_DOWN , INPUT_PULLUP);
  pinMode(PIN_LEFT , INPUT_PULLUP);
  pinMode(PIN_RIGHT, INPUT_PULLUP);
  pinMode(PIN_A    , INPUT_PULLUP);
  pinMode(PIN_B    , INPUT_PULLUP);
  pinMode(PIN_X    , INPUT_PULLUP);
  pinMode(PIN_Y    , INPUT_PULLUP);
  pinMode(PIN_L    , INPUT_PULLUP);
  pinMode(PIN_R    , INPUT_PULLUP);
  pinMode(PIN_SEL  , INPUT_PULLUP);
  pinMode(PIN_START, INPUT_PULLUP);

  XInput.setAutoSend(true);
  XInput.begin();
  
  MsTimer2::set(31, toggleSwitch);
  MsTimer2::start();  
}

void loop() {
  /* Arrows */
  bool state_AU     = !digitalRead(PIN_UP);
  bool state_AR     = !digitalRead(PIN_RIGHT);
  bool state_AL     = !digitalRead(PIN_LEFT);
  bool state_AD     = !digitalRead(PIN_DOWN);

  if ((state_AU && state_AD) || (state_AL && state_AR)) { 
    XInput.setDpad(false, false, false, false, false);
  } else {
    XInput.setDpad(state_AU, state_AD, state_AL, state_AR, false);
  }
  
  /* Buttons */
  bool state_A     = !digitalRead(PIN_A);
  bool state_B     = !digitalRead(PIN_B);
  bool state_X     = !digitalRead(PIN_X);
  bool state_Y     = !digitalRead(PIN_Y);
  bool state_L     = !digitalRead(PIN_L);
  bool state_R     = !digitalRead(PIN_R);
  bool state_SEL   = !digitalRead(PIN_SEL);
  bool state_START = !digitalRead(PIN_START);
  
  if (state_X) { 
    XInput.setButton(BUTTON_A, pressState);
  } else {  
    XInput.setButton(BUTTON_A, state_A);
  }
  if (state_Y) { 
    XInput.setButton(BUTTON_B, pressState);
  } else { 
    XInput.setButton(BUTTON_B, state_B);
  }  
  XInput.setButton(BUTTON_BACK , state_SEL  );
  XInput.setButton(BUTTON_START, state_START);
  XInput.setButton(BUTTON_LB   , state_L    );
  XInput.setButton(BUTTON_RB   , state_R    );
}

void toggleSwitch() {
  pressState = !pressState;
}
ボタン 機能
(なし) ロゴボタン
A A ボタン
B B ボタン
X A ボタン連射
Y B ボタン連射
(なし) X ボタン
(なし) Y ボタン
L L ボタン
R R ボタン
SELECT Back ボタン
START Start ボタン
(なし) L3 ボタン 1
(なし) R3 ボタン 2
十字キー デジタル方向パッド
(なし) L トリガー
(なし) R トリガー
(なし) アナログ方向スティック L
(なし) アナログ方向スティック R

See also:

スケッチ (XInput 汎用)

X68000Z では使えませんが、XInput 方式の汎用コントローラーです。Steam なんかで使えます。

・コンパイルには『Arduino XInput Library』ライブラリが必要です。
・ボードマネージャで『SparkFun AVR Boards w/ XInput』をインストールする必要があります。
・2 回目以降の書き込みにはリセットのダブルクリックが必要です (要リセットボタン)。

JOY_XINPUT_GENERAL.ino
#include <XInput.h>

// Setup
const boolean UseLeftJoystick   = false;  // set to true to enable left joystick
const boolean InvertLeftYAxis   = false;  // set to true to use inverted left joy Y
const boolean UseRightJoystick  = false;  // set to true to enable right joystick
const boolean InvertRightYAxis  = false;  // set to true to use inverted right joy Y
const boolean UseTriggerButtons = true;   // set to false if using analog triggers

/* PINS */
const int PIN_UP    = A0;
const int PIN_DOWN  = A3;
const int PIN_LEFT  = A2;
const int PIN_RIGHT = A1;
const int PIN_A     =  7;
const int PIN_B     =  8;
const int PIN_X     =  9;
const int PIN_Y     = 10;
const int PIN_L     =  3;
const int PIN_R     =  4;
const int PIN_SEL   =  5;
const int PIN_START =  6;

void setup() {
  pinMode(PIN_UP   , INPUT_PULLUP);
  pinMode(PIN_DOWN , INPUT_PULLUP);
  pinMode(PIN_LEFT , INPUT_PULLUP);
  pinMode(PIN_RIGHT, INPUT_PULLUP);
  pinMode(PIN_A    , INPUT_PULLUP);
  pinMode(PIN_B    , INPUT_PULLUP);
  pinMode(PIN_X    , INPUT_PULLUP);
  pinMode(PIN_Y    , INPUT_PULLUP);
  pinMode(PIN_L    , INPUT_PULLUP);
  pinMode(PIN_R    , INPUT_PULLUP);
  pinMode(PIN_SEL  , INPUT_PULLUP);
  pinMode(PIN_START, INPUT_PULLUP);

  XInput.setAutoSend(true);
  XInput.begin();
}

void loop() {
  /* Arrows */
  bool state_AU     = !digitalRead(PIN_UP);
  bool state_AR     = !digitalRead(PIN_RIGHT);
  bool state_AL     = !digitalRead(PIN_LEFT);
  bool state_AD     = !digitalRead(PIN_DOWN);

  if ((state_AU && state_AD) || (state_AL && state_AR)) { 
    XInput.setDpad(false, false, false, false, false);
  } else {
    XInput.setDpad(state_AU, state_AD, state_AL, state_AR, false);
  }
  
  /* Buttons */
  XInput.setButton(BUTTON_A    , !digitalRead(PIN_A    ));
  XInput.setButton(BUTTON_B    , !digitalRead(PIN_B    ));
  XInput.setButton(BUTTON_X    , !digitalRead(PIN_X    ));
  XInput.setButton(BUTTON_Y    , !digitalRead(PIN_Y    ));
  XInput.setButton(BUTTON_LB   , !digitalRead(PIN_L    ));
  XInput.setButton(BUTTON_RB   , !digitalRead(PIN_R    ));
  XInput.setButton(BUTTON_BACK , !digitalRead(PIN_SEL  ));
  XInput.setButton(BUTTON_START, !digitalRead(PIN_START));
}
ボタン 機能
(なし) ロゴボタン
A A ボタン
B B ボタン
X X ボタン
Y Y ボタン
L L ボタン
R R ボタン
SELECT Back ボタン
START Start ボタン
(なし) L3 ボタン 1
(なし) R3 ボタン 2
十字キー デジタル方向パッド
(なし) L トリガー
(なし) R トリガー
(なし) アナログ方向スティック L
(なし) アナログ方向スティック R

おわりに

X68000Z PRODUCT EDITION (BLACK MODEL)』から『X68000 Z ジョイカード』が付属し、単体で購入もできるようになったので、ゲームコントローラーの問題は解消されつつあります。

image.png
『Hacker's Edition』『Early Access Kit』ユーザーの方は一つ確保しておく事をオススメします。

See also:

  1. 左アナログ方向スティック押し込み 2

  2. 右アナログ方向スティック押し込 2

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2