外观和电气连接

外观

手柄外观如下

接收器外观

这是接收器和底座

电气连接

需要4根连接线

单片机输出是CLK DO CS

单片机输入是DI

电源电压是3.3-5v

注意模块和单片机共地

模块不支持高速,最大时钟周期约为4us左右

因此使用软件模拟时序的方式来与模块通信

只需要将模块的4根线与单片机软件中对应的GPIO连接起来就行了

#define PS2_CS_GPIOx GPIOA
#define PS2_CS_Pin GPIO_PIN_4#define PS2_CLK_GPIOx GPIOA
#define PS2_CLK_Pin GPIO_PIN_5#define PS2_DO_GPIOx GPIOA
#define PS2_DO_Pin GPIO_PIN_7#define PS2_DI_GPIOx GPIOA
#define PS2_DI_Pin GPIO_PIN_6

软件设计

HAL初始化

需要 3个推挽输出模式的GPIO 分别是 CLK DO CS

1个上拉输入模式 DI

协议分析

cs拉低开始单片机与模块的通信,拉高则通信结束

DO,DI在在CLK时钟的下降沿完成数据的发送和读取

本协议是类似SPI的协议

通信一共9个字节

这里的DODI指的是单片机的GPIO名称

Byte 功能
0 DO->0x01 DI <-(无意义)
1 DO->0x42 DI<-(红灯0x73 无灯0X41)
2 DO->0xFF DI<-0X5A
3-8 DO->0xFF DI<-(按键数据)

按键数据如下

按键分析

手柄发送来的有两种模式的数据

无灯模式(MOD LED不亮)发送的摇杆是数字量,摇杆左右两侧的四向按键功能和摇杆重合

即如下图

红灯模式(MODE LED亮红灯)

模块传输的是摇杆的模拟量

外侧大按键独立

代码

为了方便建立了一个结构体来存储按键的数据,代码有注释,请根据设备自行测试是哪个按键即可

typedef struct
{uint8_t A_D;                                       //模拟(红灯)为1 数字(无灯)为0int8_t Rocker_RX, Rocker_RY, Rocker_LX, Rocker_LY; //摇杆值(模拟状态为实际值0-0xFF)(数字态为等效的值0,0x80,0xFF)//按键值0为未触发,1为触发态uint8_t Key_L1, Key_L2, Key_R1, Key_R2;                //后侧大按键uint8_t Key_L_Right, Key_L_Left, Key_L_Up, Key_L_Down; //左侧按键uint8_t Key_R_Right, Key_R_Left, Key_R_Up, Key_R_Down; //右侧按键uint8_t Key_Select;                                    //选择键uint8_t Key_Start;                                     //开始键uint8_t Key_Rocker_Left, Key_Rocker_Right;             //摇杆按键} PS2_TypeDef;
extern PS2_TypeDef PS2_Data;
#include "PS2.h"
uint8_t PS2_RawData[9] = {0};
PS2_TypeDef PS2_Data = {0};
void PS2_CS(uint8_t Val)
{if (Val)HAL_GPIO_WritePin(PS2_CS_GPIOx, PS2_CS_Pin, GPIO_PIN_SET);elseHAL_GPIO_WritePin(PS2_CS_GPIOx, PS2_CS_Pin, GPIO_PIN_RESET);
}
void PS2_CLK(uint8_t Val)
{if (Val)HAL_GPIO_WritePin(PS2_CLK_GPIOx, PS2_CLK_Pin, GPIO_PIN_SET);elseHAL_GPIO_WritePin(PS2_CLK_GPIOx, PS2_CLK_Pin, GPIO_PIN_RESET);
}
void PS2_DO(uint8_t Val)
{if (Val)HAL_GPIO_WritePin(PS2_DO_GPIOx, PS2_DO_Pin, GPIO_PIN_SET);elseHAL_GPIO_WritePin(PS2_DO_GPIOx, PS2_DO_Pin, GPIO_PIN_RESET);
}
uint8_t PS2_Read_DI()
{return HAL_GPIO_ReadPin(PS2_DI_GPIOx, PS2_DI_Pin);
}
void PS2_Delay()
{for (int i = 0; i < 0xBf; i++)__nop();
}
uint8_t PS2_ReadWrite_Byte(uint8_t TxData)
{uint8_t TX = TxData;uint8_t RX = 0;for (int i = 0; i < 8; i++){if (TX & 0x01)PS2_DO(1);elsePS2_DO(0);TX >>= 1;PS2_CLK(1);PS2_Delay();PS2_CLK(0);RX >>= 1;RX |= (PS2_Read_DI() << 7);PS2_Delay();PS2_CLK(1);PS2_Delay();}return RX;
}void PS2_Decode()
{if (PS2_RawData[2] == 0x5A){PS2_Data.Key_Select = (~PS2_RawData[3] >> 0) & 0x01; //选择键PS2_Data.Key_Start = (~PS2_RawData[3] >> 3) & 0x01;  //开始键//左侧按键PS2_Data.Key_L_Up = (~PS2_RawData[3] >> 4) & 0x01;PS2_Data.Key_L_Right = (~PS2_RawData[3] >> 5) & 0x01;PS2_Data.Key_L_Down = (~PS2_RawData[3] >> 6) & 0x01;PS2_Data.Key_L_Left = (~PS2_RawData[3] >> 7) & 0x01;//后侧按键PS2_Data.Key_L2 = (~PS2_RawData[4] >> 0) & 0x01;PS2_Data.Key_R2 = (~PS2_RawData[4] >> 1) & 0x01;PS2_Data.Key_L1 = (~PS2_RawData[4] >> 2) & 0x01;PS2_Data.Key_R1 = (~PS2_RawData[4] >> 3) & 0x01;//右侧按键PS2_Data.Key_R_Up = (~PS2_RawData[4] >> 4) & 0x01;PS2_Data.Key_R_Right = (~PS2_RawData[4] >> 5) & 0x01;PS2_Data.Key_R_Down = (~PS2_RawData[4] >> 6) & 0x01;PS2_Data.Key_R_Left = (~PS2_RawData[4] >> 7) & 0x01;if (PS2_RawData[1] == 0x41){ //无灯模式(摇杆值八向)PS2_Data.Rocker_LX = 127 * (PS2_Data.Key_L_Right - PS2_Data.Key_L_Left);PS2_Data.Rocker_LY = 127 * (PS2_Data.Key_L_Up - PS2_Data.Key_L_Down);PS2_Data.Rocker_RX = 127 * (PS2_Data.Key_R_Right - PS2_Data.Key_R_Left);PS2_Data.Rocker_RY = 127 * (PS2_Data.Key_R_Up - PS2_Data.Key_R_Down);}else if (PS2_RawData[1] == 0x73){ //红灯模式(摇杆值模拟)//摇杆按键PS2_Data.Key_Rocker_Left = (~PS2_RawData[3] >> 1) & 0x01;PS2_Data.Key_Rocker_Right = (~PS2_RawData[3] >> 2) & 0x01;//摇杆值PS2_Data.Rocker_LX = PS2_RawData[7] - 0x80;PS2_Data.Rocker_LY = -1 - (PS2_RawData[8] - 0x80);PS2_Data.Rocker_RX = PS2_RawData[5] - 0x80;PS2_Data.Rocker_RY = -1 - (PS2_RawData[6] - 0x80);}}
}
void PS2_Read_Data(void)
{PS2_CS(0);PS2_RawData[0] = PS2_ReadWrite_Byte(0x01); // 0PS2_RawData[1] = PS2_ReadWrite_Byte(0x42); // 1for (int i = 2; i < 9; i++)PS2_RawData[i] = PS2_ReadWrite_Byte(0xff);PS2_CS(1);PS2_Decode();
}

手柄的效果还可以,对得起25元的价格

可以二次开发做成遥控车遥控器或者电脑手柄

成品

Github

【STM32F4系列】【HAL库】【自制库】ps2手柄模块驱动相关推荐

  1. stm32cube,hal库来实现PS2手柄数据发送

    stm32cube,hal库来实现PS2手柄数据发送 很久前买了个PS2的手柄,如下,之前 以前不会使用cube来配置工程,导致写程序很麻烦,对我这样的新手很不友好,看卖家提供的程序也很麻烦,拉高拉低 ...

  2. STM32F4系列HAL库配置定时器实验——输入捕获

    STM32F4系列HAL库配置定时器实验--输入捕获 输入捕获简单讲解 输入捕获模式可以用来测量脉冲宽度或者测量频率.我们以测量周期和频率为例,用一个简图来说明输入捕获的原理 假定定时器工作在向上计数 ...

  3. STM32F4系列 HAL Flash 读写

    前言 注意:F0F1系列和F4系列的Flash读写操作不相同 一.STM32CubeMX怎么查看芯片的Flash分布? 二.擦除F4系列Flash 本例程使用的是F411CEU6的型号芯片 1.擦除F ...

  4. 【树莓派C语言开发】实验14:PS2游戏手柄模块(关联PCF8591)

    本次实验还是需要用到PCF8591模数转换器,莫非它要取代双色LED成为新的常驻嘉宾吗? 本次实验是摇杆实验.这个玩意可以用于操控机器人或者是树莓派的遥控小车.当然,生活中最常见的用途还是在游戏手柄上 ...

  5. 【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)

    文章目录 相关链接 协议 外设设置 硬件PWM 分析 HAL设置 DMA 分析 HAL设置 方案设计 代码实现 解码函数 开始发送和复位 发送函数 波形 成品 相关链接 硬件介绍(PCB设计方案) 模 ...

  6. STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例)

    STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例) 目录 STM32CubeMX | STM32 F1系列HAL库低功耗 ...

  7. STM32F1系列HAL库配置系统时钟

    STM32F1系列HAL库配置系统时钟 其实一开始对于时钟我也是知之甚少,在MSP432中我就一直忽视时钟配置,其实也是在STM32学习时落下的病根,现在趁有空补一下. 时钟简单讲解 对于时钟系统,在 ...

  8. STM32系列(HAL库)——F103C8T6通过MFRC522、RFID射频卡、门禁卡模块读取卡片ID(二)

    本文继上一篇:STM32系列(HAL库)--F103C8T6通过MFRC522.RFID射频卡.门禁卡模块读取卡片ID 本文介绍在运用RC522模块时,运用链表结构存储数据的操作 Let's go! ...

  9. Python数据分析学习系列 十三 Python建模库介绍

    Python数据分析学习系列 十三 Python建模库介绍 资料转自(GitHub地址):https://github.com/wesm/pydata-book 有需要的朋友可以自行去github下载 ...

最新文章

  1. OSS正式支持IPv6公测
  2. gdb C++程序coredump不显示行号问题
  3. .NET CORE(C#) WPF 抽屉式菜单
  4. HP-JavaUtil: xls 操作类
  5. 浅谈C#中virtual和abstract的区别
  6. Tech.Ed 2011微软技术大会(二)之专题讲座
  7. Java List retainAll方法使用注意事项
  8. android数据线接口分类,安卓手机数据线接口类型
  9. oracle 时间段加减,ORACLE 时间加减操作
  10. linux 脚本 过滤 词,linux学习之shell脚本 - 文本过滤
  11. 智慧政务说明书 督察督办(八)
  12. 在控制面板找不到程序的情况下,卸载流氓软件
  13. 计算机组成原理 | 第八章《计算机的外围设备》、第九章《输入/输出系统》 学习笔记
  14. 优化新闻管理系统(分层)+代码封装
  15. 百炼---大数的乘法
  16. linux怎么安装echo命令,如何在Linux上使用Echo命令 | MOS86
  17. 商机管理细化直击销售进展难点,激发销售业绩驱动企业规模化增长!
  18. 计算机专业公务员三不限,心疼这些专业的同学,考公务员只能“三不限”,找工作也难...
  19. iOS音频采集过程中的音效实现
  20. Leaflet中使用draw绘制时获取图形的几何信息

热门文章

  1. 论文分析与讲解思路(2)--PGCN
  2. 群创15.6寸工业屏G156HCE-E01-15.6寸EDP接口
  3. 惠普t5000微型计算机价格,hp5000
  4. 华为认证证书对找工作有帮助吗?
  5. 地图编辑器开发(五)
  6. html 列表标签 ul ol dl
  7. 什么是web3.0?涉及到哪些方面?
  8. KPI, Metrics, KPI的区别
  9. Python OpenCV 图像匹配(Brute-Force与FLANN)的原理与代码实现
  10. k8s自定义资源CRD