Arduino - Joystick

In deze handleiding leren we hoe u een joystick gebruikt met Arduino. We behandelen in detail:

Joystick Pinout

Hardware Benodigd

1×Arduino Uno R3
1×USB 2.0 kabel type A/B
1×Joystick
1×Jumper wires (verbindingsdraadjes)
1×(Aanbevolen) Schroefklem Block Shield voor Arduino Uno
1×(Aanbevolen) Sensors/Servo Expansion Shield for Arduino Uno
1×(Aanbevolen) Breadboard-Shield voor Arduino Uno
1×(Aanbevolen) Behuizing voor Arduino Uno
1×(Aanbevolen) Prototyping Basisplaat & Breadboard Kit voor Arduino Uno

Of u kunt de volgende kits kopen:

1×DIYables Sensorkit (18 sensoren/displays)
Openbaarmaking: Sommige van de links in deze sectie zijn Amazon-affiliate links. We kunnen een commissie ontvangen voor aankopen die via deze links worden gedaan, zonder extra kosten voor u. We waarderen uw steun.

Over de Joystick Sensor

U heeft waarschijnlijk een joystick gezien in bijvoorbeeld een gamecontroller, speelgoedcontroller, of zelfs in grote machines zoals een graafmachinebesturing.

De joystick bestaat uit twee potentiometers die loodrecht op elkaar staan en één drukknop. Daarom levert hij de volgende outputs:

  • Een analoge waarde (van 0 tot 1023) die overeenkomt met de horizontale positie (X-coördinaat genoemd)
  • Een analoge waarde (van 0 tot 1023) die overeenkomt met de verticale positie (Y-coördinaat genoemd)
  • Een digitale waarde van een drukknop (HIGH of LOW)

De combinatie van de twee analoge waarden kan 2D-coördinaten creëren waarbij de middenstand de rustpositie aangeeft. De werkelijke richting van de coördinaten is eenvoudig te identificeren bij het uitvoeren van een testcode (in het volgende gedeelte).

Sommige toepassingen gebruiken alle drie de outputs, andere slechts een deel daarvan.

Pinout

Een joystick heeft 5 pennen:

  • GND pin: moet worden verbonden met GND (0V)
  • VCC pin: moet worden verbonden met VCC (5V)
  • VRX pin: geeft een analoge waarde die overeenkomt met de horizontale positie (X-coördinaat)
  • VRY pin: geeft een analoge waarde die overeenkomt met de verticale positie (Y-coördinaat)
  • SW pin: is de output van de drukknop in de joystick. Deze is normaal open. Als u een pull-up weerstand gebruikt op deze pin, is de SW-pin HIGH wanneer niet ingedrukt en LOW wanneer ingedrukt.
Joystick Pinout

Hoe Werkt Het

  • Wanneer u de joystickhendel naar links of rechts duwt, verandert de spanning op de VRX-pin. Het spanningsbereik is van 0 tot 5V (0 aan de linkerkant en 5V aan de rechterkant). De spanning is evenredig met de positie van de hendel ⇒ de uitleeswaarde op de analoge pin van Arduino ligt tussen 0 en 1023
  • Wanneer u de joystickhendel naar boven of beneden duwt, verandert de spanning op de VRY-pin. Het spanningsbereik is van 0 tot 5V (0 boven en 5V onder). De spanning is evenredig met de positie van de hendel ⇒ de uitleeswaarde op de analoge pin van Arduino ligt tussen 0 en 1023
  • Wanneer u de joystickhendel in elke richting beweegt, veranderen de spanningen op zowel VRX als VRY proportioneel met de projectie van de positie op elke as
  • Wanneer u de joystickhendel van boven naar beneden indrukt, sluit de drukknop binnenin de joystick. Als u een pull-up weerstand gebruikt op de SW-pin, verandert de uitgang op SW van 5V naar 0V ⇒ de uitleeswaarde op de digitale pin van Arduino verandert van HIGH naar LOW

Aansluitschema

Arduino Joystick Aansluitschema

Deze afbeelding is gemaakt met Fritzing. Klik om de afbeelding te vergroten.

Hoe Te Programmeren Voor Joystick

De joystick bestaat uit twee delen: analoog (X- en Y-as) en digitaal (drukknop)

  • Voor het analoge deel (X, Y as) hoeft u alleen maar de waarde van de analoge ingang te lezen met de functie analogRead().
int xValue = analogRead(A1); int yValue = analogRead(A0);
  • Voor het digitale deel (drukknop): dit is een knop. De eenvoudigste en handigste manier is het gebruik van de ezButton library. Deze bibliotheek ondersteunt debounce voor knoppen en activeert ook een interne pull-up weerstand. Meer over knoppen vindt u in de Arduino - Button tutorial. De bijbehorende code wordt in de volgende paragraaf van deze handleiding gepresenteerd.

Na het uitlezen van de analoge waarden kan het nodig zijn deze om te zetten naar aanstuurbare waarden. Het volgende deel bevat voorbeeldcodes hiervoor.

Arduino Code

Deze sectie geeft de volgende voorbeelden van Arduino-code:

  • Voorbeeldcode: leest analoge waarden van de joystick
  • Voorbeeldcode: leest analoge waarden en de knopstatus van de joystick
  • Voorbeeldcode: zet analoge waarden om naar MOVE_LEFT, MOVE_RIGHT, MOVE_UP, MOVE_DOWN commando’s
  • Voorbeeldcode: zet analoge waarden om naar hoeken voor aansturing van twee servo motoren (bijvoorbeeld in een pan-tilt camera)

Leest analoge waarden van joystick

/* * Deze Arduino code is ontwikkeld door newbiely.nl * Deze Arduino code wordt zonder enige beperking aan het publiek beschikbaar gesteld. * Voor volledige instructies en schema's, bezoek: * https://newbiely.nl/tutorials/arduino/arduino-joystick */ #define VRX_PIN A1 // Arduino pin connected to VRX pin #define VRY_PIN A0 // Arduino pin connected to VRY pin int xValue = 0; // To store value of the X axis int yValue = 0; // To store value of the Y axis void setup() { Serial.begin(9600) ; } void loop() { // read analog X and Y analog values xValue = analogRead(VRX_PIN); yValue = analogRead(VRY_PIN); // print data to Serial Monitor on Arduino IDE Serial.print("x = "); Serial.print(xValue); Serial.print(", y = "); Serial.println(yValue); delay(200); }

Snelstart

  • Kopieer bovenstaande code en open deze met de Arduino IDE
  • Klik op de knop Upload in de Arduino IDE om de code op de Arduino te laden
  • Beweeg de joystickhendel maximaal naar de uiterste positie en draai deze vervolgens in een cirkel (met of tegen de klok in)
  • Bekijk het resultaat in de Seriële Monitor
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Uno
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Uno' on 'COM15')
New Line
9600 baud
Ln 11, Col 1
Arduino Uno on COM15
2
  • Houd tijdens het draaien van de joystickhendel de Seriële Monitor in de gaten
    • Als de X-waarde 0 is, noteer of onthoud dan deze positie als links ⇒ de tegenovergestelde richting is rechts
    • Als de Y-waarde 0 is, noteer of onthoud dan deze positie als boven ⇒ de tegenovergestelde richting is onder

    Leest analoge waarden en knopstatus van joystick

    /* * Deze Arduino code is ontwikkeld door newbiely.nl * Deze Arduino code wordt zonder enige beperking aan het publiek beschikbaar gesteld. * Voor volledige instructies en schema's, bezoek: * https://newbiely.nl/tutorials/arduino/arduino-joystick */ #include <ezButton.h> #define VRX_PIN A1 // Arduino pin connected to VRX pin #define VRY_PIN A0 // Arduino pin connected to VRY pin #define SW_PIN 2 // Arduino pin connected to SW pin ezButton button(SW_PIN); int xValue = 0; // To store value of the X axis int yValue = 0; // To store value of the Y axis int bValue = 0; // To store value of the button void setup() { Serial.begin(9600) ; button.setDebounceTime(50); // set debounce time to 50 milliseconds } void loop() { button.loop(); // MUST call the loop() function first // read analog X and Y analog values xValue = analogRead(VRX_PIN); yValue = analogRead(VRY_PIN); // Read the button value bValue = button.getState(); if (button.isPressed()) { Serial.println("The button is pressed"); // TODO do something here } if (button.isReleased()) { Serial.println("The button is released"); // TODO do something here } // print data to Serial Monitor on Arduino IDE Serial.print("x = "); Serial.print(xValue); Serial.print(", y = "); Serial.print(yValue); Serial.print(" : button = "); Serial.println(bValue); }

    Snelstart

    • Ga naar het icoon Libraries in de zijbalk van de Arduino IDE
    • Zoek op “ezButton” en vind de button library van ArduinoGetStarted.com
    • Klik op de knop Install om de ezButton-bibliotheek te installeren
    Arduino button library
    • Kopieer bovenstaande code en open deze met de Arduino IDE
    • Klik op de knop Upload in Arduino IDE om de code in de Arduino te plaatsen
    • Druk de joystickhendel naar links/rechts/boven/beneden
    • Druk de joystickhendel naar beneden (indrukken knop)
    • Bekijk het resultaat in de Seriële Monitor
    ∞
    Newbiely | Arduino IDE 2.3.8
    ──
    ☐
    ✕
    File
    Edit
    Sketch
    Tools
    Help
    Arduino Uno
    Newbiely.ino
    ···
    8 Serial.println("Hello World!");
    Output
    Serial Monitor
    Message (Enter to send message to 'Arduino Uno' on 'COM15')
    New Line
    9600 baud
    Ln 11, Col 1
    Arduino Uno on COM15
    2

    Zet analoge waarde om naar commando’s MOVE LEFT/RIGHT/UP/DOWN

    /* * Deze Arduino code is ontwikkeld door newbiely.nl * Deze Arduino code wordt zonder enige beperking aan het publiek beschikbaar gesteld. * Voor volledige instructies en schema's, bezoek: * https://newbiely.nl/tutorials/arduino/arduino-joystick */ #define VRX_PIN A1 // Arduino pin connected to VRX pin #define VRY_PIN A0 // Arduino pin connected to VRY pin #define LEFT_THRESHOLD 400 #define RIGHT_THRESHOLD 800 #define UP_THRESHOLD 400 #define DOWN_THRESHOLD 800 #define COMMAND_NO 0x00 #define COMMAND_LEFT 0x01 #define COMMAND_RIGHT 0x02 #define COMMAND_UP 0x04 #define COMMAND_DOWN 0x08 int xValue = 0 ; // To store value of the X axis int yValue = 0 ; // To store value of the Y axis int command = COMMAND_NO; void setup() { Serial.begin(9600) ; } void loop() { // read analog X and Y analog values xValue = analogRead(VRX_PIN); yValue = analogRead(VRY_PIN); // converts the analog value to commands // reset commands command = COMMAND_NO; // check left/right commands if (xValue < LEFT_THRESHOLD) command = command | COMMAND_LEFT; else if (xValue > RIGHT_THRESHOLD) command = command | COMMAND_RIGHT; // check up/down commands if (yValue < UP_THRESHOLD) command = command | COMMAND_UP; else if (yValue > DOWN_THRESHOLD) command = command | COMMAND_DOWN; // NOTE: AT A TIME, THERE MAY BE NO COMMAND, ONE COMMAND OR TWO COMMANDS // print command to serial and process command if (command & COMMAND_LEFT) { Serial.println("COMMAND LEFT"); // TODO: add your task here } if (command & COMMAND_RIGHT) { Serial.println("COMMAND RIGHT"); // TODO: add your task here } if (command & COMMAND_UP) { Serial.println("COMMAND UP"); // TODO: add your task here } if (command & COMMAND_DOWN) { Serial.println("COMMAND DOWN"); // TODO: add your task here } }

    Snelstart

    • Kopieer bovenstaande code en open met Arduino IDE
    • Klik op de knop Upload om de code op Arduino te plaatsen
    • Beweeg de joystickhendel naar links/rechts/boven/beneden of een willekeurige richting
    • Bekijk het resultaat in de Seriële Monitor
    ∞
    Newbiely | Arduino IDE 2.3.8
    ──
    ☐
    ✕
    File
    Edit
    Sketch
    Tools
    Help
    Arduino Uno
    Newbiely.ino
    ···
    8 Serial.println("Hello World!");
    Output
    Serial Monitor
    Message (Enter to send message to 'Arduino Uno' on 'COM15')
    New Line
    9600 baud
    Ln 11, Col 1
    Arduino Uno on COM15
    2

    ※ Notiz:

    Tegelijkertijd kan er geen, één of twee commando’s actief zijn (bijvoorbeeld UP en LEFT tegelijk).

    Zet analoge waarden om naar hoeken voor aansturing van twee servo motoren

    De details vindt u in de tutorial Arduino - Joystick controls Servo Motor

Video Tutorial

We overwegen het maken van videotutorials. Als u videotutorials belangrijk vindt, abonneer u dan op ons YouTube-kanaal om ons te motiveren de video's te maken.

De onderstaande videodemo gebruikt de onderstaande code. Let op: de video toont de Arduino Uno R4, maar het werkt identiek voor de Arduino Uno R3:

/* * Deze Arduino code is ontwikkeld door newbiely.nl * Deze Arduino code wordt zonder enige beperking aan het publiek beschikbaar gesteld. * Voor volledige instructies en schema's, bezoek: * https://newbiely.nl/tutorials/arduino/arduino-joystick */ #include "Arduino_LED_Matrix.h" // Pin definitions #define PIN_VRX A1 #define PIN_VRY A0 #define PIN_SW 2 #define PIN_BUZZER 8 // Matrix display dimensions #define MATRIX_WIDTH 12 #define MATRIX_HEIGHT 8 #define MAX_SNAKE_LENGTH 96 // Snake movement direction enum Direction { UP, DOWN, LEFT, RIGHT }; // Game state machine enum GameState { START_BOOT, // Initial boot screen scrolling "DIYables" PLAYING, // Active gameplay GAME_OVER // Game over score display }; GameState currentState = START_BOOT; ArduinoLEDMatrix matrix; uint8_t frame[8][12]; // Snake properties int snakeX[MAX_SNAKE_LENGTH]; int snakeY[MAX_SNAKE_LENGTH]; int snakeLength = 3; int score = 0; Direction dir = RIGHT; Direction nextDir = RIGHT; // Food coordinates int foodX = 0; int foodY = 0; // Movement timing unsigned long lastMoveTime = 0; int moveInterval = 250; // Text scrolling timing int startTextX = 12; int scoreTextX = 12; unsigned long lastScrollTime = 0; const int SCROLL_INTERVAL = 75; // Physics particle structure for 3s fall effect struct Particle { float x; float y; float vx; float vy; bool active; }; // Function prototypes void resetGame(); void handleInput(); void updateGameLogic(); void renderGame(); void spawnFood(); void renderText(String text, int xOffset); uint8_t getCharCol(char c, int col); void playShootingStarEffect(); void playEatSound(); void playStartSound(); bool isButtonPressed(); void clearFrame(); void setup() { pinMode(PIN_SW, INPUT_PULLUP); pinMode(PIN_BUZZER, OUTPUT); matrix.begin(); randomSeed(analogRead(A2)); } void loop() { switch (currentState) { case START_BOOT: // Show "DIYables" only on initial power-up if (millis() - lastScrollTime >= SCROLL_INTERVAL) { lastScrollTime = millis(); renderText("DIYables", startTextX); startTextX--; if (startTextX < -36) { startTextX = 12; } } if (isButtonPressed()) { resetGame(); playStartSound(); currentState = PLAYING; } break; case PLAYING: handleInput(); updateGameLogic(); renderGame(); break; case GAME_OVER: // Display score ("Score: X") if (millis() - lastScrollTime >= SCROLL_INTERVAL) { lastScrollTime = millis(); String scoreStr = "Score: " + String(score); renderText(scoreStr, scoreTextX); scoreTextX--; int strLen = scoreStr.length() * 4; if (scoreTextX < -strLen) { scoreTextX = 12; } } // Press button to restart game directly if (isButtonPressed()) { resetGame(); playStartSound(); currentState = PLAYING; } break; } } // Read Joystick axes independently for accurate 4-way directional control void handleInput() { int xVal = analogRead(PIN_VRX); int yVal = analogRead(PIN_VRY); int dx = xVal - 512; int dy = yVal - 512; // Prioritize axis with stronger deflection if (abs(dx) > abs(dy)) { if (dx < -200 && dir != RIGHT) nextDir = LEFT; else if (dx > 200 && dir != LEFT) nextDir = RIGHT; } else { if (dy < -200 && dir != DOWN) nextDir = UP; else if (dy > 200 && dir != UP) nextDir = DOWN; } } // 3.0-second shooting star fall effect void playShootingStarEffect() { const int MAX_PARTICLES = 45; Particle particles[MAX_PARTICLES]; int pCount = 0; // Convert active LEDs (snake body and food) into free-falling particles for (int r = 0; r < MATRIX_HEIGHT; r++) { for (int c = 0; c < MATRIX_WIDTH; c++) { if (frame[r][c] == 1 && pCount < 25) { particles[pCount].x = c; particles[pCount].y = r; particles[pCount].vx = (float)random(-15, 15) / 100.0; particles[pCount].vy = (float)random(-20, 5) / 100.0; particles[pCount].active = true; pCount++; } } } unsigned long startTime = millis(); unsigned long lastSpawn = 0; // 3-second physics simulation loop while (millis() - startTime < 3000) { clearFrame(); unsigned long elapsedTime = millis() - startTime; // Spawn additional falling star trails from top during the first 2.2 seconds if (elapsedTime < 2200 && millis() - lastSpawn > 80 && pCount < MAX_PARTICLES) { lastSpawn = millis(); particles[pCount].x = random(0, MATRIX_WIDTH); particles[pCount].y = -random(1, 4); particles[pCount].vx = (float)random(-5, 5) / 100.0; particles[pCount].vy = (float)random(10, 30) / 100.0; particles[pCount].active = true; pCount++; } // Update particle positions for (int i = 0; i < pCount; i++) { if (!particles[i].active) continue; particles[i].x += particles[i].vx; particles[i].y += particles[i].vy; particles[i].vy += 0.04; // Gravity acceleration int px = (int)round(particles[i].x); int py = (int)round(particles[i].y); // Draw particle if (py >= 0 && py < MATRIX_HEIGHT && px >= 0 && px < MATRIX_WIDTH) { frame[py][px] = 1; } // Draw particle trail if falling rapidly int tailY = py - 1; if (tailY >= 0 && tailY < MATRIX_HEIGHT && px >= 0 && px < MATRIX_WIDTH && particles[i].vy > 0.3) { frame[tailY][px] = 1; } // Deactivate particle once below screen if (py >= MATRIX_HEIGHT + 3) { particles[i].active = false; } } matrix.renderBitmap(frame, 8, 12); // Decreasing pitch sound from 1200Hz to 100Hz synchronized over 3 seconds int soundFreq = 1200 - (int)((elapsedTime / 3000.0) * 1100); if (soundFreq > 100) { tone(PIN_BUZZER, soundFreq, 30); } delay(35); } noTone(PIN_BUZZER); clearFrame(); matrix.renderBitmap(frame, 8, 12); } // 3x5 bitmap font data uint8_t getCharCol(char c, int col) { switch (c) { // "DIYables" characters case 'D': return (col==0)?0x1F:(col==1)?0x11:0x0E; case 'I': return (col==0)?0x11:(col==1)?0x1F:0x11; case 'Y': return (col==0)?0x03:(col==1)?0x1C:0x03; case 'a': return (col==0)?0x0C:(col==1)?0x12:0x1E; case 'b': return (col==0)?0x1F:(col==1)?0x14:0x08; case 'l': return (col==0)?0x11:(col==1)?0x1F:0x10; case 'e': return (col==0)?0x0C:(col==1)?0x16:0x14; case 's': return (col==0)?0x14:(col==1)?0x16:0x0A; // "Score:" characters case 'S': return (col==0)?0x12:(col==1)?0x15:0x09; case 'c': return (col==0)?0x0C:(col==1)?0x12:0x12; case 'o': return (col==0)?0x0C:(col==1)?0x12:0x0C; case 'r': return (col==0)?0x1E:(col==1)?0x04:0x02; case ':': return (col==0)?0x00:(col==1)?0x0A:0x00; case ' ': return 0x00; // Digits 0 - 9 case '0': return (col==0)?0x0E:(col==1)?0x11:0x0E; case '1': return (col==0)?0x12:(col==1)?0x1F:0x10; case '2': return (col==0)?0x19:(col==1)?0x15:0x12; case '3': return (col==0)?0x11:(col==1)?0x15:0x0A; case '4': return (col==0)?0x07:(col==1)?0x04:0x1F; case '5': return (col==0)?0x17:(col==1)?0x15:0x09; case '6': return (col==0)?0x0E:(col==1)?0x15:0x09; case '7': return (col==0)?0x19:(col==1)?0x05:0x03; case '8': return (col==0)?0x0A:(col==1)?0x15:0x0A; case '9': return (col==0)?0x12:(col==1)?0x15:0x0E; default: return 0x00; } } // Render string to LED matrix frame void renderText(String text, int xOffset) { clearFrame(); int curX = xOffset; int topY = 1; for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); for (int col = 0; col < 3; col++) { int screenX = curX + col; if (screenX >= 0 && screenX < MATRIX_WIDTH) { uint8_t colData = getCharCol(ch, col); for (int row = 0; row < 5; row++) { if ((colData >> row) & 1) { frame[topY + row][screenX] = 1; } } } } curX += 4; } matrix.renderBitmap(frame, 8, 12); } // Snake game logic update void updateGameLogic() { if (millis() - lastMoveTime < moveInterval) return; lastMoveTime = millis(); dir = nextDir; int newHeadX = snakeX[0]; int newHeadY = snakeY[0]; switch (dir) { case UP: newHeadY--; break; case DOWN: newHeadY++; break; case LEFT: newHeadX--; break; case RIGHT: newHeadX++; break; } // Wall collision -> Game Over if (newHeadX < 0 || newHeadX >= MATRIX_WIDTH || newHeadY < 0 || newHeadY >= MATRIX_HEIGHT) { playShootingStarEffect(); scoreTextX = 12; currentState = GAME_OVER; return; } // Self-collision -> Game Over for (int i = 0; i < snakeLength; i++) { if (snakeX[i] == newHeadX && snakeY[i] == newHeadY) { playShootingStarEffect(); scoreTextX = 12; currentState = GAME_OVER; return; } } bool ateFood = (newHeadX == foodX && newHeadY == foodY); if (ateFood) { snakeLength++; score++; playEatSound(); if (moveInterval > 100) { moveInterval -= 5; } } for (int i = snakeLength - 1; i > 0; i--) { snakeX[i] = snakeX[i - 1]; snakeY[i] = snakeY[i - 1]; } snakeX[0] = newHeadX; snakeY[0] = newHeadY; if (ateFood) { spawnFood(); } } void renderGame() { clearFrame(); frame[foodY][foodX] = 1; for (int i = 0; i < snakeLength; i++) { frame[snakeY[i]][snakeX[i]] = 1; } matrix.renderBitmap(frame, 8, 12); } void spawnFood() { bool onSnake; do { onSnake = false; foodX = random(0, MATRIX_WIDTH); foodY = random(0, MATRIX_HEIGHT); for (int i = 0; i < snakeLength; i++) { if (snakeX[i] == foodX && snakeY[i] == foodY) { onSnake = true; break; } } } while (onSnake); } void resetGame() { snakeLength = 3; score = 0; dir = RIGHT; nextDir = RIGHT; moveInterval = 250; snakeX[0] = 4; snakeY[0] = 3; snakeX[1] = 3; snakeY[1] = 3; snakeX[2] = 2; snakeY[2] = 3; spawnFood(); } bool isButtonPressed() { static bool lastState = HIGH; bool state = digitalRead(PIN_SW); if (lastState == HIGH && state == LOW) { delay(50); lastState = state; return true; } lastState = state; return false; } void clearFrame() { memset(frame, 0, sizeof(frame)); } void playEatSound() { tone(PIN_BUZZER, 1200, 60); } void playStartSound() { tone(PIN_BUZZER, 440, 80); delay(90); tone(PIN_BUZZER, 554, 80); delay(90); tone(PIN_BUZZER, 659, 120); delay(120); }

Reacties

Gerelateerde Tutorials

※ ONZE BERICHTEN

  • U bent welkom om de link naar deze tutorial te delen. Gebruik onze inhoud echter niet op andere websites. We hebben veel moeite en tijd gestoken in het maken van de inhoud, respecteer alstublieft ons werk!