Uwaga! Ta strona wysyła Ci "ciasteczko".
Użytkowników online:
3
Artykuły>Mikrokontrolery i PLD>Kurs AVR-GCC Gamepad od PlayStation
printer_icon

Kurs AVR-GCC. Gamepad od Sony PlayStation

16.10.11 ABXYZ

Zwykle na płytkach startowych przeznaczonych do nauki programowania mikrokontrolerów wlutowuje się kilka miniaturowych przycisków. Spotyka się również płytki z klawiaturą zrobioną z przycisków wlutowanych w kilu rzędach . Jest to wygodne, bo można uruchamiać proste programy. Jednak obsługa w programie wielu przycisków okazuje się nieco uciążliwa, a dodatkowo występuje problem drgań styków przycisków. Zamiast walczyć z przyciskami polecam przyłączyć do płytki gamepad od konsoli Sony PlayStation2, w ten sposób temat przycisków zostanie prosto i elegancko rozwiązany.

Na fotografii poniżej wydać gamepad do PS2, który kosztował tylko kilkanaście zł. Nie jest to oryginalny pad PlayStation, ale za to ma "bajerancką" obudowę z przezroczystego tworzywa i jest podświetlany niebieskimi diodami LED. Jest to tzw. "analogowy" pad, bo w odróżnieniu od wcześniejszych modeli ("cyfrowych"), posiada obok przycisków dodatkowo dwa analogowe dżojstiki. Co ciekawe, z analogowego pada odczytywać można nie tylko które przyciski są wciśnięte, ale także siłę nacisku na przyciski. Pad wyposażony został również w silniki z niesymetrycznymi ciężarkami na osi do generowania wibracji -można sterować prędkością silnika. A to jeszcze nie wszystko, bo są dostępne wersję bezprzewodowe pada dla playstation2, które kosztują niewiele więcej niż modele z kablem.

obrazek
Fot. 1. Gamepad do konsoli playstation 2 . Do wykorzystania 14 przycisków z możliwością odczytu siły nacisku, dwa dżojstiki analogowe, dwa silniki do generowania wibracji.

Playstation komunikuje się padem magistralą szeregową, my możemy przyłączyć pada do sprzętowego interfejsu SPI AVRa atmega. Wtyk na końcu przewodu pada ma dziewięć wyprowadzeń:

obrazek
Rys. 1. Wtyk złącza gamepada playstation
PinOznaczenie i kolor przewoduOpis
1DATATą linią kontroler przesyła dane do playstation
2CMDLinią plastation przesyła komendy do kontrolera
8MPWRZasilanie silników generujących wibracje pada 7-9V
4GNDMasa
5VCCZasilanie 3.3-5V
6ATTNiskim stanem niskim na tej linii playstation sygnalizuje rozpoczęcie transmisji
7CLKSygnał zegara, taktujący dane na liniach DATA i CMD, generowany przez playstation
8NC.Nie podłączony
9ACKPad potwierdza odbiór jednego bajtu danych ustawiając tę linię w stan niski
Tab. 1. Opis wyprowadzeń złącza gamepada playstation

Konsola playstation rozpoczyna komunikację z padem ustawiając stan niski na linii ATT . Transmisja danych odbywa się jednocześnie w dwóch kierunkach. Linią CMD playstation przesyła komendy do pada, a w tym samym czasie linią DATA gamepad przesyła do playstation informacje o stanie przycisków, dżojstików oraz inne dodatkowe informacje. Na linii CLK playstation generuje sygnał zegara taktujący dane na obu liniach danych CMD i DATA. Normalnym stanem początkowym sygnału zegara to stan wysoki. Próbkowanie linii danych (CMD i DATA) następuje po narastającym zboczu sygnału CLK. Dodatkowo gamepad potwierdza odebranie kolejnych bajtów danych ustawieniem linii ACK w stan niski( z wyjątkiem ostatniego bajtu). Bity w bajcie przesyłane są w kolejności od najmłodszego do najstarszego.

Poniżej wkleiłem funkcję "pad_byte", która wysyła/odbiera jeden bajt z/do gamepada.


unsigned char pad_byte(unsigned char byte)
{
   unsigned char i,r=0;

   for(i=0; i<8; i++, byte>>=1)
   {
       CLK_CLR;
       if(byte & 0x01) CMD_SET; else CMD_CLR;
       CLK_SET;
       r>>=1;
       if(DATA_IN) r|=0x80;
   }
   CMD_SET;
   _delay_us(20);
   return r;   
}
Listing 1. Funkcja wysyłająca/odbierająca jeden bajt do/z gamepada

Możemy również przyłączyć pad poprzez sprzętowy interfejs SPI AVRa, poniżej mamy drugą wersję funkcji "pad_byte", która właśnie wykorzystuje sprzętowy SPI mikrokontrolera atmega.

// Konfiguracja SPI AVRa  
SPCR =(1<<SPE)|(1<<MSTR)  // Włącza SPI AVRa w trybie MASTER
  |(1<<DORD) // LSB wysyłany pierwszy
  |(1<<CPOL) // SCK normalnie w stanie wysokim 
  |(1<<CPHA) // Próbkowanie  po wznoszącym zboczu SCK 
  |(1<<SPR0)|(1<<SPR1); // Częstotliwość sygnału SCK fosc/128

// Wysyła jeden bajt poprzez SPI 
unsigned char pad_byte(unsigned char byte)
{
    SPDR = byte;
    while(!(SPSR & (1<<SPIF)));
 
    _delay_us(20);
    return SPDR; 
}
Listing 2. Funkcja wysyłająca/odbierająca jeden bajt do/z gamepada, korzystając ze sprzętowego interfejsu SPI mikrokontrolera atmega

Gamepad potwierdza odbiór bajtu danych ustawiając na chwilkę linię ACK w stan niski, lecz w zamieszczonych tutaj przykładach nie będzie to wykorzystywane, linię ACK pozostawiłem niepodłączoną.

Rozmowa mikrokontrolera z gamepadem odbywa się w następujący sposób: Najpierw mikrokontroler ustawia linię ATT w stan niski, co aktywuje interfejs gamepada. Dalej, wywołując wielokrotnie funkcję "pad_byte", mikrokontroler wysyła do gamepada ciąg bajtów zawierający zakodowaną komendę wraz z parametrami. Jednocześnie wywoływana wielokrotnie funkcja "pad_byte" zwraca ciąg bajtów odczytany z gamepada, który zawiera informację o stanie przycisków, dżojstików itd.

Przykładowo, żeby odczytać stan przycisków gamepada i stopień wychylenia drążka dżojstików analogowych wyślemy do gamepada dziewięć bajtów zawierających komendę: 0x42-"Controller poll", jak w tablicy poniżej.

Nr Bajt wysłany Bajt odebrany
1 0x01 0x0xff
2 0x42 0x73
3 0x00 0x5A
4 0x00 dane
5 0x00 dane
6 0x00 dane
7 0x00 dane
8 0x00 dane
9 0x00 dane
Tab. 2. Ciąg bajtów wysyłanych/odebranych do/z gamepada. Wysyłany bajt 0x42 to kod komendy "Controller poll"

Odczytane z gamepada bajty numer 4 i 5 zawierają informacje o stanie przycisków, wartość bitu 0 oznacza, że przycisk jest wciśnięty; a bajty numer 6..9 zawierają informację o stopniu wychylenia gałek dżojstików analogowych.

Bit 0 Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7
Bajt nr 4 SELECT JOYR JOYL START UP RIGHT DOWN LEFT
Bajt nr 5 L2 R2 L1 R1 trójkąt kółko krzyżyk kwadrat
Bajt nr 6 dżojstik prawy, wychylenie w kierunku lewo-prawo, 0x00 - max. w lewo, 0xff-max. w prawo
Bajt nr 7 dżojstik prawy, wychylenie w kierunku góra-dół, 0x00 - max. w górę, 0xff-max. w dół
Bajt nr 8 dżojstik lewy, wychylenie w kierunku lewo-prawo, 0x00 - max. w lewo, 0xff-max. w prawo
Bajt nr 9 dżojstik lewy, wychylenie w kierunku góra-dół, 0x00 - max. w górę, 0xff-max. w dół
Tab. 3. Odczytane z gamepada bajty numer 4 i 5 zawierają informacje o stanie przycisków; bajty numer 6..9 zawierają informację o stopniu wychylenia gałek dżojstików analogowych.

Przykładowy programik

Przykładowy program był testowany na mikrokontrolerze atmega8 z częstotliwością pracy 8MHz. Obok gamepada ps2, dołączyłem do portów we/wy AVRa osiem diod LED i cztery przełączniki. Z użyciem przełączników wybieramy numer bajtu (0-8) odczytanego z pada, którego wartość ma być pokazany na ośmiu diodach LED.

obrazek
Schemat 1. Obok gamepada ps2, dołączyłem do portów we/wy AVRa osiem diod LED i cztery przełączniki. Z użyciem przełączników wybieramy numer bajtu (0-8) odczytanego z pada, którego wartość ma być pokazany na ośmiu diodach LED.

Program przeznaczony jest dla uC ATMEGA taktowanego zegarem 8MHz, jeśli mikrokontroler ma pracować z  większą częstotliwością, to program może wymagać drobnego dopasowania.

Katalog z plikami źródłowymi projektu można pobrać klikając w link ps2_pad.zip.

Jeśli nie wiesz jak skompilować i uruchomić przykład, to polecam artykuł "Szybki start z WinAVR"

Na zakończenie podpowiem, że aby odczytać z gamepada informacje o sile nacisku na przyciski i mieć możliwość sterowania silnikami wibracji, potrzeba wcześniej te funkcje aktywować, wysyłając do pada odpowiednie komendy konfiguracyjne. Listę komend kontrolera playstation2 można znaleźć w dokumencie: Playstation 2 controller protocol notes

16.10.11 ABXYZ
legenda

Komentarze (23)

dikej03
18.02.2016 (17:01)
gość
Testowane na atmega-8A, wybór numeru bajtu za pomocą przełączników niestety nie działa, natomiast jako taka komunikacja z padem działa poprawnie. Swoją drogą dobra robota i genialna strona. Początkującemu bardzo trudno zacząć, dzięki tym i pozostałym kursom powoli sam ogarniam coraz więcej i uczę się jak tworzyć własne projekty.
mmmmm
13.03.2015 (16:51)
gość
Podpinam się pod pytanie mojego poprzednika i chciałbym dopytać jeszcze czy mogę sygnał clk wziąć z innej nóżki procka np. z wyjść timera ustawionego na f=250kHz a nie z nóżki clk wyjść SPI. Z góry dzięki za odpowiedź
gość
11.03.2015 (11:09)
gość
Jaka jest maksymalna wartość zegara dla SPI w przypadku pada? Przy kwarcu 16 Mhz i podziale przez 128 nie mogę nawiązać połączenia. Zmieniając fusy tak, że dzielę F_CPU przez 8 wszystko działa. Istneije możliwość ustawienia większego dzielnika zegara SPI, czy zostaje mi tylko zmiana kwarcu?
marek
10.11.2014 (10:35)
gość
Dzięki. Też nie mogłem znaleźć samego gniazda. Zapewne tak zrobię.
abxyz
07.11.2014 (20:15)
autor strony
Szukałem dłuższą chwilkę w internecie, ale niestety nie znalazłem nazwy tego typu złącza. Nowego gniazda raczej nie kupisz w najbliższym sklepie z częściami elektronicznymi. Ja bym odciął oryginalny wtyk kontrolera i zastąpił jakimkolwiek innym. Ewentualnie można gniazdo wylutować ze starej, popsutej konsoli. Wyprodukowano tego miliony sztuk, więc znalezienie takiego śmiecia nie powinno być trudne.
marek
07.11.2014 (10:10)
gość
Czy wtyczka od pada ma jakąś nazwę? Chciałbym znaleźć gotowe gniazdo do wlutowania w płytkę.
kozuna
19.10.2014 (18:44)
użytkownik
Witam!
Wrzuciłem program do mikrokontrolera atmega 8 taktowany na 8mhz, połączyłem jak na schemacie z taka różnicą ze podciagajacy rezystor z DATA dałem 3,3k do kompilacji używam Eclipse z winavr, rezultat jest tak ze tylko dla PC3=gnd pala sie wszystkie diody ( zapalane sa w moim przypadku stanem niskim) a w każdym innym przypadku nie pala się w ogole bez zwgledu na stan wychylenia drazkow czy stan przycisku na padzie. Uzywam oryginalnego pada, zaczynam dopero programowac w c, co moge robic zle?
abxyz
15.06.2014 (21:00)
autor strony
W naszym przypadku w ogóle nie ma potrzeby przejmować się ekranowaniem kabla kontrolera.
kozaczi
15.06.2014 (16:34)
użytkownik
Czy ekran połączyć z gnd sygnałowym?
abxyz
31.08.2013 (18:32)
autor strony
Hmm... Rozdzielczość 8-bitów dla joystika powinna wystarczyć
Co można zrobić
1. Ćwiczyć sprawność - ćwiczenia czynią mistrza :)
2. Programowo tłumić zbyt gwałtowne ruchy joystika
3. Poszukać innego kontrolera - tyle się teraz sprzedaje tanich
zdalnie sterowanych zabawek samochodów, samolotów, śmigłowców,
potem to wszytko dość szybko trafia na śmieci.
Jak się coś takiego wynajdzie, to całą elektronika wyrzucić i
wstawić płytkę z mikrokontroleram. Potencjometry kontrolera odczytywać
przetwornikiem ADC, a dane o wychyleniu joystików wysyłać portem
szeregowym( można też wykorzystać moduły radiowe )
pushkin
31.08.2013 (13:50)
gość
To jeszcze raz ja.
Na początek chciałbym podziękować za świetny artykuł i pochwalić się, że u mnie działa bez najmniejszych problemów.
W swoim testowym projekcie wykorzystałem pada, a konkretnie analogowe joysticki do sterowania dwoma serwami z modeli. Zadanie wykonane!
Ale są też pewne niuanse... mianowicie:
Nie wiem, czy to kwestia mojego pada (replika za 25PLN) czy samej technologii użytej w joystickach analogowych, ale niestety wartość bitu w zakresie 0-128 lub 128-255 czyli z wartości neutralnej do maksymalnej mieści się w 1/2 fizycznego zakresu gałki. Podsumowując, spory zakres wychyłu pozostaje nie wykorzystany, a ze względu na mały zakres rejestrowany (albo ja mam takie niezgrabne paluchy) zmiany wartości odbywają się dość skokowo i trochę utrudniają ustawienie serwa w żądanej pozycji...
Czy sprawdzał ktoś na oryginalnym padzie czy zakresy są tak samo okrojone?
pushkin
26.08.2013 (16:23)
gość
Co prawda jeszcze nie przetestowałem działania układu, ale zauważyłem w tabelce, że bity 1 i 2 w bajcie 4 nie są opisane.
Zgodnie z tą dokumentacją:
http://store.curiousinventor.com/guides/ps2/
odpowiadają one kolejno za przyciski L3 i R3 (czyli wciśnięcie lewego lub prawego analogu)
abxyz
28.02.2013 (23:26)
autor strony
Tak zostało zdefiniowane makro _NOP_ - krótkie opóźnienie

#define _NOP_ asm volatile("nop\n\t""nop\n\t" "nop\n\t" "nop\n\t" ::)

to po prostu są cztery pod rząd instrukcje procesora NOP (no operation), jedna instrukcja trwa jeden cykl zegara.
Ale właściwie chciałem napisać to że, użyte tam słówko "volatile" ma sprawić, że kompilator ma pominąć te instrukcje podczas optymalizacji, inaczej mógłby to "skrócić i wyrzucić" :)
Johny Five
28.02.2013 (20:48)
użytkownik
Kolejny komentarz jeden po drugim, co wynika chyba z mojego roztrzepania.
To co pisałem poniżej o stanie CLK to nieważne, bo teraz dopiero zrozumiałem co napisałeś w trzecim akapicie od dołu i tam wszystko już zawarłeś :P
I jakby co to nie pisze tego wszystkiego, żeby Cię denerwować czy coś w ten deseń :D , ale może znajdzie się drugi taki toporny na wiedzę użytkownik, przeczyta poniższe komentarze i któryś z nich mu pomoże :P
Pozdrawiam.
Johny Five
28.02.2013 (19:22)
użytkownik
Bardzo prawdopodobne, że mam takie problemy z tym padem bo jest to najtańszy chińczyk jakiego znalazłem, ale już od tygodnia się z tym męczyłem :P Testowałem mnóstwo wartości opóźnień i to nie tylko w twoim programie, ale też w 3 innych bibliotekach jakie tylko udało mi się znaleźć :) Może i łatwiej było by napisać własną, ale założyłem, że by mnie to przerosło.

Co do opóźnień rzeczywiście myliłem się wyłączając optymalizacje, doczytałem teraz trochę i masz 100% racji, ale czy nie ma wtedy problemów z opóźnieniami _NOP_ ?? Bo żeby program zaczął działać z optymalizacją (Os tak jak radziłeś) musiałem zamienić wszystkie _NOP_ na _delay_us(30).

Jeszcze co do funkcji pad_cmd, odpaliłem sobie Twój program jeszcze raz i nie wiem dlaczego, ale działa jedynie, gdy zmiany stanu wyjścia CLK są przeprowadzane po wysłaniu bitu CMD i odbioru bitu DATA, a nie przed.

Pozdrawiam Johny.
abxyz
28.02.2013 (14:45)
autor strony
Nie przynudzasz :)

1. Zasilanie pada.

Tak zgoda, pad powinien być zasilany napięciem 3.3V, chociaż wszystkie kontrolery, których używałem, dobrze działały przy zasilaniu napięciem 5V.

2. Optymalizacja kompilacji

Wyłączenie optymalizacji może spowodować, że kody wynikowy urośnie do gigantycznych rozmiarów, a opóźnienia (funkcje _delay_ms i _delay_us) właśnie będą źle działać. Należy włączyć optymalizację kompilacji -Os( optymalizacja pod względem rozmiaru kodu) oraz linkować z opcją -lm Jeśli nie jesteś pewien jakich użyć opcji przy kompilacji, to polecam użycie pliku makefile z programu MFile - tak jak opisałem to w kursie.

3. Funkcja "pad_byte'

Na stronie pod adresem http://store.curiousinventor.com/guides/PS2 jest zamieszczona fotografia - oscylogram pokazujący przebieg komunikacji kontrolera z konsolą playstation.

Proszę zwrócić uwagę w którym momencie zmieniają się stany na liniach DATA COMMAND, względem sygnału sygnału taktującego CLOCK.
Ja widzę tam, że zmiany stanów na DATA i COMMAND zachodzą natychmiast po (albo może w momencie) zmiany CLOCK ze stany wysokiego w niski. A odczyt stanu DATA i COMMAND odbywa się przy przejściu sygnału CLOCK ze stanu niskiego do wysokiego.

Odpowiednio do tego napisałem funkcję pad_byte.:

CLOCK H->L
ustawienie COMMAND
opóźnienie
CLOCK L->H
odczyt DATA
Natomiast twoja wersja wygląda tak:

ustawienie COMMAND
CLOCK H->L
opóźnienie
odczyt DATA
CLOCK L->H

Zatem kod który wkleiłeś robi właściwie to samo, bo widocznie dla kontrolera od playstation nie ma większego znaczenia że ustawienia linii COMMAND nastąpi tuż przed, czy zaraz po, zmianie sygnału CLOCK H->L; podobnie nie ma znaczenia ,że stan linii DATA zostanie odczytany tuż przed, czy zaraz po,
zmianie sygnału CLOCK L->H

Podobnie skonfigurowałem sprzętowy interfejs SPI AVRa (SPI mode 3 - CPOL=1, CPHA=1), tzn. setup(falling), sample(rising)

A dla czego, w Twoim przypadku, przykład z artykułu nie działa ?
Pewnie wystarczy dobrać odpowiednio opóźnienia - doświadczalnie.

Johny Five
27.02.2013 (23:12)
użytkownik
Ps. Pewnie już trochę przynudzam, ale zalecałbym zasilać układ napięciem 3.3 V jeżeli pozwala na to ATMega (typu L), lub samego pada. Na napięciu 5V pad miał problemy z komunikacją z bezprzewodowym modułem.
Ps.2 Wysoce wskazane jest także wyłączenie optymalizacji w kompilatorze, aby opóźnienia działały poprawnie
Johny Five
27.02.2013 (21:26)
użytkownik
Znalazłem na tej stronie wiele przydatnych rzeczy i dużo się nauczyłem dlatego postanowiłem się podzielić kawałkiem kodu, który udało mi się napisać.

unsigned char pad_byte(unsigned char byte)
{
unsigned char i,r=0;

for(i=0; i<8; i++)
{
if(byte & (1<<i)) CMD_SET; else CMD_CLR;
CLK_CLR;
_NOP_;
if(DATA_IN) (r|=(1<<i));
CLK_SET;
}
CMD_SET;
_NOP_;
return r;
}

Nie będę oszukiwał nie jestem znawcą, a ten kawałek kodu przeportowałem z biblioteki Billa Portera, przygotowanej na Arduino.
Jest to zmieniona funkcja "pad_byte", która to zmiana (przynajmniej dla mnie) powoduje ruszenie programowego SPI. Nie wiem czy będzie to wszystkim chodzić, a może nie wszyscy tego potrzebują w końcu autorowi manualna działa oryginalna wersja, ale uznałem że warto się tym podzielić.
Dodam że osobiście posiadam pada od PS2 nieoryginalnego, bezprzewodowego, natomiast ten fragment kodu przetestowałem jedynie pobieżnie tzn. sprawdziłem że naciśnięcie przycisku powoduje zmianę wartości w bajtach 3 i 4, ale zauważyłem również że konfiguracja przebiega pomyślnie, gdyż zamiast samych 255 jak to było na początku dostajemy teraz w odpowiedzi:
255 65 90 255 255
255 243 90 0 0 0 0 0 0
tak jak to jest na sprzętowym SPI wiec powinno być w pożądku.
Pozdrawiam.
Johny Five
24.02.2013 (19:56)
użytkownik
W moim przypadku działa, ale jedynie SPI sprzętowy. Komunikacja rozwiązana programowo nie zdaje testu, może dlatego że testowałem ten kod na nieoryginalnym bezprzewodowym padzie, ale skoro działa na sprzętowym SPI wiec raczej szukałbym jakiejś poprawki w funkcji "pad_byte()"
abxyz
02.08.2012 (09:00)
autor strony
Nie zawsze wszytko chce od razu działać, czasem trzeba powalczyć. Trzeba szukać, stukać, pukać, zmienić, dopasować i wyregulować - nazywa się to uruchamianiem:)
ja
17.07.2012 (18:44)
gość
Zrobiłem wszystko jak w artykule i po wgraniu programu wszystkie diody się świecą. Jedynie kiedy podłączę PC3 do masy zapala się dioda na PD7. Miał ktoś podobny problem? Z góry dzięki.
abxyz
04.06.2012 (22:15)
autor strony
Na m8
adm
04.06.2012 (19:02)
gość
Świetny artykuł, na jakiej atmedze uruchamiany był program testowy?
Artykuły>Mikrokontrolery i PLD>Kurs AVR-GCC Gamepad od PlayStation
Ostatnie artykuły