文章目录
- 前言
- 一、cubemx配置
- 二、代码
- 1.引入库
- bsp_hal_ps2.c
- bsp_hal_ps2.h
- 2.主函数
前言
本文讲解使用cubemx配置PS2手柄实现对手柄的按键和模拟值的读取。
很简单,库已经封装好了,直接就可以了。
文件
一、cubemx配置
这个很简单,不需要走协议,只要配置gpio就可以了
二、代码
1.引入库
使用我的两个库
bsp_hal_ps2.c
/* 包含头文件 ----------------------------------------------------------------*/
#include "bsp_hal_ps2.h"
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
#define DI() HAL_GPIO_ReadPin(PS2_DI_GPIO_Port, PS2_DI_Pin) //PB12 输入
#define DO_H() HAL_GPIO_WritePin(PS2_DO_CMD_GPIO_Port, PS2_DO_CMD_Pin, GPIO_PIN_SET) //命令位高
#define DO_L() HAL_GPIO_WritePin(PS2_DO_CMD_GPIO_Port, PS2_DO_CMD_Pin, GPIO_PIN_RESET) //命令位低
#define CS_H() HAL_GPIO_WritePin(PS2_CS_SEL_GPIO_Port, PS2_CS_SEL_Pin, GPIO_PIN_SET) //CS拉高
#define CS_L() HAL_GPIO_WritePin(PS2_CS_SEL_GPIO_Port, PS2_CS_SEL_Pin, GPIO_PIN_RESET) //CS拉低
#define CLK_H() HAL_GPIO_WritePin(PS2_CLK_GPIO_Port, PS2_CLK_Pin, GPIO_PIN_SET) //时钟拉高
#define CLK_L() HAL_GPIO_WritePin(PS2_CLK_GPIO_Port, PS2_CLK_Pin, GPIO_PIN_RESET) //时钟拉低
/* 私有变量 ------------------------------------------------------------------*/
const uint8_t Comd[2]={0x01,0x42}; //开始命令。请求数据
const uint16_t MASK[16] = {
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
}; //按键值与按键明
/* 扩展变量 ------------------------------------------------------------------*/
_u_PS2_Data PS2_Data={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //数据存储数组
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
static void delay_us(int16_t us)
{
for(int i=0; i<us*10; i++)
{
;
}
}
//向手柄发送命令
static uint8_t PS2_Cmd(uint8_t CMD)
{
volatile uint16_t ref=0x01;
uint8_t Data;
Data = 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 = ref|Data;
}
}
return Data;
}
//short poll
static 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);
}
//进入配置
static 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);
}
//发送模式设置
static 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);
}
//振动设置
static 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);
}
//完成并保存配置
static 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_ClearData(void)
{
PS2_Data.DATE.ID = 0;
PS2_Data.DATE.verify = 0;
PS2_Data.DATE.key1_U.byte = 0xff;
PS2_Data.DATE.key2_U.byte = 0xff;
PS2_Data.DATE.PSS_RX = 0;
PS2_Data.DATE.PSS_RY = 0;
PS2_Data.DATE.PSS_LX = 0;
PS2_Data.DATE.PSS_LY = 0;
}
//判断是否为红灯模式
//返回值;0,红灯模式
// 其他,其他模式
uint8_t PS2_RedLight(void)
{
uint8_t Data;
CS_L();
PS2_Cmd(Comd[0]); //开始命令
Data = PS2_Cmd(Comd[1]); //请求数据
CS_H();
PS2_Data.DATE.ID = Data;
if( Data == 0X73) return 0 ;
else return 1;
}
//读取手柄数据
void PS2_ReadData(void)
{
volatile uint8_t byte=0;
volatile uint16_t ref=0x01;
uint8_t data;
CS_L();
PS2_Cmd(Comd[0]); //开始命令
PS2_Data.DATE.ID = PS2_Cmd(Comd[1]); //请求数据
for(byte=1;byte<8;byte++) //开始接受数据
{
data = 0;
for(ref=0x01;ref<0x100;ref<<=1)
{
CLK_H();
delay_us(10);
CLK_L();
delay_us(10);
CLK_H();
if(DI())
{
data = ref|data;
}
}
PS2_Data.byte[byte] = data;
delay_us(16);
}
CS_H();
}
//对读出来的PS2的数据进行处理
//只处理了按键部分
//默认数据是红灯模式 只有一个按键按下时
//按下为0, 未按下为1
uint8_t PS2_DataKey(void)
{
uint8_t index;
uint16_t Handkey;
PS2_ClearData();
PS2_ReadData();
if(PS2_Data.DATE.verify == 0x5a)
{
Handkey=(PS2_Data.byte[3]<<8)|PS2_Data.byte[2]; //这是16个按键 按下为0, 未按下为1
for(index=0;index<16;index++)
{
if((Handkey&(1<<(MASK[index]-1)))==0)
{
return index+1;
}
}
}
return 0; //没有任何按键按下
}
//得到一个摇杆的模拟量 范围0~256
//返回1得取成功,0得取失败
uint8_t PS2_AnologData(_e_RockerSelect button,uint8_t *qdata)
{
PS2_ClearData();
PS2_ReadData();
if(PS2_Data.DATE.verify == 0x5a)
{
if(button == PSS_RX) *qdata = PS2_Data.DATE.PSS_RX;
else if(button == PSS_RY) *qdata = PS2_Data.DATE.PSS_RY;
else if(button == PSS_LX) *qdata = PS2_Data.DATE.PSS_LX;
else *qdata = PS2_Data.DATE.PSS_LY;
return 1;
}
else
{
return 0;
}
}
/******************************************************
Function: void PS2_Vibration(uint8_t motor1, uint8_t motor2)
Description: 手柄震动函数,
Calls: void PS2_Cmd(uint8_t CMD);
Input: motor1:右侧小震动电机 0x00关,其他开
motor2:左侧大震动电机 0x40~0xFF 电机开,值越大 震动越大
******************************************************/
void PS2_Vibration(uint8_t motor1, uint8_t 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);
}
//手柄配置初始化
void PS2_SetInit(void)
{
CS_H();
CLK_H();
DO_H();
PS2_ShortPoll();
PS2_ShortPoll();
PS2_ShortPoll();
PS2_EnterConfing(); //进入配置模式
PS2_TurnOnAnalogMode(); //“红绿灯”配置模式,并选择是否保存
PS2_VibrationMode(); //开启震动模式
PS2_ExitConfing(); //完成并保存配置
CS_H();
CLK_H();
DO_H();
}
bsp_hal_ps2.h
#ifndef __BSP_HAL_PS2_H__
#define __BSP_HAL_PS2_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include "main.h"
/* 宏定义 --------------------------------------------------------------------*/
//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
/* 类型定义 ------------------------------------------------------------------*/
typedef enum
{
PSS_RX = 0,
PSS_RY,
PSS_LX,
PSS_LY,
}_e_RockerSelect;
typedef union
{
uint8_t byte;
struct
{
uint8_t SELECT :1;
uint8_t L3 :1;
uint8_t R3 :1;
uint8_t START :1;
uint8_t UP :1;
uint8_t RIGHT :1;
uint8_t DOWN :1;
uint8_t LEFT :1;
}bit;
}_u_key1;
typedef union
{
uint8_t byte;
struct
{
uint8_t L2 :1;
uint8_t R2 :1;
uint8_t L1 :1;
uint8_t R1 :1;
uint8_t TRI :1;
uint8_t CIRCLE :1;
uint8_t FORK :1;
uint8_t REC :1;
}bit;
}_u_key2;
typedef union
{
uint8_t byte[8];
struct
{
uint8_t ID;
uint8_t verify;
_u_key1 key1_U;
_u_key2 key2_U;
uint8_t PSS_RX;
uint8_t PSS_RY;
uint8_t PSS_LX;
uint8_t PSS_LY;
}DATE;
}_u_PS2_Data;
/* 扩展变量 ------------------------------------------------------------------*/
extern _u_PS2_Data PS2_Data;
/* 函数声明 ------------------------------------------------------------------*/
void PS2_SetInit(void);
void PS2_ClearData(void);
void PS2_ReadData(void);
void PS2_Vibration(uint8_t motor1, uint8_t motor2);
uint8_t PS2_AnologData(_e_RockerSelect button,uint8_t *qdata);
uint8_t PS2_DataKey(void);
uint8_t PS2_RedLight(void);
#endif // __BSP_HAL_PS2_H__
2.主函数
初始化
PS2_SetInit();
uint8_t a;
主循环
if( !PS2_RedLight())
{//判断手柄是否为红灯模式,是,指示灯LED点亮
HAL_Delay(50); //延时很重要不可去
for(a=0; a<8; a++)//清除数据缓冲区
PS2_Data.byte[a] = 0x00;
PS2_ReadData();
// y_axisbuff = (128 - PS2_Data.DATE.PSS_LY)*2;//最高速度256
// x_axisbuff = (PS2_Data.DATE.PSS_LX - 128)*2;
// yawbuff = ( -128+PS2_Data.DATE.PSS_RX)*2;
// if(ABS(y_axisbuff) < 50) y_axisbuff = 0; //限制遥控中间位置的误差
// if(ABS(yawbuff) < 50) yawbuff = 0;
// if(ABS(x_axisbuff) < 50) x_axisbuff = 0;
}
else
{//判断手柄不是红灯模式,指示灯LED熄灭
PS2_ClearData();
}
HAL_Delay(50);