[TH] Arduino: JoyStick Shield

บทความนี้แนะนำการใช้ Game Pad/Joystick กับบอร์ด Arduino Uno หรือ Arduino Mega เนื่องจากเป็นโมดูลที่ออกแบบเป็น Shield ของบอร์ดทั้ง 2 เมื่อนำมาประกอบจะได้เกมแพดน่ารัก ๆ 1 ชิ้นดังภาพที่ 1 โดยในบทความอธิบายเพิ่มเติมเกี่ยวกับข้อมูลของการเชื่อมต่อระหว่างอุปกรณ์แต่ละชิ้นกับ GPIO พร้อมตัวอย่างการใช้งาน ซึ่งเนื้อหาเกี่ยวกับโมดูลจอยสติกอ่านได้จากบทความก่อนหน้านี้

ภาพที่ 1 Joystick Shield

Joystick Shield

ชิลด์จอยสติกเป็นบอร์ดสำหรับใส่บนบอร์ด Arduino Uno หรือ Arduino Mega ที่เป็นฟอร์มเดียวกัน และได้สภาพของการต่อพ่วงเป็นดังภาพที่ 1 แต่สำหรับคนชอบทำเองอย่างพวกเรา ซึ่งก่อนจะหาซื้อชิลด์ตัวนี้มีได้ทดลองทำเองกับไมโครคอนโทรลเลอร์แบบต่าง ๆ จนได้ผลในระดับที่ใช้งานจริงได้ดังภาพที่ 2,3 และ 4

ภาพที่ 2 ต้นแบบกับ STM32
ภาพที่ 3 ต้นแบบกับ ESP32
ภาพที่ 4 ต้นแบบกับ ESP32 SPRAM

จากภาพที่ 5 จะพบว่าชิลด์ตัวนี้ประกอบไปด้วยโมดูลจอยสติก กับสวิตช์แบบกดติดปล่อยกับอีก 6 ตัว โดยแต่ละตัวต่อวงจร Pull Up เอาไว้ ซึ่งการเชื่อมต่อของโมดูลและสวิตช์กับขาของ Arduino Uno/Mega เป็นดังภาพที่ 5 หรือตามตารางต่อไปนี้

JoyStick SheildArduino Uno/Arduino Mega GPIO
VrXA0
VrYA1
Joystick SWD8
sw เล็กซ้ายD7
sw เล็กขวาD6
sw ฟ้าซ้ายD5
sw ฟ้าขวาD3
sw เหลืองบนD2
sw เหลืองล่างD4
ภาพที่ 5 ตำแหน่งการเชื่อมต่อ

ตัวอย่างโปรแกรม

ตัวอย่างโปรแกรมแสดงสถานะของการทำงานของจอยสติกและสถานะของสวิตช์ต่าง ๆ เป็นดังนี้ และตัวอย่างผลลัพธ์เป็นดังภาพที่ 6

/****************************************************************
   Joypad Shield
   by JarutEx (https://www.jarutex.com)
 ****************************************************************/
#define VR_X 0
#define VR_Y 1
#define VR_SW 8
#define SW_SELECT 7 // Select
#define SW_START 6 // Start
#define SW_X 5 // blue left
#define SW_Y 2 // yellow top
#define SW_A 4 // yellow bottom
#define SW_B 3 // blue right
#define NUM_SWITCHES 7

uint8_t swPins[NUM_SWITCHES] = {VR_SW, SW_SELECT, SW_START, SW_X, SW_Y, SW_A, SW_B};
uint8_t swStatus[NUM_SWITCHES] = {0, 0, 0, 0, 0, 0, 0}; // 1-pressed, 0-released
uint16_t joy[2] = {0, 0}; // x,y

void doInput() {
  joy[0] = analogRead(0);
  joy[1] = analogRead(1);
  for (int i = 0; i < NUM_SWITCHES; i++) {
    swStatus[i] = ((digitalRead(swPins[i])) ? (0) : (1));
  }
}

void doShowInfo() {
  Serial.print("X: ");
  Serial.print(joy[0]);
  Serial.print(" Y: ");
  Serial.print(joy[1]);
  Serial.print(" Sw: ");
  for (int i = 0; i < NUM_SWITCHES; i++) {
    Serial.print(swStatus[i]);
    if (i < (NUM_SWITCHES - 1)) {
      Serial.print(":");
    }
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < NUM_SWITCHES; i++) {
    pinMode( swPins[i], INPUT );
    digitalWrite( swPins[i], HIGH );
  }
}

void loop() {
  doInput();
  doShowInfo();
}
ภาพที่ 6 ตัวอย่างผลลัพธ์จากตัวอย่างโปรแกรม

กรณีที่ใช้กับบอร์ด ESP32 ดังภาพที่ 7 ต้องเชื่อมต่อจากขั้วจ่อที่เป็นสีเหลืองจากด้านขวามือด้านบนและโค้ดตัวอย่างโปรแกรมเป็นดังนี้

/*
 * esp32oled + GamePad
 * (C) 2021, JarutEx (https://www.jarutex.com)
 * 2021-07-06
*/

#include <Arduino.h>

#define PIN_VR_X 36
#define PIN_VR_Y 39
#define PIN_SW_A 2
#define PIN_SW_B 14
#define PIN_SW_C 13
#define PIN_SW_D 15
#define PIN_SW_E 16
#define PIN_SW_F 26
#define MAX_SW 6

uint8_t swPins[MAX_SW] = {PIN_SW_A,PIN_SW_B,PIN_SW_C,PIN_SW_D,PIN_SW_E,PIN_SW_F};
uint8_t swValues[MAX_SW];
uint8_t vrPins[2] = {PIN_VR_X, PIN_VR_Y};
uint16_t vrValues[2];

void setup() {
  for (int i=0; i<MAX_SW; i++) {
    pinMode( swPins[i], INPUT_PULLUP );
    swValues[i] = 1;
  }
  Serial.begin(9600);
}

void doUpdate() {
  for (int i=0; i<MAX_SW; i++) {
    swValues[i] = digitalRead( swPins[i] );
  }
  vrValues[0] = analogRead( vrPins[0] );
  vrValues[1] = analogRead( vrPins[1] );  
}

void doShow() {
  Serial.print(vrValues[0]);
  Serial.print(",");
  Serial.print(vrValues[1]);
  Serial.print(":");
  for (int i=0; i<MAX_SW; i++) {
    Serial.print(swValues[i]);
    if (i<(MAX_SW-1)) {
      Serial.print("/");
    }
  }
  Serial.println();
}

void loop() {
  doUpdate();
  doShow();
  delay(250);
}
ภาพที่ 7 การใช้ชิลด์กับบอร์ด ESP32

ตัวอย่างการใช้งานกับบอร์ด ESP32 ที่เชื่อมต่อกับปุ่มต่าง ๆ มีโค้ดการทำงานดังนี้

# Joystick module + ESP32 + MicroPython
# By JarutEx (https://www.jarutex.com)
from machine import Pin, ADC
import time
import machine as mc
import gc

gc.collect()
gc.enable()

mc.freq(240000000)

vrx = ADC(Pin(36, Pin.IN))
vrx.atten(ADC.ATTN_11DB)       #Full range: 3.3v
vry = ADC(Pin(39, Pin.IN))
vry.atten(ADC.ATTN_11DB)       #Full range: 3.3v

swPins = [
    Pin(2, Pin.IN, Pin.PULL_UP), # A
    Pin(14, Pin.IN, Pin.PULL_UP), # B
    Pin(13, Pin.IN, Pin.PULL_UP), # C
    Pin(15, Pin.IN, Pin.PULL_UP), # D
    Pin(16, Pin.IN, Pin.PULL_UP), # E
    Pin(26, Pin.IN, Pin.PULL_UP) #f
]

vrxValue = 0
vryValue = 0
swValue = [1,1,1,1,1,1]

def doUpdate():
    global vrxValue, vryValue, swValue
    vrxValue = vrx.read()
    vryValue = vry.read()
    for i in range(6):
        swValue[i] = swPins[i].value() 
    
def doShow():
    print("({},{}):A{}/B{}/C{}/D{}/E{}/F{}".format(
        vrxValue,vryValue,
        swValue[0],swValue[1],swValue[2],
        swValue[3],swValue[4],swValue[5]))

while True:
    doUpdate()
    doShow()
    time.sleep_ms(200)

สรุป

จากบทความนี้จะพบว่าชิลด์จอยสติกสามารถใช้งานได้ทันทีโดยไม่ต้องต่อวงจรเพิ่มเติม และขาของ Arduino Uno และ Arduino Mega มีมากพอสำหรับการใช้งาน แต่อย่างไรก็ดี ถ้าต้องการให้แสดงผลด้วยความเร็วและสวยงาม ซึ่งเป็นขีดจำกัดของบอร์ดทั้ง 2 นี้ เนื่องจากปริมาณหน่วยความจำแรมมีไม่มากพอสำหรับทำเทคนิคการสลับบัฟเฟอร์หรือการซ้อนภาพต่าง ๆ ดังนั้น ถ้าสามารถนำภาคจอยสติกนี้เชื่อมต่อกับไมโครคอนโทรลเลอร์ที่ทำหน้าที่แสดงผลและปรมวลผลภาพเข้าด้วยกันได้ ผู้อ่านสามารถสร้างเครื่องเล่นเกมของตนเองขึ้นมาได้โดยไม่ยุ่งยากเลยทีเดียว สุดท้ายนี้ขอให้สนุกกับการเขียนโปรแกรมครับ

ท่านใดอยากพูดคุยสามารถคอมเมนท์ไว้ได้เลยครับ

แหล่งอ้างอิง

  1. JoyStick Shield expansion board for arduino

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-07-04, 2021-07-06, 2021-10-12