macsbug

Just another WordPress.com site

Easy M5STACK JOYSTICK

leave a comment »

200円でできる 超安価な M5STACK JOYSTICK を作りました。 2018.06.06

テトリスをジョイスティックで操作できるようになります。
ケースに収まった感触と JOYSTICK の操作は とても使いやすいです。

左:M5STACK BASIC。 右:M5STAC BASIC + BATTERY:縦のサイズがピッタリです。


準備:

No  Nomen  Link   Price
 1  JoyStick Controller  whemyqong5 Store (C$1.01)   90円
 1  JoyStick Controller  cbincnm Store (C$1.01)   90円
 2  ピンヘッダ 1×40 (40P)  秋月電子通商   85円
 3  M5STACK BASIC  –     0円
 4  M5STACK BASIC CASE  –     0円
 5  ワイヤー  –   –
 6  穴あけ用カッター  –   –
 7  両面テープ  –   –
 ——————————-  ————————————  ——
 合計      175円
 スケッチ:macsbug  TETRIS with M5STACK
 8  スケッチ:しかるのち  M5Stack:テトリス改造

JoyStick Hots PS2 Two-axis Lever Joystick Game Sensor Controller

端子:[ GND, 5V, VRX, VRY, SW ]


ケース加工:
Joystick と USB-C, Power Swicth 場所にカッターで穴を空けます。
マルは 丸穴専用カッターが便利です。


回路図:配線は 5本のみです。


配線:直接配線。
_ ケースの穴と JOYSTICK KNOB の高さは重要です。
_ ケースの穴に対して JOYSTICK の高さと動きを事前に調べておきます。
_ 15ピン ピンヘッダー と JOYSTICK を 配線します。
_ 配線後 M5STACK に取り付け、JOYSTICK の高さと動きをチョックします。
_ 必要に応じて両面テープで固定してください。


配線:基板配線。
_ ケースの穴と JOYSTICK KNOB の高さは重要です。
_ ケースの穴に対して JOYSTICK の高さと動きを事前に調べておきます。
_ 基板に 15ピン ピンヘッダー と JOYSTICK を 配線します。
_ 配線後 M5STACK に取り付け、JOYSTICK の高さと動きをチョックします。
_ 必要に応じて両面テープで固定してください。
_ メモ:JOYSTICKは基板に取り付ける位置で高さを調整できます。


M5STACK 取り付け:JOYSTICKの高さ調整。
_ M5STACK と JOYSTICK は 以下の接続になります。
_ ケースの穴に対し JOYSTICKのKNOBが 自由に動く事が大切です。
_ JOYSTICKのKNOBが 穴に接触しない様に両面テープ等で高さを調整します。


Joystick 機能:

 
bool KeyPadLoop(){ 
 uint16_t joyX = analogRead(JOY_X);
 uint16_t joyY = analogRead(JOY_Y);
 if(digitalRead(sw) == 0){ClearKeys();but_A=true;delay(300);return true;}
 if( joyY >= 3500 ){ ClearKeys();but_DOWN =true;delay(250);return true;}
 if( joyX <= 1500 ){ ClearKeys();but_LEFT =true;delay(250);return true;}
 if( joyX >= 2500 ){ ClearKeys();but_RIGHT=true;delay(250);return true;}
 return false; }

参考:
How to connect the joystick to Arduino:JOYSICKの回路図と使用方法。


感想:
購入時の M5STACKケースが使用できないものかと考え、
超安価な 90円のジョイスティックを組み合わせてみました。
2つ作りましたが 基板にピンとJOYSITCK を取り付ける方法が楽でした。
ケースをカッターで切るのは 綺麗に出来ず なかなか難しいです。
1つの箱の中に収まる感じはスッキリして 握った感じがとても良いです。

 


スケッチ:

macsbug テトリス移植版オリジナル: TETRIS with M5STACK
しかるのち氏のテトリス改造版:M5Stack:テトリス改造 を DL します。
改造された しかるのち氏に感謝致し 使用させて頂きます。
M5Stack:テトリス改造 の [  bool KeyPadLoop ] を 以下の様に変更します。
_ これは Joystick の機能を追加する為です。

//========================================================================
// TETRIS with M5STACK : 2018.01.20 Transplant by macsbug
//                       2018.05.03 Modified by @shiakrunochi
//                       2018.06.06 Modified by macsbug
// Controller : Buttons A = LEFT, B = RIGHT, C = START, ROTATE
// Display    : Left = 100x240, Center = 120x240, Right = 100x240
// Block      : 8ea, 12x12 pixel
// SD         : tetris.jpg : BackGround Image : R.G.B 320x240 pixel
// Github     : (Original) https://macsbug.wordpress.com/2018/01/20/tetris-with-m5stack/
// Github     : (revision) http://shikarunochi.matrix.jp/?p=2296
// Github     : (joystick) https://macsbug.wordpress.com/2018/06/06/easy-m5stack-joystick/
//========================================================================
#include <M5Stack.h>                                       // M5STACK
#include "M5StackUpdater.h"                                // SD UPDATE
uint16_t BlockImage[8][12][12];                            // Block
uint16_t backBuffer[240][120];                             // GAME AREA
uint16_t nextBlockBuffer[60][48];                          // NEXT BLOCK AREA
const int Length = 12;     // the number of pixels for a side of a block
const int Width  = 10;     // the number of horizontal blocks
const int Height = 20;     // the number of vertical blocks
int screen[Width][Height] = {0}; //it shows color-numbers of all positions
struct Point {int X, Y;};
struct Block {Point square[4][4]; int numRotate, color;};
Point pos; Block block;
int nextBlockType = -1;
long score = 0;
Block nextBlock;
int rot, fall_cnt = 0;
bool started = false, gameover = false;
boolean but_A = false, but_LEFT = false, but_RIGHT = false, but_DOWN = false;
boolean but_UP = false;
int game_speed = 25; // 25msec
Block blocks[7] = {
  {{{{-1,0},{0,0},{1,0},{2,0}},{{0,-1},{0,0},{0,1},{0,2}},
  {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},2,1},
  {{{{0,-1},{1,-1},{0,0},{1,0}},{{0,0},{0,0},{0,0},{0,0}},
  {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},1,2},
  {{{{-1,-1},{-1,0},{0,0},{1,0}},{{-1,1},{0,1},{0,0},{0,-1}},
  {{-1,0},{0,0},{1,0},{1,1}},{{1,-1},{0,-1},{0,0},{0,1}}},4,3},
  {{{{-1,0},{0,0},{0,1},{1,1}},{{0,-1},{0,0},{-1,0},{-1,1}},
  {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},2,4},
  {{{{-1,0},{0,0},{1,0},{1,-1}},{{-1,-1},{0,-1},{0,0},{0,1}},
  {{-1,1},{-1,0},{0,0},{1,0}},{{0,-1},{0,0},{0,1},{1,1}}},4,5},
  {{{{-1,1},{0,1},{0,0},{1,0}},{{0,-1},{0,0},{1,0},{1,1}},
  {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},2,6},
  {{{{-1,0},{0,0},{1,0},{0,-1}},{{0,-1},{0,0},{0,1},{-1,0}},
  {{-1,0},{0,0},{1,0},{0,1}},{{0,-1},{0,0},{0,1},{1,0}}},4,7}
};
extern uint8_t tetris_img[];
#define JOY_X  2
#define JOY_Y 26
#define sw     5
//========================================================================
void setup(void) {
  Serial.begin(115200);         // SERIAL
  M5.begin();                   // M5STACK INITIALIZE
  Wire.begin();
  if(digitalRead(BUTTON_A_PIN) == 0){updateFromFS(SD);ESP.restart();}
  M5.Lcd.setBrightness(200);    // BRIGHTNESS = MAX 255
  M5.Lcd.fillScreen(BLACK);     // CLEAR SCREEN
  M5.Lcd.setRotation(1);        // SCREEN ROTATION = 0
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(2);
  //----------------------------// Make Block ----------------------------
  pinMode(sw,    INPUT_PULLUP);
  pinMode(JOY_X, INPUT);
  pinMode(JOY_Y, INPUT);
  //----------------------------// Make Block ----------------------------
  make_block( 0, BLACK);        // Type No, Color
  make_block( 1, 0x00F0);       // DDDD     RED
  make_block( 2, 0xFBE4);       // DD,DD    PUPLE 
  make_block( 3, 0xFF00);       // D__,DDD  BLUE
  make_block( 4, 0xFF87);       // DD_,_DD  GREEN 
  make_block( 5, 0x87FF);       // __D,DDD  YELLO
  make_block( 6, 0xF00F);       // _DD,DD_  LIGHT GREEN
  make_block( 7, 0xF8FC);       // _D_,DDD  PINK
  //----------------------------------------------------------------------
  // M5.Lcd.drawJpgFile(SD, "/tetris.jpg");     // Load background from SD
  M5.Lcd.drawJpg(tetris_img, 34215);     // Load background from file data
  PutStartPos();                                // Start Position
  for (int i = 0; i < 4; ++i) screen[pos.X + 
   block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = block.color;
  Draw();                                       // Draw block
  DrawNextBlock();
}
//========================================================================
void loop() {
  if (gameover) return;
  Point next_pos;
  int next_rot = rot;
  GetNextPosRot(&next_pos, &next_rot);
  ReviseScreen(next_pos, next_rot);
  M5.update();
  delay(game_speed);                                      // SPEED ADJUST
}
//========================================================================
void Draw() {                               // Draw 120x240 in the center
  for (int i = 0; i < Width; ++i) for (int j = 0; j < Height; ++j)
   for (int k = 0; k < Length; ++k) for (int l = 0; l < Length; ++l)
    backBuffer[j * Length + l][i * Length + k] = BlockImage[screen[i][j]][k][l];
    M5.Lcd.pushImage(100, 0, 120, 240, (uint16_t *)backBuffer);
}
//========================================================================
void DrawNextBlock() {  
  for(int x = 0; x < 48;x++) {
    for(int y = 0; y < 60;y++){
      nextBlockBuffer[y][x]=0;
    }
  }
  nextBlock = blocks[nextBlockType];
  int offset = 6 + 12;
  for (int i = 0; i < 4; ++i) {
      for (int k = 0; k < Length; ++k) for (int l = 0; l < Length; ++l){
        nextBlockBuffer[60 - (nextBlock.square[0][i].X * Length + l + 
        offset)][nextBlock.square[0][i].Y * Length + k + offset] = 
        BlockImage[nextBlockType + 1][k][l];
      }
  }
  M5.Lcd.pushImage(26, 100, 48, 60, (uint16_t *)nextBlockBuffer);
  M5.Lcd.fillRect(2, 76, 96, 19, BLACK);
  M5.Lcd.setCursor(10, 78);
  M5.Lcd.print(score);//M5.Lcd.printf("%7d",score);
}
//========================================================================
void PutStartPos() {
  pos.X = 4; pos.Y = 1;
  if (nextBlockType == -1){
    block = blocks[random(7)];
  }else{
    block = blocks[nextBlockType];
  }
  nextBlockType = random(7);
  rot = random(block.numRotate);
}
//========================================================================
bool GetSquares(Block block, Point pos, int rot, Point* squares) {
  bool overlap = false;
  for (int i = 0; i < 4; ++i) {
    Point p;
    p.X = pos.X + block.square[rot][i].X;
    p.Y = pos.Y + block.square[rot][i].Y;
    overlap |= p.X < 0 || p.X >= Width || p.Y < 0 || p.Y >= 
      Height || screen[p.X][p.Y] != 0;
    squares[i] = p;
  }
  return !overlap;
}
//========================================================================
void ClearKeys(){but_A=false;but_LEFT=false;but_RIGHT=false;but_DOWN=false;}
//========================================================================
void GameOver() {
  for (int i = 0; i < Width; ++i) for (int j = 0; j < Height; ++j) if (screen[i][j] != 0) screen[i][j] = 4; gameover = true; } //======================================================================== bool KeyPadLoop(){ uint16_t joyX = analogRead(JOY_X); uint16_t joyY = analogRead(JOY_Y); if(digitalRead(sw) == 0){ClearKeys();but_A=true;delay(300);return true;} if( joyY >= 3500 ){ ClearKeys();but_DOWN =true;delay(250); return true;}
  if( joyX <= 1500 ){ ClearKeys();but_LEFT =true;delay(250); return true;} if( joyX >= 2500 ){ ClearKeys();but_RIGHT=true;delay(250); return true;}
  return false;
}
//========================================================================
void GetNextPosRot(Point* pnext_pos, int* pnext_rot) {
  bool received = KeyPadLoop();
  if (but_A) started = true;
  if (!started) return;
  pnext_pos->X = pos.X;
  pnext_pos->Y = pos.Y;
  if ((fall_cnt = (fall_cnt + 1) % 10) == 0) pnext_pos->Y += 1;
  else if (received) {
    if (but_LEFT) { but_LEFT = false; pnext_pos->X -= 1;}
    else if (but_RIGHT) { but_RIGHT = false; pnext_pos->X += 1;}
    else if (but_DOWN) { but_DOWN = false; pnext_pos->Y += 1;}
    else if (but_A) { but_A = false;
      *pnext_rot = (*pnext_rot + block.numRotate - 1)%block.numRotate; 
    }
  }
}
//========================================================================
void DeleteLine() {
  int deleteCount = 0;
  for (int j = 0; j < Height; ++j) {
    bool Delete = true;
    for (int i = 0; i < Width; ++i) if (screen[i][j] == 0) Delete = false; if (Delete) { for (int k = j; k >= 1; --k) {
        for (int i = 0; i < Width; ++i) { screen[i][k] = screen[i][k - 1]; } } deleteCount++; } } switch (deleteCount){ case 1:score = score + 40;break; case 2:score = score + 100;break; case 3:score = score + 300;break; case 4:score = score + 1200;break; } if(score > 9999999){score = 9999999;}
}
//========================================================================
void ReviseScreen(Point next_pos, int next_rot) {
  if (!started) return;
  Point next_squares[4];
  for (int i = 0; i < 4; ++i) screen[pos.X + 
    block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = 0;
  if (GetSquares(block, next_pos, next_rot, next_squares)) {
   for (int i = 0; i < 4; ++i){
     screen[next_squares[i].X][next_squares[i].Y] = block.color;
   }
   pos = next_pos; rot = next_rot;
  }
  else {
   for (int i = 0; i < 4; ++i) screen[pos.X + 
    block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = block.color;
   if (next_pos.Y == pos.Y + 1) {
    DeleteLine(); PutStartPos();DrawNextBlock();
    if (!GetSquares(block, pos, rot, next_squares)) {
     for (int i = 0; i < 4; ++i) screen[pos.X + 
      block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = block.color;
      GameOver();
    }
   }
  }
  Draw();
}
//========================================================================
void make_block( int n , uint16_t color ){            // Make Block color       
  for ( int i =0 ; i < 12; i++ ) for ( int j =0 ; j < 12; j++ ){
    BlockImage[n][i][j] = color;                      // Block color
    if ( i == 0 || j == 0 ) BlockImage[n][i][j] = 0;  // BLACK Line
  } 
}
//========================================================================
広告

Written by macsbug

6月 6, 2018 @ 8:50 pm

カテゴリー: ESP32, M5STACK

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。