前提:
准备一个STM32F407ZG的探索者开发板,一个双轴按键摇杆传感器模块(可自行在某宝上搜索)。
游戏手柄点位控制图:
实验目的:
利用USB外设实现游戏手柄的简易功能,通过USB将设备与电脑连接,简单控制小游戏。本次实验采用5个按键分别控制游戏手柄的X键、Y键、A键、B键、右侧摇杆键,使用两路ADC检测右侧摇杆的x坐标和y坐标,进而控制前后左右。
一、使用STM32CubeMX生成HID代码
1.1.打开STM32CubeMX,并点击ACCESS TO MCU SELECTOR
1.2.选择芯片型号
1.3.添加5个按键(暂时先用5个测试),依据原理图配置上下拉,分别用于控制游戏手柄的 X键、Y键、A键、B键、右操作摇杆键。
1.4.配置RCC,选择外部晶振作为时钟源
1.5.配置两路ADC(暂时先用2路测试)
1.6.选择USB接口
1.7.配置USB设备
1.8.配置时钟
1.9.配置Project Manager
1.10.生成工程
二、修改usbd_hid.c
2.1.将默认的报告描述符改成需要的游戏手柄报告描述符:找到usbd_hid.c中的HID_MOUSE_ReportDesc数组,并按需求将以下代码将其替换:
__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, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
替换结果:
2.2.将HID_MOUSE_REPORT_DESC_SIZE改成HID_MOUSE_ReportDesc的实际大小
三、修改main.c
在main.c中增加编写按键扫描与处理以及ADC通道值获取功能并调用,最后将获取的按键值和8位的ADC值发送到主机,具体代码如下:
#include "main.h"
#include "adc.h"
#include "usb_device.h"
#include "gpio.h"
#include "usbd_hid.h"
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
extern USBD_HandleTypeDef hUsbDeviceFS;
/* KEY端口定义 */
#define KEY_X HAL_GPIO_ReadPin(KEY_X_GPIO_Port, KEY_X_Pin)
#define KEY_Y HAL_GPIO_ReadPin(KEY_Y_GPIO_Port, KEY_Y_Pin)
#define KEY_A HAL_GPIO_ReadPin(KEY_A_GPIO_Port, KEY_A_Pin)
#define KEY_B HAL_GPIO_ReadPin(KEY_B_GPIO_Port, KEY_B_Pin)
#define KEY_RIGHT HAL_GPIO_ReadPin(KEY_RIGHT_GPIO_Port, KEY_RIGHT_Pin)
#define KEYX_PRES 1 /* KEY_X 按下 */
#define KEYY_PRES 2 /* KEY_Y 按下 */
#define KEYA_PRES 3 /* KEY_A 按下 */
#define KEYB_PRES 4 /* KEY_B 按下 */
#define KEYRIGHT_PRES 5 /* KEY_RIGHT 按下*/
/*
* sendbuf[0]~sendbuf[1]:按键
* sendbuf[2]:左侧摇杆x坐标
* sendbuf[3]:左侧摇杆y坐标
* sendbuf[4]:右侧摇杆x坐标
* sendbuf[5]:右侧摇杆y坐标
*/
unsigned char sendbuf[6]={0x00,0x00,0x80,0x80,0x80,0x80};
uint8_t key_scan(void)
{
uint8_t keyval = 0;
if (KEY_X == 0) keyval = KEYX_PRES;
if (KEY_Y == 1) keyval = KEYY_PRES;
if (KEY_A == 0) keyval = KEYA_PRES;
if (KEY_B == 0) keyval = KEYB_PRES;
if (KEY_RIGHT == 0) keyval = KEYRIGHT_PRES;
return keyval; /* 返回键值 */
}
void key_handle(void)
{
uint8_t key;
sendbuf[0] = 0x00;
sendbuf[1] = 0x00;
key = key_scan();
switch (key)
{
case KEYY_PRES: //up
{
sendbuf[0] = 0x08;
break;
}
case KEYA_PRES: //down
{
sendbuf[0] = 0x01;
break;
}
case KEYX_PRES: //left
{
sendbuf[0] = 0x04;
break;
}
case KEYB_PRES: //right
{
sendbuf[0] = 0x02;
break;
}
case KEYRIGHT_PRES: //右操作摇杆键
{
sendbuf[1] = 0x08;
break;
}
default: break;
}
}
void adc_channel_set(ADC_HandleTypeDef *adc_handle, uint32_t ch, uint32_t rank, uint32_t stime)
{
/* 配置对应ADC通道 */
ADC_ChannelConfTypeDef adc_channel;
adc_channel.Channel = ch; /* 设置ADCX对通道ch */
adc_channel.Rank = rank; /* 设置采样序列 */
adc_channel.SamplingTime = stime; /* 设置采样时间 */
HAL_ADC_ConfigChannel( adc_handle, &adc_channel);
}
uint32_t adc_get_result(uint32_t ch)
{
adc_channel_set(&hadc1, ch, 1, ADC_SAMPLETIME_480CYCLES); /* 设置通道,序列和采样时间 */
HAL_ADC_Start(&hadc1); /* 开启ADC */
HAL_ADC_PollForConversion(&hadc1, 10); /* 轮询转换 */
return (uint16_t)HAL_ADC_GetValue(&hadc1); /* 返回最近一次ADC1规则组的转换结果 */
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_USB_DEVICE_Init();
while (1)
{
key_handle();
sendbuf[4] = (uint8_t)adc_get_result(ADC_CHANNEL_10);
sendbuf[5] = (uint8_t)adc_get_result(ADC_CHANNEL_11);
USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&sendbuf,sizeof(sendbuf));
}
}
四、测试功能
在线测试点击:游戏手柄测试
实验现象:使用USB连接线将设备与电脑相连,点击 游戏手柄测试,按下任意按键或者摇动右侧摇杆,可看到网页中相应的按键或摇杆会跟随实际游戏手柄动作而动作。
程序源码:
通过GitHub分享:GitHub - Freddysssss/STM32F407ZG_USB_HID_Gamepad
通过网盘分享的文件:STM32F407ZG_USB_HID_Gamepad.rar
链接: https://pan.baidu.com/s/1QkR1bPzMPpaE-9A2zF6j3A?pwd=gw6u 提取码: gw6u