IMPORTANT, LAST CODE HAD BUGS IN IT!In PSButton:
return (~buttons & button > 0); -> return ((~buttons & button) > 0); Tested on:
Arduino Decimila (should work for any atmega168 or atmega 8 board if pinouts are the same!)
Arduino MEGA (VERY BUGGY! Needs to be looked at under oscilloscope)
On the mega when you click the analog buttons all buttons come trough clearly, except the fact select is always pressed. Select happens to be a signed bit if the button intiger ws signed, but it is unsigned :/
Code:#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <avr/io.h>
#define LED_PIN 13
#define DELAY(wait) digitalWrite(LED_PIN,LOW); delay(wait); digitalWrite(LED_PIN,HIGH);
/* These are AVR PORTB pins, +8 to convert to Arduino pins */
#if defined(__AVR_ATmega1280__)
//PortB pin mapping on arduino Mega
#pragma message("Arduino Mega")
#define PS2clk 7 //13
#define PS2cmd 5 //11
#define PS2att 4 //10
#define PS2dat 6 //12
#else
#pragma message("Arduino")
//PortB mapping on arduino168/8 bassed boards
#define PS2clk 5 //13
#define PS2cmd 3 //11
#define PS2att 2 //10
#define PS2dat 4 //12
#endif
#define PS2PORT PORTB
#define PS2IN PINB
#define PS2DDR DDRB
#define CTRL_CLK 20
#define CTRL_BYTE_DELAY 20
//These are our button constants
#define PSB_SELECT 0x0001
#define PSB_L3 0x0002
#define PSB_R3 0x0004
#define PSB_START 0x0008
#define PSB_PAD_UP 0x0010
#define PSB_PAD_RIGHT 0x0020
#define PSB_PAD_DOWN 0x0040
#define PSB_PAD_LEFT 0x0080
#define PSB_L2 0x0100
#define PSB_R2 0x0200
#define PSB_L1 0x0400
#define PSB_R1 0x0800
#define PSB_GREEN 0x1000
#define PSB_RED 0x2000
#define PSB_BLUE 0x4000
#define PSB_PINK 0x8000
#define SET(x,y) (x|=(1<<y))
#define CLR(x,y) (x&=(~(1<<y)))
#define CHK(x,y) (x & (1<<y))
#define TOG(x,y) (x^=(1<<y))
boolean PSButton(uint16_t button);
unsigned char PS2data[9];
void read_gamepad();
void config_gampad();
unsigned char get_gamepad_mode();
unsigned char i;
void setup() {
Serial.begin(57600);
pinMode(LED_PIN,OUTPUT);
digitalWrite(LED_PIN,HIGH);
//similar to pinmod(pin,OUTPUT)
//Setting up the pin to be output
SET(PS2DDR,PS2clk);
SET(PS2DDR,PS2att);
SET(PS2DDR,PS2cmd);
//Sets pin to Input mode
CLR(PS2DDR,PS2dat);
SET(PS2PORT,PS2dat);
config_gampad();
}
void loop () {
read_gamepad();
if(PSButton(PSB_SELECT))
Serial.print("Select\n");
if(PSButton(PSB_L3))
Serial.print("L3\n");
if(PSButton(PSB_R3))
Serial.print("R3\n");
if(PSButton(PSB_START))
Serial.print("Start\n");
if(PSButton(PSB_PAD_UP))
Serial.print("Up\n");
if(PSButton(PSB_PAD_RIGHT))
Serial.print("Right\n");
if(PSButton(PSB_PAD_LEFT))
Serial.print("LEFT\n");
if(PSButton(PSB_PAD_DOWN))
Serial.print("DOWN\n");
if(PSButton(PSB_L1))
Serial.print("L1\n");
if(PSButton(PSB_R1))
Serial.print("R1\n");
if(PSButton(PSB_L2))
Serial.print("L2\n");
if(PSButton(PSB_R2))
Serial.print("R2\n");
if(PSButton(PSB_GREEN))
Serial.print("Triangle\n");
if(PSButton(PSB_RED))
Serial.print("Circle\n");
if(PSButton(PSB_PINK))
Serial.print("Square\n");
if(PSButton(PSB_BLUE))
Serial.print("X\n");
}
boolean PSButton(uint16_t button) {
uint16_t buttons = *(uint16_t*)(PS2data+3);
return ((~buttons & button) > 0);
}
unsigned char _gamepad_shiftinout (char byte) {
unsigned char tmp = 0;
for(i=0;i<8;i++) {
if(CHK(byte,i)) SET(PS2PORT,PS2cmd);
else CLR(PS2PORT,PS2cmd);
CLR(PS2PORT,PS2clk);
delayMicroseconds(CTRL_CLK);
if(CHK(PS2IN,PS2dat)) SET(tmp,i);
SET(PS2PORT,PS2clk);
}
SET(PS2PORT,PS2cmd);
delayMicroseconds(CTRL_BYTE_DELAY);
return tmp;
}
void _gamepad_shiftout (char byte) {
for(i=0;i<8;i++) {
if(CHK(byte,i)) SET(PS2PORT,PS2cmd);
else CLR(PS2PORT,PS2cmd);
CLR(PS2PORT,PS2clk);
delayMicroseconds(CTRL_CLK);
SET(PS2PORT,PS2clk);
//delayMicroseconds(CTRL_CLK);
}
SET(PS2PORT,PS2cmd);
delayMicroseconds(CTRL_BYTE_DELAY);
}
unsigned char _gamepad_shiftin() {
unsigned char tmp = 0;
for(i=0;i<8;i++) {
CLR(PS2PORT,PS2cmd);
CLR(PS2PORT,PS2clk);
delayMicroseconds(CTRL_CLK);
if(CHK(PS2IN,PS2dat)) SET(tmp,i);
SET(PS2PORT,PS2clk);
delayMicroseconds(CTRL_CLK);
}
SET(PS2PORT,PS2cmd);
delayMicroseconds(CTRL_BYTE_DELAY);
return tmp;
}
void read_gamepad() {
SET(PS2PORT,PS2cmd);
SET(PS2PORT,PS2clk);
CLR(PS2PORT,PS2att); // low enable joystick
delayMicroseconds(CTRL_BYTE_DELAY);
//Send the command to send button and joystick data;
char dword[9] = {0x01,0x42,0,0,0,0,0,0,0};
for (int i = 0; i<9; i++) {
PS2data[i] = _gamepad_shiftinout(dword[i]);
}
SET(PS2PORT,PS2att); // HI disable joystick
}
unsigned char get_gamepad_mode() {
SET(PS2PORT,PS2cmd);
SET(PS2PORT,PS2clk);
CLR(PS2PORT,PS2att); // low enable joystick
_gamepad_shiftout(0x01);
unsigned char x = _gamepad_shiftin();
SET(PS2PORT,PS2att); // HI disable joystick
return x;
}
void config_gampad() {
SET(PS2PORT,PS2cmd);
SET(PS2PORT,PS2clk);
CLR(PS2PORT,PS2att); // low enable joystick
_gamepad_shiftout(0x01);
_gamepad_shiftout(0x43);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x01);
_gamepad_shiftout(0x00);
// Lock to Analog Mode on Stick
_gamepad_shiftout(0x01);
_gamepad_shiftout(0x44);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x01);
_gamepad_shiftout(0x03);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x00);
// Vibration
/*
_gamepad_shiftout(0x01);
_gamepad_shiftout(0x4D);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x01);
*/
_gamepad_shiftout(0x01);
_gamepad_shiftout(0x4F);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0xFF);
_gamepad_shiftout(0xFF);
_gamepad_shiftout(0x03);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x01);
_gamepad_shiftout(0x43);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x00);
_gamepad_shiftout(0x5A);
_gamepad_shiftout(0x5A);
_gamepad_shiftout(0x5A);
_gamepad_shiftout(0x5A);
_gamepad_shiftout(0x5A);
SET(PS2PORT,PS2att);
}