这几天学习用STM32 HAL库,发现用HID USB 实在是太方便了,刚好手头有一副并口PS手柄,于是试着改成USB手柄。
采取STM32读取PS手柄数据,再通过USB发送给PC的方案。
首先拆开PS手柄,PS手柄共有7根线,和STM连接方式如下:
手柄端: STM32端:
红:VCC 3-5V
黑:GND
黄:ATT ------------------------------------ PB.14(选择线,由单片机输出)
橙:COMMAND-----------------------------PD.10(命令线,由单片机输出)
棕:DATA----------------------------------- PD.8(数据线,由手柄输出)
蓝:CLOCK ---------------------------------PD.12(时钟线,由单片机输出)
绿:ACK (这根线可以不用连接)
单片机引脚:PB.14 PD.10 PD.12设置成推挽输出, PD.8 设置为上拉输入
打开STM32CubeMx软件,配置好引脚和时钟,USB_DEVICE里面选着Human Interface Device Class(HID),其他的全部默认即可。
关键部位修改
usbd_hid.c文件里的报告描述符:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x10, // USAGE_MAXIMUM (Button 16)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x10, // REPORT_COUNT (16)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x32, // USAGE (Z)
0x09, 0x33, // USAGE (Rx)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
usbd_hid.h文件里面:
#define HID_MOUSE_REPORT_DESC_SIZE 46 //这个值根据报告描述符修改
PS手柄读取:
uint8_t res[5]; //保存手柄返回值
uint8_t PSInOut(uint8_t data); //手柄的命令发送,数据接收
uint8_t HIDBuffer[6]; //USB的数据缓冲区
//PS手柄读写函数,data参数为0表示只读数据
uint8_t PSInOut(uint8_t data)
{
volatile uint8_t res =0;//保存读取的一个字节
volatile uint8_t j = 1;
volatile uint8_t temp = data;
//循环读写一个字节
for(int i=0;i<8;i++)
{
HAL_GPIO_WritePin(CLOCK_GPIO_Port,CLOCK_Pin,GPIO_PIN_RESET);//CLK = 0;
HAL_Delay(1);
if(temp !=0)
{
if(data&0X01)
HAL_GPIO_WritePin(COMMAND_GPIO_Port,COMMAND_Pin,GPIO_PIN_SET);//CMND = 1;
else
HAL_GPIO_WritePin(COMMAND_GPIO_Port,COMMAND_Pin,GPIO_PIN_RESET);//CMND = 0;
data = data >>1;
}
if(HAL_GPIO_ReadPin(DATA_GPIO_Port,DATA_Pin)==GPIO_PIN_SET)//DATA == 1
res = res +j;
j = j<<1;
HAL_Delay(1);
HAL_GPIO_WritePin(CLOCK_GPIO_Port,CLOCK_Pin,GPIO_PIN_SET);//CLK = 1;
HAL_Delay(2);
}
return res;
}
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_WritePin(ATT_GPIO_Port,ATT_Pin,GPIO_PIN_RESET);//ATT = 0;
res[0]=PSInOut(0x01);//开始
res[1]=PSInOut(0x42);//请求数据,数字手柄返回0X41
//参数0,表示只接收PS的数据
res[2]=PSInOut(0);//返回值0X5A
res[3]=PSInOut(0);//BIT7--BIT0(LEFT,DOWN,RIGHT,UP,START,,,SELECT)
res[4]=PSInOut(0);//BIT7--BIT0(□,X,○,△,R1,L1,R2,L2)
HAL_GPIO_WritePin(ATT_GPIO_Port,ATT_Pin,GPIO_PIN_SET);//ATT = 1;
//将按键值转换到usb发送缓冲区
//USB缓冲器低2字节为16个按键,第3个和第4个为X,Y坐标
HIDBuffer[0] = res[4];
HIDBuffer[1] = res[3]|0xF6;
//将十字按键转换成X,Y坐标
uint8_t temp = res[3] & 0xF0;
switch(temp)
{
case 0xF0:
HIDBuffer[2]=0;
HIDBuffer[3]=0;
break;
case 0xe0://上
HIDBuffer[3] = 0x81;
break;
case 0xb0://下
HIDBuffer[3] = 0x7F;
break;
case 0x70://左
HIDBuffer[2] = 0x81;
break;
case 0xd0://右
HIDBuffer[2] = 0x7F;
break;
default:
break;
}
//向PC发送数据
USBD_HID_SendReport(&hUsbDeviceFS,HIDBuffer,6);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
|
|