基于PS2索尼游戏手柄开发

最近师妹拿了个PS2手柄给我


安排!!!!
代码下载链接

在32上面 成功用PS2 控制显示屏输出

PS2是一个很好学习通讯时序的的工具
这里写下他的实现代码和我的学习思路

1 2 3 4 5 6 7 8 9
DI/DAT DO/CMD NC VDD GND CS/SEL CLK NC ACK

我们不使用 NC NC ACK 这三个端口

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

我们接线如下
DI PB12 浮空输入 输入 数据
DO PB13 推挽输出 输出 数据

CS PB14 推挽输出 输出 数据
CLK PB15 推挽输出 输出 数据
首先是PS2 初始化 我们将IO配置成对应的模式

void PS2_Init(void)  //PB12 ÊäÈëÏÂÀ­ ÆäËûµÄÍÆÍìÊä³ö
{GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;GPIO_InitStruct.GPIO_Pin= GPIO_Pin_12;GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Mode= GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Pin= GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);
}

然后 我们宏定义了一堆指令 为了简化我们后续的代码
这里用到了正点原子给的 sys.h 的32库

`#define DI   PBin(12)           //PB12 (DI 数据输入位)输入#define DO_H PBout(13)=1        //令PB13 (DO 命令位/数据输出位) 输出高电平
#define DO_L PBout(13)=0        //令PB13 (DO 命令位/数据输出位)输出低电平#define CS_H PBout(14)=1     //令PB14 (CS 使能位)输出拉高
#define CS_L PBout(14)=0     //令PB14 (CS 使能位)输出拉低#define CLK_H PBout(15)=1      //令PB15 (CLK)输出拉高
#define CLK_L PBout(15)=0      //令PB15 (CLK)输出拉低//These are our button constants
#define PSB_SELECT      1
#define PSB_L3          2
#define PSB_R3          3
#define PSB_START       4
#define PSB_PAD_UP      5
#define PSB_PAD_RIGHT   6
#define PSB_PAD_DOWN    7
#define PSB_PAD_LEFT    8
#define PSB_L2         9
#define PSB_R2          10
#define PSB_L1          11
#define PSB_R1          12
#define PSB_GREEN       13
#define PSB_RED         14
#define PSB_BLUE        15
#define PSB_PINK        16
#define PSB_TRIANGLE    13
#define PSB_CIRCLE      14
#define PSB_CROSS       15
#define PSB_SQUARE      26//#define WHAMMY_BAR      8//These are stick values
#define PSS_RX 5              右遥控数据
#define PSS_RY 6#define PSS_LX 7
#define PSS_LY 8
`

再开始命令之前
我们定义一个数组存放我们要发的数据

u16 Handkey;
u8 Comd[2]={0x01,0x42};
u8 Data[9]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

然后我们根据时序图设置我们要发送的代码

DI 是发送 DO 是接收 可以看出
DI DO 一次发送过程有8位 数据
发送的过程中 CS一直处于 低电平
而CLK是每发送一个数据 则发送出一个脉冲 (低电平——高电平)
所以我们根据时序规律写出代码

Tips:volatile是易变型变量,是防止编译器优化代码时假设这个变量的值,保证每次小心地重新读取值。

void PS2_Cmd(u8 CMD)
{volatile u16 ref=0x01;// 定义一个Data[1] = 0; //令数据位1 为0for(ref=0x01;ref<0x0100;ref<<=1) //发送一个8位的数据{if(ref&CMD)   //输入你要发送的数据 如果不是发送为0x00 则拉高电平 准备发送状态DO_H;                 else DO_L;   //否则拉低电平CLK_H;                        //每发送一个指令 给CLK一个>50us电平脉冲 delay_us(50);CLK_L;delay_us(50);CLK_H;  if(DI)             //如果输入得到了高电平Data[1] = ref|Data[1]; //与上一段的数据进行赋值处理}
}

发送数据之后我们紧接着来读取PS2的数据表


这个数据意义顺序对照表的含义是 数据 一共 有 (9位)
首先 我们明白 英文含义 idle 空置 data 数据位置
DO 代表输出 输出指向手柄 (遥控)输出 DI 代表 向手柄接收器输入

    我们先从 DO来看 第一位: 向遥控输出 0x01第二位: 向遥控输出 0x42第三位: 向遥控输出  0x00 既 NULL 、空 、 闲置第四位: 向遥控输出  左电机参数第五位: 向遥控输出  右电机参数第六位: 向遥控输出  0x00 既 NULL 、空 、 闲置第七位: 向遥控输出  0x00 既 NULL 、空 、 闲置第八位: 向遥控输出  0x00 既 NULL 、空 、 闲置第九位: 向遥控输出  0x00 既 NULL 、空 、 闲置然后再从 DI来看 第一位: 接收器得到    0x00 既 NULL 、空 、 闲置第二位: 接收器得到    接收器得到遥控器上面的ID第三位: 接收器得到  0X5A ...(未知这个数据有什么用)第四位: 接收器得到   SELECT L3 R3 START  UP RIGHT DOWN LEFT  这8个按键的数值 (正好8个 对应8个数据位置)第五位: 接收器得到  L3 R2 L1 R1  三角形 圆形  X 正方形  这8个按键的数值 (正好8个 对应8个数据位置)第六位: 接收器得到   右遥杆 X值的坐标 可以看到 0X00 是指左边  0XFF 指指向右边  从左到右边 分了 0 ~255 个数值第七位: 接收器得到   右遥杆 Y值的坐标 可以看到 0X00 是指上边  0XFF 指指向下边  从上到下边 分了 0 ~255 个数值第八位: 接收器得到  左遥杆 X值的坐标 可以看到 0X00 是指左边  0XFF 指指向右边  从左到右边 分了 0 ~255 个数值第九位: 接收器得到   左 遥杆 Y值的坐标 可以看到 0X00 是指上边  0XFF 指指向下边  从左到右边 分了 0 ~255 个数值
void PS2_ReadData(void)
{volatile u8 byte=0;volatile u16 ref=0x01;CS_L;  //拉低电平表示准备要来数据了PS2_Cmd(Comd[0]);   //0X01PS2_Cmd(Comd[1]);   //0X02for(byte=2;byte<9;byte++)     //发送6次 从2开始是因为指引数组{for(ref=0x01;ref<0x100;ref<<=1)   //循环8次 不断左移 1 位{CLK_H;    //脉冲CLK_L;delay_us(50);CLK_H;if(DI)  //收到DI的数据Data[byte] = ref|Data[byte];  //把脉冲数据保存下来}delay_us(50);}CS_H;
}

判断PS2是否为红灯状态 (红灯状态不工作)

u8 PS2_RedLight(void)
{CS_L;  //低电平 告诉 PS2_Cmd(Comd[0]);  //发送第一个通信码PS2_Cmd(Comd[1]);  //发送第二个通信码CS_H;if( Data[1] == 0X73)   return 0 ; //0X41 表示绿灯 0X73表示红灯else return 1
}

读取手柄数据

void PS2_ReadData(void)
{volatile u8 byte=0; //  volatile防止比特位数据被修改 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)  //循环8次 每一次 脉冲一个字节{CLK_H;     DELAY_TIME;CLK_L;DELAY_TIME;CLK_H;if(DI)Data[byte] = ref|Data[byte];//存储数据}delay_us(16);  //接收数据处理时间}CS_H; //高电平
}

得到摇杆值的模拟量 范围 0 ~ 255

u8 PS2_AnologData(u8 button)
{return Data[button];
}

清空数据缓冲区

void PS2_ClearData()   //将数组的数据全部清理为0
{u8 a;for(a=0;a<9;a++)Data[a]=0x00;
}

手柄振动函数
Motor1 右侧小 振动电机 0X00 关 其他开
Motor2 左侧大 振动电机 0x40 ~ 0XFF 电机开 值越大 振动越大

void PS2_Vibration(u8 motor1, u8 motor2)
{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);
}

简短刷新连接函数(?)

//short poll
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();      //完成并且保存配置

分割线
下面是 我的主函数

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "pstwo.h"u8 x=0;int main(void){  u8 angle=0;  u8 key=0;u8 lcd_id[12];         delay_init();       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); uart_init(115200);   LED_Init();              LCD_Init();LCD_Clear(BLACK);PS2_Init();    sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);LED1=1;LED0=1;   PS2_SetInit(); while(1) {       sprintf((char*)lcd_id,"KEY :%04X",key);LCD_ShowString(30,40,210,24,24,"SHOW TIME !! "); x  = key%10;switch(x){case 0:LCD_Clear(WHITE);delay_ms(10);;break;case 1:LCD_Clear(BLACK);delay_ms(10);break;case 2:LCD_Clear(BLUE);delay_ms(10);break;case 3:LCD_Clear(RED);delay_ms(10);break;case 4:LCD_Clear(MAGENTA);delay_ms(10);break;case 5:LCD_Clear(GREEN);delay_ms(10);break;case 6:LCD_Clear(CYAN);delay_ms(10);break;case 8:LCD_Clear(YELLOW);delay_ms(10);break;case 9:LCD_Clear(BRRED);delay_ms(10);break;case 10:LCD_Clear(GRAY);delay_ms(10);break;case 11:LCD_Clear(LGRAY);delay_ms(10);break;}key=PS2_DataKey();sprintf((char*)lcd_id,"PS2::%04X",key); POINT_COLOR=RED;    LCD_ShowString(30,110,200,16,16,lcd_id);       PS2_ReadData();  angle = (PS2_AnologData(PSS_RX)/5)*3+15; delay_ms(1);if(key!=0)LED1=!LED1;}
}

【STM32 嵌入式设计】PS2索尼游戏手柄解析和代码开发相关推荐

  1. STM32嵌入式系统FreeRTOS使用cJSON解析和构建JSON

    一.环境 控制器STM32F407+MDK5.34+cJSON1.7.7 二.安装cJSON MDK中打开Pack Install,选择Generic下边MDK-Pack::cJSON,点击安装Ins ...

  2. 索尼游戏手柄SP2的开发体会

    索尼游戏手柄SP2的开发体会 1.PS手柄介绍 接收器引脚输出: 通信时序: 2.代码解读 3.库文件解读 ps2手柄是索尼的PlayStation2游戏机的遥控手柄. 该款手柄的通讯协议被游戏爱好者 ...

  3. verilog实例_Verilog设计与逻辑综合实例解析(含代码)(Tasks amp;Functions)

    1.function中的逻辑被综合成了什么? 由于function中没有任何时序结构,function只能综合出组合逻辑. 例如,以下function有2个输入信号和一个控制信号,输出算术运算结果. ...

  4. 计算机三级嵌入式试题讲解,计算机三级嵌入式系统操作题及解析.docx

    PAGE PAGE # 计算机三级嵌入式系统操作题及解析 操作题(一) 1地铁进出站闸机的控制器以 S3C2410芯片为核心,并外加其他功能电 路来进行设计,其基本功能描述如下: a闸机能够识别本地铁 ...

  5. 蓝桥杯嵌入式设计与开发历届客观题答案

    该页面由pdf转换而来,阅读效果不佳,你可以在这里下载pdf原件:https://download.csdn.net/download/dvs_dn/85085622 你也可以在百度文库免费下载该文档 ...

  6. 第十二届省赛嵌入式设计与开发《停车计费系统》

    前言 刷了几套蓝桥杯省赛程序题目,心有所感,故写下文章记录一下,本篇文章记录的是第十二届省赛嵌入式设计与开发程序设计题目. 这套题的考察重点和难点在STM32的串口和字符串的处理,难点在于细节方面,对 ...

  7. c语言自定义函数程序设计,ch3自定义函数设计 C语言 《解析C程序设计》.ppt

    ch3自定义函数设计 C语言 <解析C程序设计> 全局变量--外部变量 在函数外定义的变量 有效范围:从定义变量的位置开始到本源文件结束,及有extern声明的其它源文件 存储类型:缺省e ...

  8. Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战

    Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战 Java生鲜电商平台-  什么是秒杀 通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动 比如说京东秒杀,就是一种定时定量秒杀,在规定 ...

  9. Java生鲜电商平台-促销系统的架构设计与源码解析

    Java生鲜电商平台-促销系统的架构设计与源码解析 说明:本文重点讲解现在流行的促销方案以及源码解析,让大家对促销,纳新有一个深入的了解与学习过程. 促销系统是电商系统另外一个比较大,也是比较复杂的系 ...

最新文章

  1. Google Test(GTest)使用方法和源码解析——预处理技术分析和应用
  2. 异步方法顺序调用问题
  3. 带你一起学kivy第一天
  4. 新上映的电影不在影院也一样能看到
  5. 第一讲,Python的安装(干货)
  6. Chapter7-12_Controllable Chatbot
  7. Java(1-15)
  8. Java多线程学习四十:如何写一个必然死锁的例子
  9. Typora列表段落(list paragraph)的行间距
  10. 列车座位应考虑向后摆放
  11. APP分发渠道的竞争分析
  12. IMazing for Mac破解版永久激活方法
  13. 结对作业 ——UI组第八组 冯富禹 齐天浩
  14. Autumn Web Handler
  15. 在网页前端调用exe程序并传参
  16. emlog模板酷黑自适应CoolBlack主题 黑的有质感
  17. Android 启动“无启动图标的 apk“
  18. 使用ASP.NET.MVC制作手机接收验证码
  19. 当老板让我从 Java8 升到 Java11
  20. python发微信提醒天气冷了注意保暖_提醒人注意保暖的句子 天气冷了注意保暖句子...

热门文章

  1. CRC16-CCITT 的算法
  2. Apache Commons Email 怎样设置接收方发送已读回执?
  3. 分享几款超好用的 REST API 工具
  4. 使用IDEA创建Maven项目一直卡在Generating project in Batch mode
  5. Grounding DINO-开集目标检测论文解读
  6. 使用GetData Graph Digitizer,没有坐标界面出现。
  7. matlab梁结点,用matlab编程对无限梁设计
  8. 大牧絮叨设计模式:抽象工厂模式
  9. MATLAB概率密度函数和累积分布函数指令
  10. 这两年大家都在吃瘪,结果微软他闷声发大财了?!