学习 PS2 无线手柄的使用方法,将市场上 PS2 手柄通过解码应用到我们自己产品之中,比如控制智能车,机械臂等等任何涉及无线通信控制的一些diy场景。本次主要让大家了解 PS2 无线手柄的工作原理,以及掌握 PS2 无线手柄的使用并最终通过串口打印各按键的键值。

常见用途

diy 产品,舵机,寄存器 一些无线控制的设置和产品

手柄原理

ps2 由手柄与接收器两部分组成,手柄主要负责发送按键信息。都接通电源并打开手柄 开关时,手柄与接收器自动配对连接,在未配对成功的状态下,接收器绿灯闪烁,手柄上的 灯也会闪烁,配对成功后,接收器上绿灯常亮,手柄上灯也常亮,这时可以按“MODE” 键,选择手柄发送模式。
接收、、和主机(单片机)相连,实现主机与手柄之间的通讯。

实物参考如下图

接收器引脚输出,

1 2 3 4 5 6 7 8 9
DI/DAT DO/CMD NC GND VDD CS/SEL CLK NC ACK
数据 命令 空/不接 通讯3.3V ---- 时钟 一般不接 不接

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

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

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

3.NC:空端口。

4.GND:电源地。

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

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

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

8.NC:空端口。

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

 在时钟下降沿时,完成数据的发送与接收。

当主机想读手柄数据时,将会拉低 CS 线电平,并发出一个命令“0x01”; 手柄会回复 它的 ID“0x41=模拟绿灯,0x73=模拟红灯”;在手柄发送 ID 的同时,主机将传送 0x42,请求数据;随后手柄发送出 0x5A,告诉主机“数据来了”。idle:数据线空闲,改数据线无数据传送。
一共一个通讯周期有 9 个数据,这些数据是依次按为传送。
表 1:数据意义对照表!

当有按键按下,对应位为“0”,其他位为“1”,例如当键“SELECT”被按下时,Data[3]=11111110B,
红灯模式时:左右摇杆发送模拟值,0x00~0xFF(256) 之间的模拟量,且摇杆按下的键值值
L3、R3 有效;
绿灯模式时:左右摇杆模拟值为无效,推到极限时,对应发送 UP、RIGHT、DOWN、 LEFT、△、○、╳、□,按键 L3、R3 无效。

硬件连接部分

接收器与 stm32 连接方式
Dl—>PC13
DO—>PB14
CS—>OC15
CLK—>PB8

下面就是测试程序

完整程序详见工程文件。 这里主要介绍 ps2.c 文件中的函数。

void PS2_Init(void)
{//ÊäÈë  DI->PC13        GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO,       ENABLE);GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_13;//PC13GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //ÏÂÀ­Ä£Ê½PWR_BackupAccessCmd(ENABLE);RCC_LSEConfig(RCC_LSE_OFF);BKP_TamperPinCmd(DISABLE);PWR_BackupAccessCmd(DISABLE);GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_9;//PB9GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);    }

端口初始化

//向手柄发送命令

 void PS2_Cmd(u8 CMD)
{volatile u16 ref=0x01; for(ref=0x01;ref<0x0100;ref<<=1){if(ref&CMD){DO_H;  //输出一位控制位}else DO_L;CLK_H; //时钟拉高 delay_us(50);CLK_L; delay_us(50); CLK_H;}
}

//读取手柄数据

 void PS2_ReadData()
{volatile u8 byte=0; volatile u16 ref=0x01;//PS2 解码通讯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;CLK_L; delay_us(50); CLK_H;if(DI)Data[byte] = ref|Data[byte];}delay_us(50);}CS_H;
}

上面两个函数分别为主机向手柄发送数据、手柄向主机发送数据。手柄向主机发送的数 据缓存在数组 Data[ ]中,数组中共有 9 个元素,每个元素的意义请见表 1。
//对读出来的 PS2 的数据进行处理 //按下为 0, 未按下为 1

u8 PS2_DataKey()
{u8 index; PS2_ClearData(); PS2_ReadData();Handkey=(Data[4]<<8)|Data[3]; //这是 16 个按键 按下为 0, 未按下为 1for(index=0;index<16;index++){if((Handkey&(1<<(MASK[index]-1)))==0) return index+1;} return 0;   //没有任何按键按下
}

8 位数 Data[3]与 Data[4],分别对应着 16 个按键的状态,按下为 0,未按下为 1。通过
对这两个数的处理,得到按键状态并返回键值。
编写主函数:
PS2 解码通讯

int main(void)
{u8 key;Stm32_Clock_Init(9); //系统时钟设置delay_init(72);    //延时初始化uart_init(72,9600);  //串口 1 初始化PS2_Init();   while(1)    {   key=PS2_DataKey();if(key!=0)  //有按键按下{    printf("   \r\n   %d  is  pressed  \r\n",key);}printf(" %5d %5d %5d %5d\r\n",PS2_AnologData(PSS_LX),PS2_AnologData(PSS_LY), PS2_AnologData(PSS_RX),PS2_AnologData(PSS_RY) );delay_ms(50);}
}

上面两个函数分别为主机向手柄发送数据、手柄向主机发送数据。手柄向主机发送的数 据缓存在数组 Data[ ]中,数组中共有 9 个元素,每个元素的意义请见表 1。

//对读出来的 PS2 的数据进行处理 //按下为 0, 未按下为 1

u8 PS2_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)return index+1;} return 0;   //没有任何按键按下
}

当有按键按下时,输出按键值

4 下载与测试

编译程序并下载。按 ANALOG 可以改变模式,先选择红灯模式,遥控器上指示灯为红 色。串口输出的模拟值为 127 或 128,当晃动摇杆时,相应的模拟值就会改变,这时摇杆按 键可以按下,可以输出键值,见图 2。

图 2 按下“△”,输出对应的键值“13”。

图 3 按“ANALOG”,改为绿灯模式,手柄上指示灯变为“绿色”,串口输出的模拟值为

“255”,轻轻晃动摇杆,模拟值不变。

图 4 我们将右摇杆向上推到极限,这时串口输出“13 is pressed”,键值对应“△”,但模

拟的值不改变。

图 5 “红灯模式”和“绿灯模式”的主要区别就在与摇杆模拟值的输出。

测试案例2

ps2 函数

/*********************************************************
File:PS2驱动程序
Description: PS2驱动程序
**********************************************************/
u16 Handkey;
u8 Comd[2]={0x01,0x42};    //开始命令。请求数据
u8 Data[9]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //数据存储数组
u16 MASK[]={PSB_SELECT,PSB_L3,PSB_R3 ,PSB_START,PSB_PAD_UP,PSB_PAD_RIGHT,PSB_PAD_DOWN,PSB_PAD_LEFT,PSB_L2,PSB_R2,PSB_L1,PSB_R1 ,PSB_GREEN,PSB_RED,PSB_BLUE,PSB_PINK};  //按键值与按键明void PS2_Init(void)
{//输入  DI->PB9           GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA, ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable , ENABLE);GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_14;//PA14GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉模式//PWR_BackupAccessCmd(ENABLE);//RCC_LSEConfig(RCC_LSE_OFF);//BKP_TamperPinCmd(DISABLE);//PWR_BackupAccessCmd(DISABLE);GPIO_Init(GPIOA,&GPIO_InitStructure);//  DO->PA12    CS->PA8  CLK->PB9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);   }//向手柄发送命令
void PS2_Cmd(u8 CMD)
{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(50);Delay_us(50);CLK_L;//delay_us(50);Delay_us(50);CLK_H;if(DI)Data[1] = ref|Data[1];}
}
//判断是否为红灯模式
//返回值;0,红灯模式
//        其他,其他模式
u8 PS2_RedLight(void)
{CS_L;PS2_Cmd(Comd[0]);  //开始命令PS2_Cmd(Comd[1]);  //请求数据CS_H;if( Data[1] == 0X73)   return 0 ;else 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;CLK_L;//delay_us(50);Delay_us(50);CLK_H;if(DI)Data[byte] = ref|Data[byte];}//delay_us(50);Delay_us(50);}CS_H;
}//对读出来的PS2的数据进行处理      只处理了按键部分         默认数据是红灯模式  只有一个按键按下时
//按下为0, 未按下为1u8 PS2_DataKey()
{//  static uint8 temp=1;u8 index;PS2_ClearData();PS2_ReadData();Handkey=(Data[4]<<8)|Data[3];     //这是16个按键  按下为0, 未按下为1for(index=0;index<16;index++){     if((Handkey&(1<<(MASK[index]-1)))==0){//temp=(Handkey&(1<<(MASK[index]-1)));return index+1;}}return 0;          //没有任何按键按下
}//得到一个摇杆的模拟量    范围0~255
u8 PS2_AnologData(u8 button)
{return Data[button];
}//清除数据缓冲区
void PS2_ClearData()
{u8 a;for(a=0;a<9;a++)Data[a]=0x00;
}
/**************************************************************************
函数功能:获取PS2无线手柄按键值,定时器每隔段时间进行读取PS2_DataKey()
入口参数:无
返回  值:无
**************************************************************************/
void scan_ps2(void)
{if (flag_scan_ps2)   //定时时间到{flag_scan_ps2 = 0;key = PS2_DataKey();switch(key){case PSB_PAD_UP:CPWM[1]+=10;if(CPWM[1]>=2300)   CPWM[1]=2300;dj1+=10;if(dj1>=2200)dj1=2200;sprintf(buf,"#1P%dT1\r\n",dj1);UART_PutStr(USART3,buf);break; case PSB_PAD_DOWN:CPWM[1]-=10;if(CPWM[1]<=700)  CPWM[1]=700;dj1-=10;if(dj1<=700)dj1=700;sprintf(buf,"#1P%dT1\r\n",dj1);UART_PutStr(USART3,buf);break;case PSB_PAD_LEFT:CPWM[2]+=10;if(CPWM[2]>=2300) CPWM[2]=2300;dj2+=10;if(dj2>=2200)dj2=2200;sprintf(buf,"#2P%dT1\r\n",dj2);UART_PutStr(USART3,buf);break; case PSB_PAD_RIGHT:CPWM[2]-=10;if(CPWM[2]<=700) CPWM[2]=700;dj2-=10;if(dj2<=700)dj2=700;sprintf(buf,"#2P%dT1\r\n",dj2);UART_PutStr(USART3,buf);break;case PSB_TRIANGLE:CPWM[3]+=10;if(CPWM[3]>=2300) CPWM[3]=2300;dj3+=10;if(dj3>=2200)dj3=2200;sprintf(buf,"#3P%dT1\r\n",dj3);UART_PutStr(USART3,buf);break; case PSB_CROSS:CPWM[3]-=10;if(CPWM[3]<=700)  CPWM[3]=700;dj3-=10;if(dj3<=700)dj3=700;sprintf(buf,"#3P%dT1\r\n",dj3);UART_PutStr(USART3,buf);break;case PSB_PINK:CPWM[4]+=10;if(CPWM[4]>=2300)  CPWM[4]=2300;dj4+=10;if(dj4>=2200)dj4=2200;sprintf(buf,"#4P%dT1\r\n",dj4);UART_PutStr(USART3,buf);break; case PSB_CIRCLE:CPWM[4]-=10;if(CPWM[4]<=700) CPWM[4]=700;dj4-=10;if(dj4<=700)dj4=700;sprintf(buf,"#4P%dT1\r\n",dj4);UART_PutStr(USART3,buf);break;case PSB_L1:CPWM[5]+=10;if(CPWM[5]>=2300) CPWM[5]=2300;dj5+=10;if(dj5>=2200)dj5=2200;sprintf(buf,"#5P%dT1\r\n",dj5);UART_PutStr(USART3,buf);break; case PSB_L2:CPWM[5]-=10;if(CPWM[5]<=700)  CPWM[5]=700;dj5-=10;if(dj5<=700)dj5=700;sprintf(buf,"#5P%dT1\r\n",dj5);UART_PutStr(USART3,buf);break;case PSB_R1:CPWM[6]+=10;if(CPWM[6]>=2300) CPWM[6]=2300;dj6+=10;if(dj6>=2200)dj6=2200;sprintf(buf,"#6P%dT1\r\n",dj6);UART_PutStr(USART3,buf);break; case PSB_R2:CPWM[6]-=10;if(CPWM[6]<=700)  CPWM[6]=700;dj6-=10;if(dj6<=700)dj6=700;sprintf(buf,"#6P%dT1\r\n",dj6);UART_PutStr(USART3,buf);break;default:break;}}}

main 函数

uint16 CPWM[9]= {1500,1500,1500,1500,1500,1500,1500,1500,1500};
unsigned int dj1=1500;
unsigned int dj2=1500;
unsigned int dj3=1500;
unsigned int dj4=1500;
unsigned int dj5=1500;
unsigned int dj6=1600;char buf[30];
uint16 UartRec[9];            //上位机字符串解析都放在这个数组里
unsigned char flag_uart1_rev=0;
unsigned char flag_uart2_rev=0;
char uart2_buf[255];
char uart1_buf[255];
unsigned char i=0;
u32 key, key_bak;
uint8 flag_vpwm=0;
unsigned char flag_scan_ps2;
void scan_ps2(void);
int main(void)
{   SysTick_Init();     //系统滴答定时器初始化    Servor_GPIO_Config();       LED_Init();       //LED 初始化函数Beep_Init();      //蜂鸣器初始化函数Beep_Test();      //蜂鸣器测试Led_Test(); Timer_Init();Timer_ON();PS2_Init();Uart_Init(1);  Uart_Init(3);   USART3_Config(115200);USART_Config(USART1,115200);while (1){    scan_ps2();}
}

由于设备坏了,就不测试了,自己测试吧!!!1

快速学习Stm32舵机控制板控制多个舵机运动以及调速

学习PS2无线手柄解码通讯手册相关推荐

  1. 玩转X-CTR100 l STM32F4 l PS2无线手柄

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] SONY的PS2无线手柄是索尼游戏机的遥控手柄,控制 ...

  2. 使用Arduino mega 2560读取PS2无线手柄信号并控制小车运动

    使用Arduino mega 2560读取PS2无线手柄信号并控制小车运动 文章目录 使用Arduino mega 2560读取PS2无线手柄信号并控制小车运动 1 前言 2 硬件连接 2.1 硬件构 ...

  3. 玩转X-CTR100 l STM32F4 l PS2无线手柄-4WD智能小车

    我造轮子,你造车,创客一起造起来!更多塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] 前面已介绍X-CTR100控制器解码PS2无线手 ...

  4. 10 模拟SPI驱动PS2无线手柄

    ROS机器人工程 PS2手柄驱动移植 什么是驱动移植? 不同平台,端口的初始化.配置.数据的读/写 都不一样.改成平台所需格式. 用PS2手柄控制你的机器人 用PS2手柄调节最大速度 用PS2手柄复合 ...

  5. PS2无线遥控手柄与STM32单片机通信

    PS2无线遥控手柄 接下来要做一个小车玩玩,在网上淘了一个PS2无线遥控手柄,用于控制小车的前进.后退等功能. 实物图如下: 其中有两个PS2游戏摇杆,对应的驱动原理参见下文: PS2游戏摇杆原理及控 ...

  6. 单片机右摇杆c语言函数英文,对PS2遥控手柄与stm32单片机通讯的理解(结合平衡小车之家的说明和程序)...

    为了更好地应用PS2遥控手柄,我想尽量理解一下它与stm32单片机间通讯控制的过程,首先看了平衡小车之家给的PS2遥控手柄使用说明,讲解的内容比较简洁,光凭这个说明不能很轻易地理解配套的程序逻辑,接下 ...

  7. 用32板实现ps2无线遥控的实时控制

    最近对无线控制有点着迷,无意中接触到ps2无线遥控,发射/接收端自动连接,通道多(包括摇杆模拟值),通信协议简单,关键价格还便宜! 经过一下午对材料的阅读,更改程序,最终实现了无线遥控实时控制LED灯 ...

  8. 北通手柄连接电脑没反应_北通无线手柄连接电脑没反应如何解决?

    你是否正在寻找关于北通无线手柄的内容?让我把最简洁的东西奉献给你: 北通无线手柄连接电脑没反应如何解决? 提问者:冯安祯| 地点:泸州| 浏览次数:399| 提问时间:2016-01-28 14:14 ...

  9. 遨博协作机器人插件开发-机械臂无线手柄遥控插件开发

    目录 1.课程简介 2.实训目的 3.实训环境 4.实训原理 5.实训步骤 6.真机测试 1.课程简介 在前面课程我们讲解了如何进行通用插件的开发以及使用,本次课程以无线手柄为例,介绍无线遥控插件的开 ...

  10. 对PS2遥控手柄与stm32单片机通信的理解(结合平衡小车之家的说明和程序)

    为了更好地应用PS2遥控手柄,我想尽可能理解一下它与stm32单片机间通信控制的过程,首先看了平衡小车之家给的PS2遥控手柄使用说明,讲解的内容比较简洁,光凭这个说明不能很轻易地理解配套的程序逻辑,接 ...

最新文章

  1. 鼠标按键获取感兴趣区域 2
  2. WCF RIA Service实体类中发复杂类型
  3. NSLocalizedString 实现国际化
  4. disaster——我都做了些什么啊!
  5. 流水线技术在高速数字电路设计中的应用
  6. sql行数少于10_如何用少于100行的代码创建生成艺术
  7. win2000/2003 Discuz生存环境搭建及基础优化 攻略
  8. 剑指offer(Python版本)
  9. 工程数学线性代数 同济大学版 第六版 课后习题答案 高等数学 大学数学 线性代数 课后题答案与解析 考试复习提纲
  10. Vue实现仿豆瓣电影
  11. 【涨知识】你家用的是A级锁还是B级锁,什么锁最安全?
  12. 独立站卖家如何借势营销
  13. Factory(工厂)模式
  14. mysql1.2.17,17.1 MySQL主从介绍17.2 准备工作17.3 配置主17.4 配置从17.5 测试主从同步...
  15. 【docker】docker介绍
  16. Linux 软连接和硬链接
  17. Bugly SDK 集成使用
  18. dockerHomeassistant
  19. 氮化硼气凝胶介绍-供应Al2O3-SiO2-ZrO2三元复合/MTMS-SiO2甲基三甲氧基硅烷改性氧化硅颗粒/聚酰亚胺/二氧化硅气凝胶定制
  20. JavaScript-修炼之路第七层

热门文章

  1. 数学建模——更新1——excel箱线图
  2. 字节跳动java面试题,附详细答案解析
  3. 5GNR解调分析手持式频谱分析仪
  4. 用verilog实现数字频率计
  5. 2022电大国家开放大学网上形考任务-国学经典选读(山东)非免费(非答案)
  6. 计算机病毒教学评课,计算机病毒评课稿.pdf
  7. Centos7远程桌面win7
  8. STM32智能小车电路综合实习报告
  9. Linux C聊天室的实现
  10. EMQ X开源版使用