見出し画像

M5Stackのジョイスティック制御


ジョイスティックを使って、M5Stackのディスプレイ上に表示したカーソルの制御を行います。AD変換やディスプレイの表示方法などM5Stackの基礎的な部分は以下を参考にしました。

使用するジョイスティックの説明

ジョイスティック

使用するジョイスティックを以下の図に示します。M5Stackの下部にIMU基板を接続していますが、今回は使用しないので無視してください。

使用するジョイスティックとM5Stack basic

ジョイスティックの可動域とM5StackのanalogReadの取得値の関係を調べた結果、これらの関係は以下の図のようになっていました。

ジョイスティックの可動域とanalogReadの取得値の関係

図において、オレンジで示した範囲がジョイスティックの可動域を、青で示
した領域がanalogReadで取得する値が変化する範囲を示します。また、青で示した領域の左上で取得される値と右下で取得される値(x,y)を図に示しました。

オレンジで示される領域では、値は最大値または最小値が取得されます。

図のように、実際の可動域に対して、analogReadの値が変化する範囲は小さく設定されていることが分かります。

M5Stackとジョイスティックの接続

M5Stackとジョイスティックのピンを以下のように接続します。

配線の様子
  • GND ⇔ GND

  • VRx ⇔ 35ピン

  • VRy ⇔ 36ピン

  • SW ⇔ 2ピン

  • Vin ⇔ 3.3V

今回は、M5Stackの内部プルアップを使用するため、SWとM5Stackの2ピンは直接接続します。内部プルアップを使用する場合、ピンのセットアップを以下のように行います。

pinMode(STICK_BUTTON, INPUT_PULLUP); // ジョイスティックボタン入力ピンの設定(内部プルアップ)

ジョイスティックのVRx,VRyは連続値を出力とするため、M5StackのAD変換用ピンである35,36ピンと接続します。AD変換に使用できるピンは限られているので注意してください。

カーソルの制御手法の説明

M5Stackの画面にカーソルを表示します。今回、ジョイスティックから取得した位置(VRx,VRy)をそのまま画面上の座標に変換することで、カーソル位置の指定を行います。

値の変換にはmap関数を使用します。map関数は以下のように使用します。

map(変換する入力値, 入力値の最小値, 入力値の最大値, 変換後の最小値, 変換後の出力値)

値の変換に使用するコードは以下のようになります。

map(X, 0, 4095, 0, M5.Lcd.width())

ここで、M5.Lcd.width()はM5Stackのディスプレイの横幅の最大値を取得します。

ソースコード

ソースコードの全体を以下に示します。カーソルはdrawEllipseによって丸を表示しています。

#include <M5Stack.h>

TFT_eSprite sprite = TFT_eSprite(&M5.Lcd);

#define STICK_X 35
#define STICK_Y 36
#define STICK_BUTTON 2

void setup() {
  M5.begin();
  M5.Speaker.begin();
  M5.Speaker.mute();

  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(2);

  sprite.setColorDepth(8);
  sprite.setTextSize(2);
  sprite.createSprite(M5.Lcd.width(), M5.Lcd.height());

  pinMode(STICK_X, INPUT); //スティックのX位置
  pinMode(STICK_Y, INPUT); //スティックのY位置
  pinMode(STICK_BUTTON, INPUT_PULLUP); // ジョイスティックボタン入力ピンの設定(内部プルアップ)
}

void loop() {
  sprite.fillScreen(BLACK);
  sprite.setCursor(0, 0);
  int X = analogRead(STICK_X);
  int Y = analogRead(STICK_Y);
  sprite.printf("stick X :%d\n",X);
  sprite.printf("stick Y :%d\n",Y);
  sprite.printf("stick distance :%f\n",sqrt(pow(X, 2) + pow(Y, 2))); //原点からの距離
  sprite.printf("stick button state :%d\n",digitalRead(2));
  sprite.drawEllipse(map(X, 0, 4095, 0, M5.Lcd.width()), map(Y, 0, 4095, 0, M5.Lcd.height()), 10, 10, WHITE); //スティックの位置をLcdの位置に変換
  sprite.pushSprite(0, 0);
  delay(1);
}

画面更新時のディスプレイのちらつきを防ぐため、spriteを使って描画しています。spriteの使用方法は以下のサイトを参考にさせていただきました。

制御の様子

制御の動画を以下に示します。

制御の様子

まとめ

ジョイスティックを使って、カーソル位置の制御を行いました。今回使用した方法は実装は簡単でしたが、以下の問題点が挙げられました。

  • スティックを離すとカーソルが画面中央に戻ってしまう。

  • 細かい位置操作が難しい

  • スティックを操作していない状態でも、誤差によってカーソルが微動する

この記事が気に入ったらサポートをしてみませんか?