Introduction: Interfacing PS2 Controller With AVR -Bit Bang
Hey friends in this instructable I will show you how to interface sony PS2 controller with AVR microcontroller .This will be your handy code which you can be used in future to control robots .You can get analogue value from joystick which can be used to control the speed of motor .
I have explained the code with help of 3 section
1)what is SPI ?
2)PS2 protocol
3)Finally the code
I have written the code for atmega640 in BIT BANGbut anyone who as worked with AVR can easily write a code for any series atmega microcontroller.You can also check 'Interfacing PS2 with AVR -SPI ' in which i have used internal SPI of AVR.
Let's get started!
Step 1: Material and Software Required
Materials required
1)sony PS2 controller
2)Atmega640
3)AVRISP programmer(or any other programmer depending upon your microcontroller )
4)one to one connector
software
1)Winavr(or any AVR compiler)
2)progISP
and of course you should have basic knowledge of AVR programming and embedded C.
Step 2: Understanding SPI
what is SPI ?
(you can skip this step if u know SPI communication )
Serial Peripheral Interface Bus or SPI bus is a synchronous serial data link de facto standard, that operates in full duplex mode. Devices communicate in master/slave mode where the master device initiates the data frame. Multiple slave devices are allowed with individual slave select (chip select) lines. Sometimes SPI is called a four-wire serial bus, contrasting with three-, two-, and one-wire serial buses. SPI is often referred to as SSI (Synchronous Serial Interface).
In SPI there are 6 connection
MOSI-master out slave in
MISO-master in slave out
SCK-clock is provided by master to slave by this pin
SS-slave select ,master selects a slave by this pin
VCC-voltage pin
GND -ground
Both master and slave have shift register when master provides 8 clocks the content of each register is interchanged and data is transferred from master to slave and vice versa thus a full duplex communication .
so what is BIT BANG ?
Bit banging is a technique for serial communications using software instead of dedicated hardware. Software directly sets and samples the state of pins on the microcontroller, and is responsible for all parameters of the signal: timing, levels, synchronization, etc. In contrast to bit banging, dedicated hardware (such as a modem, UART, or SPI) handles these parameters and provides a (buffered) data interface in other systems, so software is not required to perform signal demodulation. Bit banging can be implemented at very low cost, and is used in, for example, embedded systems.
In this instructable I am using bit bang technique instead of using AVR's SPI hardware .This code will work fine for many of our task .
you can refer this
1)http://avrbeginners.net/architecture/spi/spi.html
2)http://www.embedded.com/electronics-blogs/beginner-s-corner/4023908/Introduction-to-Serial-Peripheral-Interface
site to understand SPI further
Step 3: PS2 Protocol
This http://store.curiousinventor.com/guides/PS2/ best site to understand PS2 protocol.
Byte Sequence to Configure Controller for Analog Mode
-- 0x43 Go into configuration mode
byte # 1 2 3 4 5
Command (hex) 01 43 00 0x01 00
Data (hex) FF 41 5A FF FF
section header digital
-- 0x44 Turn on analog mode
byte # 1 2 3 4 5 6 7 8 9
Command (hex) 01 44 00 0x01 0x03 00 00 00 00
Data (hex) FF F3 5A 00 00 00 00 00 00
section header config parameters
-- 0x43 Exit config mode
byte # 1 2 3 4 5 6 7 8 9
Command (hex) 01 43 00 0x00 5A 5A 5A 5A 5A
Data (hex) FF F3 5A 00 00 00 00 00 00
section header config parameters
Step 4: Hardware Setup
Setting a hardware is very easy you have to connect only 6 pins given below.you can use one to one connectors to connect PS2 side with board.Remove the plastic cover of one to one wire and make the gap bigger to fit in PS2 connector and then insulate the cnnector
-------------LOOKING AT THE PLUG-------------------
-------------------------------
PIN 1-> | o o o | o o o | o o o |
\___________________/
PIN # USAGE
1 DATA -PORTB3
2 COMMAND -PORTB2
3 N/C (9 Volts unused)
4 GND -GND pin
5 VCC -VCC pin
6 ATT -PORTB1
7 CLOCK -PORTB0
8 N/C
9 ACK
you can connect wire as shown in picture above.I have made adapter to connect PS2 controller with the board
Step 5: Explaning the Code
if u have understood the flowchart this will be quite easy
The code has only 2 function
1) int gameByte(short int command)
2) void int_PS2inanalougemode()
int gameByte(short int command)
{
short int i ; // variable used as counter
_delay_us(1);
short int data = 0x00; // clear data variable to save setting low bits later.
for(i=0;i<8;i++) // as 8 bytes are transferred i<8
{
if(command & _BV(i)) //each bit of command is ANDED with 1 one by one, thus value of that cmnd is if in condition
{
sbi(PORTB, PScommand); // if command is one command pin is set
}
else
{
cbi(PORTB, PScommand); // else command pin is made zero
}
cbi(PORTB, PSclock); // CLOCK LOW
_delay_us(1); // wait for output to stabilise
if((PINB & _BV(PSdata)))
{
sbi(data, i); // read PSdata pin and store
}
else
{
cbi(data, i);
}
sbi(PORTB, PSclock); // CLOCK HIGH
}
sbi(PORTB, PScommand);
_delay_us(20); // wait for ACK to pass.
return(data);
}
void int_PS2inanalougemode()-
this function puts the controller in analogue mode until it returns value 0x73 in 2nd byte which indicates that PS2 controller is in analogue mode if it doesn't return its increments the counter and continues to put PS2 controller is in analogue mode
int main(void)
in main loop we simply poll the input of PS2 controller .
video
complete code is here
Attachments

Participated in the
Microcontroller Contest
12 Comments
5 years ago
does this work with the wireless ps2 controller also?
6 years ago on Introduction
Hi this is my code...
Can you please review it and just let me know what I am doing wrong
In this code initially what I have done is seen if pressing the buttons are giving me high logic on the specified pins
What's happening is that I am not able to come out of the loop in which he is checking for configuration and analog mode..
Reply 6 years ago on Introduction
does the red LED on the PS2 controller goes on?
if yes it means PS2 is going in analog mode but it is unable to tell the microcontroller
if no then PS2 contoller is not going in analog mode and you need to check the connection
Reply 6 years ago on Introduction
hi
the red light stays on for the whole duration but clicking any other does not give me any output in output port
that means ps2 is not able to send 0x73 to microcontroller
what should i do?
Reply 6 years ago on Introduction
red led goes on when just given vcc and ground
when given 5v with code it switch on's and when again clicked its goes off
but when i connect all the pins the pressing of buttons is not giving me high pins in my output port(portA)
is anything wrong with my code ??
Reply 6 years ago on Introduction
try out this code its for atmega640 the value from joystick is displayed on portK you can use any port just declare it output first
AS this code is working it should work
if not probably then there will be some connection problem ,solve it and then you could build your code upon this
/*
BIT BANG PS2 for atmega640 -connection according to SPI
-------------LOOKING AT THE PLUG-------------------
-------------------------------
PIN 1->| o o o | o o o | o o o |
\_____________________________/
PIN # USAGE
1 DATA
2 COMMAND
3 N/C (9 Volts unused)
4 GND
5 VCC
6 ATT
7 CLOCK
8 N/C
9 ACK
----NOTES--
*> 0x5A(by controller) to say "here comes the data".
*> bite 1. header. (should possibly put test on this byte to detect unplugging of controller.)
ie if (temp==0x73)
*/
#ifndef F_CPU
#define F_CPU 14745600UL // or whatever may be your frequency
#endif
#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>
#define PSdata 3 // PB3
#define PScommand 2 // PB5
#define PSclock 1 // PB2
#define PSattention 0 // PB6
#define sbi(x,y) x|=(1<<y)
#define cbi(x,y) x&=~(1<<y)
//#define _BV(y) (1<<y)
// PSx controller communication function.
// send a byte on the command line and receive one on the data line.
// needs Attention pin to have gone low before called to activate controller.
int sendTo_slave(short int command)
{
short int i ;
_delay_us(1);
short int data = 0x00; // clear data variable to save setting low bits later.
for(i=0;i<8;i++)
{
if(command & _BV(i))
{
sbi(PORTB, PScommand); // bit bang "command" out on PScommand wire.
}
else
{
cbi(PORTB, PScommand);
}
cbi(PORTB, PSclock); // CLOCK LOW
_delay_us(1); // wait for output to stabilise
if((PINB & _BV(PSdata)))
{
sbi(data, i); // read PSdata pin and store
}
else
{
cbi(data, i);
}
sbi(PORTB, PSclock); // CLOCK HIGH
}
sbi(PORTB, PScommand);
_delay_us(20); // wait for ACK to pass.
return(data);
}
void int_PS2inanalougemode()
{
// this loop continues to put PSx controller into analouge mode untill the
// controller responds with 0x73 in the 2nd byte.
// (PS2 controller responds with 0x73 when in analouge mode.)
// the status LEDs will continue to count upwards untill a controller is found.
// if everything is working correctly this should happen on the first pass of
// this loop but occasionally errors occur and a 2nd or 3rd itteration happen.
unsigned char chk_ana = 0, cnt = 0;
while(chk_ana != 0x73)
{
// put controller in config mode
sbi(PORTB, PScommand);
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
sendTo_slave(0x01);
sendTo_slave(0x43);
sendTo_slave(0x00);
sendTo_slave(0x01);
sendTo_slave(0x00);
sbi(PORTB, PScommand);
_delay_ms(1);
sbi(PORTB, PSattention);
_delay_ms(10);
// put controller in analouge mode
sbi(PORTB, PScommand);
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
sendTo_slave(0x01);
sendTo_slave(0x44);
sendTo_slave(0x00);
sendTo_slave(0x01);
sendTo_slave(0x03);
sendTo_slave(0x00);
sendTo_slave(0x00);
sendTo_slave(0x00);
sendTo_slave(0x00);
sbi(PORTB, PScommand);
_delay_ms(1);
sbi(PORTB, PSattention);
_delay_ms(10);
// exit config mode
sbi(PORTB, PScommand);
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
sendTo_slave(0x01);
sendTo_slave(0x43);
sendTo_slave(0x00);
sendTo_slave(0x00);
sendTo_slave(0x5A);
sendTo_slave(0x5A);
sendTo_slave(0x5A);
sendTo_slave(0x5A);
sendTo_slave(0x5A);
sbi(PORTB, PScommand);
_delay_ms(1);
sbi(PORTB, PSattention);
_delay_ms(10);
// poll controller and check in analouge mode.
sbi(PORTB, PScommand);
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
sendTo_slave(0x01);
chk_ana = sendTo_slave(0x42); // the 2nd byte to be returned from the controller should = 0x73 for "red" analouge controller.
sendTo_slave(0x00);
sendTo_slave(0x00);
sendTo_slave(0x00);
sendTo_slave(0x00);
sendTo_slave(0x00);
sendTo_slave(0x00);
sendTo_slave(0x00);
sbi(PORTB, PScommand);
_delay_ms(1);
sbi(PORTB, PSattention);
_delay_ms(10);
// keep increasing counter to be dispalyed untill PSx controller confirms it's in analouge mode.
PORTK=cnt++;
if (cnt > 254){ cnt=0;}
}
}
int main(void)
{
DDRK=0XFF;
DDRH=0xFF;
// PSx controller I/O pin setup:
sbi(DDRB, PB1); // clock. output. (blue)
cbi(DDRB, PB3); // data. input. (brown)
sbi(PORTB, PB3); // enable pullup resistor
cbi(DDRB, PB4); // acknolage. input. (green)
sbi(PORTB, PB4); // enable pullup resistor
sbi(DDRB, PB2); // command. output. (orange)
sbi(DDRB, PB0); // attention. output. (yellow)
int_PS2inanalougemode();
unsigned char data0, data1, data2, data3, data4, data5,RV,RH,LV,LH,temp;
while(1)
{
sbi(PORTB, PScommand); // start communication with PSx controller
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
sendTo_slave(0x01); // bite 0. header.
temp = sendTo_slave(0x42); // bite 1. header. (should possibly put test on this byte to detect unplugging of controller.)
sendTo_slave(0x00); // bite 2. header.
data0 = sendTo_slave(0x00); // bite 3. first data bite.
data1 = sendTo_slave(0x00); // bite 4.
RH = sendTo_slave(0x00); // RH
RV = sendTo_slave(0x00); // RV UP-00 DOWN-255
LH = sendTo_slave(0x00); // LH lEFT-00 RIGHT-255
LV = sendTo_slave(0x00);
_delay_us(1);
sbi(PORTB, PScommand); // close communication with PSx controller
_delay_us(1);
sbi(PORTB, PSattention); // all done.
PORTK=LH;
}
}
ALL the best!
6 years ago on Step 3
hi i am trying to interface avr with ps2 controller and i am using atmega8535 for it
this might sound silly but since command line is used by ps2 to send to controller so why are we using those bytes in the code, if we are going to burn the code in microcontroller
and can we actually check those commands in code whether we have received them from ps2 and then act accordingly (as per defined under those conditions) like when i press R2 i want to writs the code to control motor inside that block . can it be used??
please do reply or please mail me at arunimachaurasia@gmail
Reply 6 years ago on Introduction
Hey ,Yeah you can program microcontroller to control motor on button press
can you please specify where are you facing problem.
so that i can help you out
Reply 6 years ago on Introduction
#include
#include
#define sbi(port,bit) (port) |= (1<<(bit))
#define cbi(port,bit) (port) &= ~(1<<(bit))
#ifdef F_CPU
#define F_CPU 16000000UL
#endif F_CPU
#define sei()
#include
#define wdt_enable(timeout)
#define wdt_reset()
#define PSclock 7 // PB7
#define PSdata 6 // PB6
#define PSacknolage 3 // PB3
#define PScommand 5 // PB5
#define PSattention 4 // PB4
#define VCC 1 //PB1
#define GND 0 //PB0
unsigned char gameByte(unsigned char command);
unsigned char gameByte(unsigned char command)
{
short int i ;
_delay_us(1);
short int data = 0x00; // clear data variable to save setting low bits later.
for(i=0;i<8;i++)
{
if(command & _BV(i)) sbi(PORTD, PScommand); // bit bang "command" out on PScommand wire.
else cbi(PORTD, PScommand);
cbi(PORTD, PSclock); // CLOCK LOW
_delay_us(1); // wait for output to stabilise
if((PIND & _BV(PSdata))) sbi(data, i); // read PSdata pin and store
else cbi(data, i);
sbi(PORTD, PSclock); // CLOCK HIGH
}
sbi(PORTD, PScommand);
_delay_us(20); // wait for ACK to pass.
return(data);
}
// put 1 byte on the 8 LEDs. obviously you need to change the output pins to
// match your board.
int main(void)
{
sbi(DDRB,PB1);
sbi(PORTB, PB1);
sbi(DDRB,PB0);
cbi(PORTB,PB0);
//_delay_ms(10);
// set the baud rate of the UART
// (needed for transmitting over radio module).
//uartSetUp(2400);
// PSx controller I/O pin setup:
sbi(DDRB, PB7); // clock. output. (blue)
cbi(DDRB, PB6); // data. input. (brown)
sbi(PORTB, PB6); // enable pullup resistor
cbi(DDRB, PB3); // acknolage. input. (green)
sbi(PORTB, PB3); // enable pullup resistor
sbi(DDRB, PB5); // command. output. (orange)
sbi(DDRB, PB4); // attention. output. (yellow)
// enable interupts
sei();
// watchdog timer reset and enable
//wdt_reset();
//wdt_enable(0x02);
//timerInit();
// this loop continues to put PSx controller into analouge mode untill the
// controller responds with 0x73 in the 2nd byte.
// (PS2 controller responds with 0x73 when in analouge mode.)
// the status LEDs will continue to count upwards untill a controller is found.
// if everything is working correctly this should happen on the first pass of
// this loop but occasionally errors occur and a 2nd or 3rd itteration happen.
unsigned char chk_ana = 0;
while(chk_ana != 0x73){
// put controller in config mode
sbi(PORTB, PScommand);
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
gameByte(0x01); //POLL ONCE JUST FOR ONCE
gameByte(0x42);
gameByte(0x00);
gameByte(0xFF);
gameByte(0xFF);
gameByte(0x01);
gameByte(0x43);
gameByte(0x00);
gameByte(0x01);
gameByte(0x00);
sbi(PORTB, PScommand);
_delay_ms(1);
sbi(PORTB, PSattention);
_delay_ms(1);
// put controller in analouge mode
sbi(PORTB, PScommand);
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
gameByte(0x01);
gameByte(0x44);
gameByte(0x00);
gameByte(0x01);
gameByte(0x03);
gameByte(0x00);
gameByte(0x00);
gameByte(0x00);
gameByte(0x00);
sbi(PORTB, PScommand);
_delay_ms(1);
sbi(PORTB, PSattention);
_delay_ms(1);
//TO CONFIGURE TO RETURN PRESSURE VALUES
sbi(PORTB, PScommand);
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
gameByte(0x01);
gameByte(0x4F);
gameByte(0x00);
gameByte(0xFF);
gameByte(0xFF);
gameByte(0x03);
gameByte(0x00);
gameByte(0x00);
gameByte(0x00);
sbi(PORTB, PScommand);
_delay_ms(1);
sbi(PORTB, PSattention);
// exit config mode
sbi(PORTB, PScommand);
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
gameByte(0x01);
gameByte(0x43);
gameByte(0x00);
gameByte(0x00);
gameByte(0x5A);
gameByte(0x5A);
gameByte(0x5A);
gameByte(0x5A);
gameByte(0x5A);
sbi(PORTB, PScommand);
_delay_ms(1);
sbi(PORTB, PSattention);
//_delay_ms(10);
// poll controller and check in analouge mode.
sbi(PORTB, PScommand);
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
gameByte(0x01);
chk_ana = gameByte(0x42); // the 2nd byte to be returned from the controller should = 0x73 for "red" analouge controller.
gameByte(0x00);
gameByte(0x00);
gameByte(0x00);
gameByte(0x00);
gameByte(0x00);
gameByte(0x00);
gameByte(0x00);
sbi(PORTB, PScommand);
_delay_ms(1);
sbi(PORTB, PSattention);
//_delay_ms(10);
sbi(DDRC ,PC1);
cbi(PORTC ,PC1);
_delay_ms(10);
}
sbi(DDRC ,PC1);
sbi(PORTC ,PC1);
_delay_ms(10);
while(chk_ana==0x73)
{
short int temp, data0, data1, data2=0,data3=0; // data4, data5,data6,data7,data8,data9,data10,
short int i=0 ;
while (1){
sbi(PORTB, PScommand); // start communication with PSx controller
sbi(PORTB, PSclock);
cbi(PORTB, PSattention);
gameByte(0x01); // bite 0. header.
temp = gameByte(0x42); // bite 1. header. (should possibly put test on this byte to detect unplugging of controller.)
gameByte(0x00); // bite 2. header.
data0 = gameByte(0x00); // bite 3. first data bite.
data1 = gameByte(0x00); // bite 4.
data2 = gameByte(0x00); // bite 5.
data3 = gameByte(0x00); // bite 6.
//data4 = gameByte(0x00); // bite 7.
//data5 = gameByte(0x00); // bite 8.
//data6 = gameByte(0x00);
//data7 = gameByte(0x00);
//data8 = gameByte(0x00);
//data9 = gameByte(0x00);
//data10 = gameByte(0x00);
if(data0==0xFE) //SELECT
{
sbi(DDRA, PA1);
sbi(PORTA, PA1);
_delay_ms(1);
}
else if(data0==0x7F) //LEFT ARROW
{
sbi(DDRA, PA2);
sbi(PORTA, PA2);
_delay_ms(1);
}
else if(data0==0xBF) //DOWNWARDS
{
sbi(DDRA, PA3);
sbi(PORTA, PA3);
_delay_ms(1);
}
else if(data0==0xDF) //RIGHT ARROW
{
sbi(DDRA, PA3);
sbi(PORTA, PA3);
_delay_ms(1);
}
else if(data0==0xEF) //UPWARDS
{
sbi(DDRA, PA1);
sbi(PORTA, PA4);
_delay_ms(1);
}
else if(data2==0x7F)
{
//RIGHT X-AXIS JOYSTICK
sbi(DDRA ,PA5);
sbi(PORTA, PA5);
_delay_ms(1);
}
else //NOTHING IS PRESSED
{
sbi(DDRA, PA6);
sbi(PORTA, PA6);
_delay_ms(1);
}
_delay_us(10);
sbi(PORTB, PScommand); // close communication with PSx controller
_delay_ms(1);
sbi(PORTB, PSattention); // all done.
};
};
}
7 years ago on Introduction
Hi
My controller can't make a connection. Controller is wireless and leds only blink Maybe you know why? How to make proper delays? Or maybe it is something else?
8 years ago on Step 4
Hi, please update your pin connection as
per following pin connection, your code works for digital pad but for
analog mode my receiver's link led blinks.please help in analog mode.
PIN # USAGE
1 DATA -PORTB3
2 COMMAND -PORTB2
3 N/C (9 Volts unused)
4 GND -GND pin
5 VCC -VCC pin
6 ATT -PORTB0
7 CLOCK -PORTB1
8 N/C
9 ACK-PORTB4
Reply 8 years ago on Introduction
friend I tested the code and it works for both analog and digital mode.give it a try and let me know
all the best