PS2手柄通讯协议解析—附资料和源码「建议收藏」

PS2手柄通讯协议解析—附资料和源码「建议收藏」文章目录一.PS2介绍二.PS2通讯协议介绍一.PS2介绍今天就带大家来认识一下PS2的通讯协议,如果你需要用PS2无线手柄搭配单面机来DIY制作,那么千万别错过这篇文章。首先介绍一下我们今天的主角–PS2手柄。PS2手柄是日本SONY公司的PlayStation2游戏机的遥控手柄。索尼的PSX系列游戏主机在全球都很畅销。不知什么时候便有人打起PS2手柄的主意,破解了通讯协议,使…

大家好,又见面了,我是你们的朋友全栈君。
PS2手柄通讯协议解析---附资料和源码「建议收藏」

一.PS2介绍

PS2手柄通讯协议解析---附资料和源码「建议收藏」

今天就带大家来认识一下PS2的通讯协议,如果你需要用PS2无线手柄搭配单面机来DIY制作,那么千万别错过这篇文章。

首先介绍一下我们今天的主角—–PS2手柄。 PS2手柄是日本SONY公司的PlayStation2 游戏机的遥控手柄。索尼的 PSX系列游戏主机在全球都很畅销。不知什么时候便有人打起 PS2手柄的主意,破解了通讯协议,使得手柄可以接在其他器件上遥控使用,比如遥控我们熟悉的机器人。突出的特点是这款手柄性价比极高,按键丰富,方便扩展到其它应用中。

二.PS2通讯协议介绍

PS2采用的是SPI通信协议,SPI是串行外设接口的缩写,是一种高速的、全双工、同步的通信总线,并且在芯片的管脚上只占用四根线(DI、DO、CS、CLK),节约了芯片的管脚,同时为PCB的布局上节省空间。

(1)PS2端口介绍

PS2手柄通讯协议解析---附资料和源码「建议收藏」

PS2接收器上一共有九根引脚,按上图从左往右,依次为:

1.DI/DAT:信号流向,从手柄到主机,此信号是一个8bit 的串行数据,同步传送于时钟的下降沿。信号的读取在时钟由高到低的变化过程中完成。

2.DO/CMD:信号流向,从主机到手柄,此信号和 DI相对,信号是一个 8bit 的串行数据, 同步传送于时钟的下降沿。

3.NC:空端口。

4.GND:电源地。

5.VCC:接收器工作电源,电源范围 3~5V。

6.CS/SEL:用于提供手柄触发信号。在通讯期间,处于低电平。

7.CLK:时钟信号,由主机发出,用于保持数据同步。

8.NC:空端口。

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

(2)PS2通讯过程

PS2手柄通讯协议解析---附资料和源码「建议收藏」

1. CS线在通讯期间拉低,通信过程中CS信号线在一串数据(9个字节,每个字节为8位)发送完毕后才会拉高,而不是每个字节发送完拉高。

2. DO、DI在在CLK时钟的下降沿完成数据的发送和读取。

下降沿:数字电平从高电平(数字“1”)变为低电平(数字“0”)的那一瞬间叫作下降沿。

3. CLK的每个周期为12us。若在某个时刻,CLK处于下降沿,若此时DO为高电平则取“1”,低电平则取“0”。连续读8次则得到一个字节byte的数据,连续读9个字节就能得到一次传输周期所需要的数据。DI也是一样的,发送和传输同时进行。

具体的通讯过程如下:
在这里插入图片描述
以STM32为例:

1. 首先STM32拉低CS片选信号线,然后在每个CLK的下降沿读一个bit,每读八个bit(即一个byte)CLK拉高一小段时间,一共读九组bit。

2. 第一个byte是STM32发给接收器命令“0X01” 。

3. PS2手柄会在第二个byte回复它的ID(0x41=绿灯模式,0x73=红灯模式),同时第二个byte时STM32发给PS2一个0x42请求数据。

红灯模式时 : 左右摇杆发送模拟值,0x00~0xFF 之间,且摇杆按下的 键值 L3 、 R3 有效;
绿灯模式时 : 左右摇杆模拟值为无效,推到极限时,对应发送 UP、RIGHT、DOWN、 LEFT、△、○、╳、□,按键 L3 、 R3 无效;

4. 第三个byte PS2 会给主机发送 “0x5A” 告诉STM32数据来了。

5. 从第四个byte开始全是接收器给主机发送数据,每个byte定义如上图,当有按键按下,对应位为“0 ”,例如当键“SELECT”被按下时, Data[3]=11111110。

对于整个通讯过程,你理解成下面的一段对话:

对于整个通讯过程,你理解成下面的一段对话:
首先,拉低CS,表示开始数据通信
byte 0 :
STM32(DO) : 0x01 ————————- [现在开始通信]
PS2手柄(DI) : 空 —————————- [空]
byte 1 :
STM32(DO) : 0x42 ————————– [请求发送数据]
PS2手柄(DI) : 红灯0x73
            绿灯0X41 ———————[现在的ID]
byte 2 :
STM32(DO) : 空 —————————— [空]
PS2手柄(DI) : 0X5A ————————- [数据来了]
byte 3 :
STM32(DO) : 0X00~0XFF —————— [右侧小震动电机是否开启]
PS2手柄(DI) : 00000000~11111111 ——- [SELECT、 L3 、 R3、 START 、 UP、 RIGHT、 DOWN、 LEFT 是否被按下,若被按下对应位为0]
byte 4 :
STM32(DO) : 0X00~0XFF —————— [左侧大震动电机振动幅度]
PS2手柄(DI) : 00000000~11111111 ——- [L2 、 R2、L1 、R1、△、○、╳、□ 是否被按下,若被按下对应位为0]
byte 5 :
STM32(DO) : 空 ——————————– [空]
PS2手柄(DI) : 0X00~0XFF —————— [左侧X轴摇杆模拟量]
byte 6 :
STM32(DO) : 空 ——————————– [空]
PS2手柄(DI) : 0X00~0XFF —————— [左侧Y轴摇杆模拟量]
byte 7 :
STM32(DO) : 空 ——————————– [空]
PS2手柄(DI) : 0X00~0XFF —————— [右侧X轴摇杆模拟量]
byte 8 :
STM32(DO) : 空 ——————————– [空]
PS2手柄(DI) : 0X00~0XFF —————— [右侧Y轴摇杆模拟量]
注:在手柄通信前还需要一系列的初始化(是否启动振动电机、是否进行锁存等),详情可以参考下面代码。当然,不进行初始化也是可以的,手柄会默认之前的配置。

PS2手柄通讯协议解析---附资料和源码「建议收藏」

注意:
1.模拟量只对红灯模式下有效,绿灯模式下摇杆推至极限分别对应 UP、RIGHT、DOWN、 LEFT、△、○、╳、□ 。
2. L3、R3只对红灯模式下有效,在绿灯模式下无效。

三.基于STM32的PS2通信源码

//采用模拟SPI通信
/*DI->PB12; DO->PB13; CS->PB14; CLK->PB15 */
void PS2_Init(void) { 
    
// 输入 DI->PB12
 RCC->APB2ENR|=1<<3; // 使能 PORTB 时钟 
 GPIOB->CRH&=0XFFF0FFFF;//PB12 设置成输入 默认下拉
 GPIOB->CRH|=0X00080000; 
 // DO->PB13 CS->PB14 CLK->PB15 
 RCC->APB2ENR|=1<<3; // 使能 PORTB 时钟 
 GPIOB->CRH&=0X000FFFFF;
 GPIOB->CRH|=0X33300000; //PB13、 PB14 、 PB15 推挽输出 
  } 
  //端口初始化,PB12 为输入,PB13 、PB14 、PB15 为输出。
  
// 向手柄发送命令
void PS2_Cmd(u8CMD) 
{ 
   
  volatile u16 ref=0x01; 
  Data[1]=0; 
  for(ref=0x01;ref<0x0100;ref<<=1) 
  { 
   
    if(ref&CMD) 
    { 
   
     DO_H; // 输出一位控制位
    }
    else DO_L; 
    CLK_H; // 时钟拉高 
    delay_us(10); 
    CLK_L; 
    delay_us(10); 
    CLK_H; 
    if(DI) 
    { 
   Data[1]=ref|Data[1];}
  }
 delay_us(16);
}

// 判断是否为红灯模式,0x41=模拟绿灯,0x73=模拟红灯 
// 返回值;0,红灯模式 
// 其他,其他模式
u8PS2_RedLight(void) 
{ 
   
  CS_L; 
  PS2_Cmd(Comd[0]); // 开始命令
  PS2_Cmd(Comd[1]); // 请求数据
  CS_H; 
  if( Data[1]== 0X73) return 0else return 1}

// 读取手柄数据 
void PS2_ReadData(void) 
{ 
   
  volatile u8 byte=0; 
  volatile u16 ref=0x01; 
  CS_L; 
  PS2_Cmd(Comd[0]); // 开始命令
  PS2_Cmd(Comd[1]); // 请求数据
  for(byte=2;byte<9;byte++) // 开始接受数据 
  { 
   
    for(ref=0x01;ref<0x100;ref<<=1) 
    { 
    
      CLK_H; 
      delay_us(10); 
      CLK_L; 
      delay_us(10); 
      CLK_H; 
      if(DI) 
      { 
   Data[byte]= ref|Data[byte];}
    }
    delay_us(16);
  }
  CS_H;
}   

/* 上面两个函数分别为主机向手柄发送数据、手柄向主机发送数据。手柄向主机发送的数据缓存在数组 Data[]中, 数组中共有9个元素,每个元素的意义请见表1。 还有一个函数是用来判断手柄的发送模式,也就是判断 ID(红灯还是绿灯模式) 即 Data[1]的值。 */


// 对读出来的 PS2 的数据进行处理,只处理按键部分
//按下为0,未按下为1
u8PS2_DataKey() 
{ 
   
  u8 index; 
  PS2_ClearData(); 
  PS2_ReadData(); 
  Handkey=(Data[4]<<8)|Data[3]; // 这是 16个按键 按下为 0 , 未按下为 1 
  for(index=0;index<16;index++) 
  { 
   
    if((Handkey&(1<<(MASK[index]-1)))==0) 
    returnindex+1;
  }
  return 0; // 没有任何按键按下
}

// 得到一个摇杆的模拟量 范围 0~256 
u8PS2_AnologData(u8 button) 
{ 
   
  return Data[button];
}


// 清除数据缓冲区
void PS2_ClearData() 
{ 
   
  u8 a; 
  for(a=0;a<9;a++) 
    { 
   Data[a]=0x00;}
}

/* 8 位数 Data[3]与 Data[4],分别对应着 16个按键的状态,按下为 0,未按下为 1。 通过 对这两个数的处理,得到按键状态并返回键值。 另一个函数的功能就是返回模拟值,只有在“红灯模式”下值才是有效的,拨动摇杆, 值才会变化,这些值分别存储在 Data[5]、Data[6]、 Data[7]、 Data[8]。 */


//手柄配置初始化: 
void PS2_ShortPoll(void) 
{ 
   
  CS_L; 
  delay_us(16); 
  PS2_Cmd(0x01); 
  PS2_Cmd(0x42); 
  PS2_Cmd(0X00); 
  PS2_Cmd(0x00); 
  PS2_Cmd(0x00); 
  CS_H; 
  delay_us(16);
}


//进入配置
void PS2_EnterConfing(void) 
{ 
   
  CS_L;
  delay_us(16); 
  PS2_Cmd(0x01); 
  PS2_Cmd(0x43); 
  PS2_Cmd(0X00); 
  PS2_Cmd(0x01); 
  PS2_Cmd(0x00); 
  PS2_Cmd(0X00);
  PS2_Cmd(0X00); 
  PS2_Cmd(0X00); 
  PS2_Cmd(0X00); 
  CS_H; 
  delay_us(16);
}


// 发送模式设置 
void PS2_TurnOnAnalogMode(void) 
{ 
   
  CS_L; 
  PS2_Cmd(0x01); 
  PS2_Cmd(0x44); 
  PS2_Cmd(0X00); 
  PS2_Cmd(0x01);//analog=0x01;digital=0x00 软件设置发送模式 
  PS2_Cmd(0xEE);//Ox03 锁存设置,即不可通过按键“MODE ”设置模式。 //0xEE 不锁存软件设置,可通过按键“MODE ”设置模式。 
  PS2_Cmd(0X00); 
  PS2_Cmd(0X00); 
  PS2_Cmd(0X00); 
  PS2_Cmd(0X00); 
  CS_H; 
  delay_us(16);
}


// 振动设置
void PS2_VibrationMode(void) 
{ 
   
  CS_L; 
  delay_us(16); 
  PS2_Cmd(0x01); 
  PS2_Cmd(0x4D); 
  PS2_Cmd(0X00); 
  PS2_Cmd(0x00); 
  PS2_Cmd(0X01); 
  CS_H; 
  delay_us(16);
}


// 完成并保存配置
void PS2_ExitConfing(void)
{ 
   
  CS_L;
  delay_us(16);
  PS2_Cmd(0x01);
  PS2_Cmd(0x43); 
  PS2_Cmd(0X00);
  PS2_Cmd(0x00); 
  PS2_Cmd(0x5A); 
  PS2_Cmd(0x5A); 
  PS2_Cmd(0x5A);
  PS2_Cmd(0x5A); 
  PS2_Cmd(0x5A); 
  CS_H; 
  delay_us(16);
}

// 手柄配置初始化
void PS2_SetInit(void) 
{ 
   
  PS2_ShortPoll();
  PS2_ShortPoll();
  PS2_ShortPoll(); 
  PS2_EnterConfing(); // 进入配置模式 
  PS2_TurnOnAnalogMode(); // “红绿灯”配置模式,并选择是否保存 
  PS2_VibrationMode(); // 开启震动模式 
  PS2_ExitConfing(); // 完成并保存配置
}
/* 可以看出配置函数就是发送命令,发送这些命令后,手柄就会明白自己要做什么了,发送命令时,不需要考虑手柄发来的信息。 手柄配置初始化,PS2_ShortPoll()被执行了3次,主要是为了建立和恢复连接。 具体的配置方式请看注释。 */
void PS2_Vibration(u8motor1,u8motor2)
{ 
   
   CS_L; 
   delay_us(16); 
   PS2_Cmd(0x01); // 开始命令
   PS2_Cmd(0x42);// 请求数据
   PS2_Cmd(0X00);
   PS2_Cmd(motor1);
   PS2_Cmd(motor2); 
   PS2_Cmd(0X00); 
   PS2_Cmd(0X00); 
   PS2_Cmd(0X00); 
   PS2_Cmd(0X00); 
   CS_H; 
   delay_us(16);
} 
//只 有 在 初 始 化 函 数 void PS2_SetInit(void) 中 , 对 震 动 电 机 进 行 了初 始 化 (PS2_VibrationMode();//开启震动模式),这个函数命令才会被执行。 

四.文档与源码下载链接

1.PS2参考文档CSDN:PS2解码通讯手册.pdf

2.这里还有一份我写的源码:PS2源码HAL库+CubeMX+Stm32F103C8 注意:

  • 里面除了PS2的源码还加了延时实验的源码。由于HAL库本身没有微秒级的延时,所以需要自己写微秒级的延时函数,详情看源码。至于延时的原理参考另一篇博客:Stm32延时与计时方法(HAL库)
  • 为防止与PS2通信过快而乱码导致延迟,需要在主函数的while(1)中延时50ms,即加一句delay_ms(50)。(原工程中没有,需要自行加上)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/130068.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月27日 下午4:00
下一篇 2022年4月27日 下午4:20


相关推荐

  • SLIC算法

    SLIC算法基础知识在介绍 SLIC 之前 先来介绍以下 Lab 颜色空间的介绍 Lab 色彩模型是由亮度 L 要素和与有关色彩的 a b 要素组成 L 的值由 0 黑色 到 100 白色 a 表示从洋红色至绿色的范围 a 为负值表示绿色而正值表示品红 b 表示从黄色至蓝色的范围 b 为负值表示蓝色而正值表示黄色 Lab 颜色空间的优点 1 不像 RGB 和 CMYK 色彩空间 Lab 颜色被设计来接近人类生理视觉 它致力于感知均匀性 它的 L 分量密切匹配人类亮度感知 因此可以被用来通过修改 a 和 b 分量的输出色阶来做精确的颜色平衡 或使用 L 分量来调

    2026年3月18日
    2
  • 微信本地数据库解密[通俗易懂]

    微信本地数据库解密[通俗易懂]微信本地数据库解密(安卓)微信的本地数据库EnMicroMsg.db存储在/data/data/com.tencent.mm/MicroMsg/(一长串)/中uin存储在/data/data/com.tencent.mm/shared_prefs/com.tencent.mm_preferences.xml(或auth_hold_prefs.xml)中,IMEI存储在/data/data/…

    2022年6月1日
    41
  • 网络尖兵技术分析及应对

    网络尖兵技术分析及应对网络尖兵技术分析及应对 转载于 https blog 51cto com 58308

    2026年3月16日
    2
  • 从 Clawdbot → Moltbot → OpenClaw:全网最完整本地部署实战指南来了!

    从 Clawdbot → Moltbot → OpenClaw:全网最完整本地部署实战指南来了!

    2026年3月13日
    2
  • 图论算法 —— 图论概述

    图论算法 —— 图论概述概述 图是计算机中常用的一种存储结构 图论是数学的一个分支 他以图为研究对象 不同情形具有不同的算法 关于图 点击这里 图的常见算法 图的搜索 点击这里 图的遍历 点击这里 AOV 网与拓扑排序 点击这里 AOE 网与关键路径 点击这里 图的连通性 点击这里 Floyd 算法 点击这里 Dijkstra 算法 点击这里 Ford 算法与 SPFA 点击这里 差分

    2026年3月18日
    2
  • 声纹识别行业佼佼者快商通荣获2019年吴文俊人工智能科学技术奖!

    声纹识别行业佼佼者快商通荣获2019年吴文俊人工智能科学技术奖!吴文俊人工智能科学技术奖 被誉为 中国智能科学技术最高奖 代表人工智能领域的最高荣誉 是以人工智能先驱 我国智能科学研究的开拓者和领军人物吴文俊院士命名的科研大奖 经科学技术部核准设立 由国家级学会 中国人工智能学会发起主办 每年评奖一次 具备提名推荐国家科学技术奖资格 2019 年度第九届吴文俊人工智能科学技术奖评审工作已经完成 经相关权威机构及两院院士 会士等专家学者的提名推荐 通

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号