Try   HackMD

Play Station 2 Controller - Dual Shock 2

兼容 Sony PlayStation2 的遙控手柄。
通訊協定被破解後,被廣泛使用在其他需要遙控的應用上。

Overview

分為手把接收器
接收器連接主機(可抽換為其他控制器),接收來自手把的訊號,亦可發送命令至手把選擇模式。

  • 手把 :

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  • 接收器 :

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

Pin Figuration

通訊協定類似 SPI (Serial Peripheral Interface)。

1 2 3 4 5 6 7 8 9
DI/DAT DO/CMD NC GND VDD CS/SEL CLK NC ACK
  • DI/DAT : Master in Slave out. 單次送收 8bits,CS下降緣時發送。
  • DO/CMD : Master out Slave in. 單次送收 8bits,CS下降緣時發送。
  • NC : No Connection. ( 震動馬達電源 : 7.2~9V (?) )
  • GND : 電源地。
  • VDD : 工作電壓 3~5 V 。
  • CS/SEL : Chip Select. 通訊期間維持低電壓
  • CLK : Clock Signal. 由主機發送。
  • NC : No Connection.
  • ACK : Acknowledgement. 軟體設定不使用。

(*註 : ACK在說明書解釋為 : 从手柄到主机的应答信号。此信号在每个 8bits 数据发送的最后一个周期变低并且 CS 一直保持低电平,如果 CS 信号不变低,约 60 微秒 PS 主机会试另一个外设。在编程时未使用 ACK 端口。)

時序

CLK 頻率 250kHz,若通訊不穩,可適當增加頻率。
先送 LSB 。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


一個通訊週期 9 Bytes,如下表依序傳送。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • 主機讀取手把資料時:

    1. 主機先拉低CS腳並發送"0x01"(CMD)。
    2. 手把回復ID "0x41"(綠燈模式) 或 "0x73"(紅燈模式)。
    3. 主機發送 "0x42" 請求數據。
    4. 手把發送 "0x5A" 確認狀態。
    5. 開始資料段如上圖。

    當該按鍵被按下,其對應位置為 "0",其他為 "1"
    eg. LEFT 被按下時 Data[3] = 0b01111111.

    (*註 : idle 為閒置狀態)

  • 綠燈模式 :
    左右搖桿回傳類比值(0x00 ~ 0xFF)。
    L3、R3有效。

  • 紅燈模式 :
    左右搖桿推至極限時回傳 UP、RIGHT、DOWN、LEFT,△、〇、X、□。
    L3、R3無效。

  • 震動模式(未使用) :
    WW 位控制右邊震動馬達 : 0x00 為關,其他為開。
    YY 位控制左邊震動馬達 : 0x40 ~ 0xFF 為開,數字越大震動越大。

硬體使用說明

手把使用兩顆AAA電池,接收器使用主機電源(3~5V)。

接收器未配對時閃綠燈。
手把未配對時燈會不停地閃,未找到前手把的燈會不停地閃,超過一定時間會自動進入待機模式,等待 Start 鍵再次喚醒。

接收器接上電源,手把上開關撥至 ON 時會自動配對附近接收器,成功配對時,燈常亮。

成功配對後,Mode可切換綠燈模式或紅燈模式。

程式範例

主機 : ASA M128

  • PA0 -> DAT (Input)
  • PA1 -> CMD (Output)
  • PA2 -> CS (Output)
  • PA3 -> CLK (Output)

PS2.c

/** * @file PS2.h * @author C.Y. YANG * @date 2020.1.31 * @brief PS2搖桿 * * NOTE: 硬體相依標頭檔內腳位定義與各檔案內工作頻率定義 */ /* * PA0 -> DAT (Input) * PA1 -> CMD (Output) * PA2 -> CS (Output) * PA3 -> CLK (Output) */ #include "PS2.h" #include <math.h> #include <stdio.h> #include <stdint.h> #include <avr/io.h> #include <util/delay.h> #define F_CPU 11059200UL uint8_t DO[9] = {0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t DI[9] = {0}; void PORT_init (void) { DIR_SET(); CS_SET(); CLK_SET(); } // Full-Duplex uint8_t ByteCommunication (uint8_t cmd) { uint8_t res_buffer = 1; uint8_t res = 0; for (int i = 0; i < 8; i++) { if(cmd & 0x01) CMD_SET(); else CMD_CLR(); cmd >>= 1; _delay_us(100); CLK_CLR(); _delay_us(100); if(PINA & 0x01) res = res + res_buffer; res_buffer <<= 1; CLK_SET(); } return res; } uint8_t Read_PS2_Controller (void) { uint8_t controller_res = 0; CS_CLR(); for(int i = 0; i < 9; i++) DI[i] = ByteCommunication(DO[i]); CS_SET(); if(DI[1] == 0x41) //printf("Green Light Mode\n"); if(DI[3] == PSB_SELECT) printf("PSB_SELECT\n"); controller_res = 1; if(DI[3] == PSB_L3) printf("PSB_L3\n"); controller_res = 2; if(DI[3] == PSB_R3) printf("PSB_R3\n"); controller_res = 3; if(DI[3] == PSB_START) printf("PSB_START\n"); controller_res = 4; if(DI[3] == PSB_PAD_UP) printf("PSB_PAD_UP\n"); controller_res = 5; if(DI[3] == PSB_PAD_RIGHT) printf("PSB_PAD_RIGHT\n"); controller_res = 6; if(DI[3] == PSB_PAD_DOWN) printf("PSB_PAD_DOWN\n"); controller_res = 7; if(DI[3] == PSB_PAD_LEFT) printf("PSB_PAD_LEFT\n"); controller_res = 8; if(DI[4] == PSB_L2) printf("PSB_L2\n"); controller_res = 9; if(DI[4] == PSB_R2) printf("PSB_R2\n"); controller_res = 10; if(DI[4] == PSB_L1) printf("PSB_L1\n"); controller_res = 11; if(DI[4] == PSB_R1) printf("PSB_R1\n"); controller_res = 12; if(DI[4] == PSB_GREEN) printf("PSB_GREEN\n"); controller_res = 13; if(DI[4] == PSB_RED) printf("PSB_RED\n"); controller_res = 14; if(DI[4] == PSB_BLUE) printf("PSB_BLUE\n"); controller_res = 15; if(DI[4] == PSB_PINK) printf("PSB_PINK\n"); controller_res = 16; if(DI[1] == 0x73) { //printf("Red Light Mode\n"); if(DI[5] != 128) printf("PSS_RX : %d\n", DI[5]); if(DI[6] != 127) printf("PSS_RY : %d\n", DI[6]); if(DI[7] != 128) printf("PSS_LX : %d\n", DI[7]); if(DI[8] != 127) printf("PSS_LY : %d\n", DI[8]); } while ((DI[3] != 0xFF) || (DI[4] != 0xFF)) { CS_CLR(); for(int i = 0; i < 9; i++) DI[i] = ByteCommunication(DO[i]); CS_SET(); _delay_ms(1); } _delay_ms(10); return controller_res; }

PS2.h

/** * @file PS2.h * @author C.Y. YANG * @date 2020.1.31 * @brief PS2搖桿 * * NOTE: 硬體相依標頭檔內腳位定義與各檔案內工作頻率定義 */ /* * PA0 -> DAT (Input) * PA1 -> CMD (Output) * PA2 -> CS (Output) * PA3 -> CLK (Output) */ #ifndef PS2_H_ #define PS2_H_ #include <math.h> #include <stdio.h> #include <stdint.h> #include <avr/io.h> #include <util/delay.h> #define F_CPU 11059200UL #define DIR_SET() (DDRA |= (1<<DDRA1) | \ (1<<DDRA2) | \ (1<<DDRA3)) #define CMD_SET() (PORTA |= (1<<PORTA1)) #define CMD_CLR() (PORTA &= ~(1<<PORTA1)) #define CS_SET() (PORTA |= (1<<PORTA2)) #define CS_CLR() (PORTA &= ~(1<<PORTA2)) #define CLK_SET() (PORTA |= (1<<PORTA3)) #define CLK_CLR() (PORTA &= ~(1<<PORTA3)) // PS2 Buttons #define PSB_SELECT 0b11111110 #define PSB_L3 0b11111101 #define PSB_R3 0b11111011 #define PSB_START 0b11110111 #define PSB_PAD_UP 0b11101111 #define PSB_PAD_RIGHT 0b11011111 #define PSB_PAD_DOWN 0b10111111 #define PSB_PAD_LEFT 0b01111111 #define PSB_L2 0b11111110 #define PSB_R2 0b11111101 #define PSB_L1 0b11111011 #define PSB_R1 0b11110111 #define PSB_GREEN 0b11101111 #define PSB_RED 0b11011111 #define PSB_BLUE 0b10111111 #define PSB_PINK 0b01111111 #define PSB_TRIANGLE 0b11101111 #define PSB_CIRCLE 0b11011111 #define PSB_CROSS 0b10111111 #define PSB_SQUARE 0b01111111 // PS2 Sticks // #define PSS_RX 5 // #define PSS_RY 6 // #define PSS_LX 7 // #define PSS_LY 8 void PORT_init (void); uint8_t ByteCommunication (uint8_t cmd); uint8_t Read_PS2_Controller (void); #endif /* PS2_H_ */

main.c

/* * PS2_contoller.c * * Created: 2020/1/31 * Author : C.Y. YANG * NOTE: */ /* * Play Station 2 Controller * * PA0 -> DAT (Input) * PA1 -> CMD (Output) * PA2 -> CS (Output) * PA3 -> CLK (Output) * */ #define F_CPU 11059200UL #include "c4mlib.h" #include "PS2.h" int main (void) { C4M_DEVICE_set(); uint8_t ck = 0; printf("----- Start -----\n"); PORT_init(); while (1) { ck = Read_PS2_Controller(); //printf("ck = %d\n", ck); _delay_ms(100); } return 0; }

Reference

參考智宇机器人PS2 无线遥控手柄说明书
版权声明
本手册版权归智宇机器人(以下简称“ZYRobot”)所有,对该手册保留一切权力,
非经 ZYRobot 授权同意(书面形式),任何单位及个人不得擅自摘录本手册部分及全部内容用于商业用途,违者将追究其法律责任。可以在网上传播,以方便更多人,但必须保证手册的完整性。

https://shopee.tw/product/139069730/2342925575

https://store.curiousinventor.com/guides/PS2
https://robosavvy.com/forum/viewtopic.php?t=2561
https://www.rhydolabz.com/wiki/?p=12663
https://zh.wikipedia.org/wiki/DualShock

tags: MODULE ROBOT