Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Tal O
Published © GPL3+

Shooting aliens with PS2 joystick

A true blast from the past

IntermediateShowcase (no instructions)148
Shooting aliens with PS2 joystick

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
Analog joystick (Generic)
×1
ps2 male connector
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

Untitled file

Arduino
#include <ps2dev.h>    //Emulate a PS/2 device
PS2dev keyboard(4, 3); //clock (green), data (white)

// button related
#define BUT_RIGHT 0
#define BUT_LEFT 1
#define BUT_SPACE 2

#define BUT_PRESS 0
#define BUT_RELEASE 1
#define NUMBUTTON 3

// joyStick relater
#define JOYSTICK_X A0
#define JOYSTICK_Y A1
#define JOYSTICK_LB 5
#define JOYSTICK_RB 6

int joyStickXCenter = 0;
int joyStickYCenter = 0;
byte joyStickDebounceGap = 10;

// Variables will change:
int buttonState[NUMBUTTON];      // the current button state
int lastButtonState[NUMBUTTON]; // the previous reading from the input pin
unsigned long lastDebounceTime[NUMBUTTON]; // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers
byte currentCheckedButton = 0;


#define ps2DataBufferSIZE 7
byte ps2DataBuffer[ps2DataBufferSIZE];
byte ps2DataBufferHead = 0;
byte ps2DataBufferTail = 0;
byte messageByteSent = 0;


void insertToBuffer(byte value)
{
  ps2DataBuffer[ps2DataBufferHead] = value;
  ps2DataBufferHead = (ps2DataBufferHead + 1) % ps2DataBufferSIZE;
}

byte pullFromBuffer(byte * readValue)
{
  byte availableBuffer = 0;
  if (ps2DataBufferHead != ps2DataBufferTail)
  {
    *readValue = ps2DataBuffer[ps2DataBufferTail];
    availableBuffer = 1;
  }

  return availableBuffer;
}

void moveBufferToNext()
{
  // move
  ps2DataBufferTail = (ps2DataBufferTail + 1) % ps2DataBufferSIZE;
}



void setup()
{
  keyboard.keyboard_init();
  Serial.begin(115200);
  Serial.println("System started");
  pinMode(LED_BUILTIN, OUTPUT);
  initJoyStick();
}

void loop()
{
  //Handle PS2 communication and react to keyboard led change
  //This should be done at least once each 10ms
  unsigned char leds;
  unsigned char c;  //char stores data recieved from computer for KBD
  if (keyboard.available())
  {
    int reply = keyboard.read(&c);
    if (!reply)
      keyboard.keyboard_reply(c, &leds);
    // on resend
    if (c == 0xFE)
    {
      Serial.println("System RESEND");
      //messageByteSent = 0;
    } //end if
  } //end if

  if (messageByteSent)
  {
    moveBufferToNext();
    messageByteSent = 0;
  } // end if

  //handle buffer
  byte currentDataToSend;
  if (pullFromBuffer(&currentDataToSend))
  {
    messageByteSent = 1;
    keyboard.write(currentDataToSend);
  } // end if


  // process joystick
  processJoyStick();

}

void initJoyStick()
{
  byte counter = 10;
  unsigned long accumalteX = 0;
  unsigned long accumalteY = 0;
  for (int i = 0; i < counter; i++)
  {
    accumalteX += analogRead(JOYSTICK_X);
    delay(1);
    accumalteY += analogRead(JOYSTICK_Y);
    delay(1);
  }

  joyStickXCenter = int(accumalteX / counter);
  joyStickYCenter = int(accumalteY / counter);
  //Serial.println("joyStickXCenter - " + String(joyStickXCenter));
  //Serial.println("joyStickYCenter - " + String(joyStickYCenter));

  // set up buttons
  for (byte i = 0; i < NUMBUTTON; i++)
  {
    // reset variables
    buttonState[i] = HIGH;
    lastButtonState[i] = HIGH;
    lastDebounceTime[i] = 0;
  } //end for

  // press button
  pinMode(JOYSTICK_LB, INPUT);
  pinMode(JOYSTICK_RB, INPUT);
}



void processJoyStick()
{
  int reading = 1;
  int readJoyStickX = 0;

  switch (currentCheckedButton)
  {
    case BUT_RIGHT:

      readJoyStickX = analogRead(JOYSTICK_X);
      if (readJoyStickX > joyStickDebounceGap + joyStickXCenter)
        reading = 0;
      break;

    case BUT_LEFT:

      readJoyStickX = analogRead(JOYSTICK_X);
      if (readJoyStickX < joyStickXCenter - joyStickDebounceGap)
        reading = 0;
      break;
    case BUT_SPACE:
      // read the state of the switch into a local variable:
      reading = !(digitalRead(JOYSTICK_LB) | digitalRead(JOYSTICK_RB));
      break;
    default:
      Serial.println("WTF ???");
  }


  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState[currentCheckedButton]) {
    // reset the debouncing timer
    lastDebounceTime[currentCheckedButton] = millis();
  } //end if

  if ((millis() - lastDebounceTime[currentCheckedButton]) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState[currentCheckedButton]) {
      buttonState[currentCheckedButton] = reading; //match

      // flag and buffer
      switch (currentCheckedButton)
      {
        case BUT_RIGHT:
          //Serial.println("BR");
          insertToBuffer(0xe0);
          if (buttonState[currentCheckedButton] == HIGH)
            insertToBuffer(0xf0);
          insertToBuffer(0x74);
          break;
        case BUT_LEFT:
          //Serial.println("BL");
          insertToBuffer(0xe0);
          if (buttonState[currentCheckedButton] == HIGH)
            insertToBuffer(0xf0);
          insertToBuffer(0x6B);
          break;
        case BUT_SPACE:
          //Serial.println("BS");
          if (buttonState[currentCheckedButton] == HIGH)
            insertToBuffer(0xf0);
          insertToBuffer(0x29);
          break;
      } //end switch
    } //end if
  } //end if

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState[currentCheckedButton] = reading;

  // move to next button for next loop
  currentCheckedButton = (currentCheckedButton + 1) % NUMBUTTON;

}

Credits

Tal O
20 projects • 55 followers
Maker @ heart

Comments