STM32 HAL库学习(六)USB识别成Custom HID通信

11 篇文章 23 订阅

一、STM32F070 USB基础知识了解:

STM32F070 USB采用USB 2.0规范,时钟频率为48MHZ,有一个专用的USB数据存储区,大小为1024字节;支持16个单向传输端点、8个双向传输端点

USB外设模块构成图:

USB物理接口模块:

USB_DM、USB_DP —— 数据正、负信号

Analog Transceiver —— 模拟收发器

Embedded pull-up resister —— 可控嵌入负载电阻

Battery Charging Detection(BCD) —— 电池充电检测

USB_NOE —— 允许输出信号,可用于驱动LED或提供通信信息

Serial Interface Engine(SIE)串行接口引擎:

这个模块主要用于同步模式识别、CRC/PID的生成和检验、SOF/reset信号的生成、产生中断信号等

Timer定时器模块:

生成起始帧的锁定时钟脉冲以及检测阻塞

USB连接到到APB总线的APB接口模块构成有:Packet Memory、Arbiter(仲裁器,解决冲突访问APB的问题)、Register Mapper(寄存器映射器)、APB封装器(将USB外设映射到APB的地址空间)、中断映射

 

二、STM32Cube USB中间件文件了解:

在STM32CubeMX中选择USB中间件,点击生成代码就会自动加载USB的库文件,查看STM32_USB_Device_Library文件夹可见,USB库文件分为两类:一类是Class即设备类文件;一类是Core即内核文件。内核文件和设备类文件分别如下两图所示:

usbd_core.c /h —— 处理USB通信和状态机的函数

usbd_ctlreq.c/h —— 处理USB事务结果

usbd_conf_template.c/h —— 底层接口文件的模板文件,用户对其进行修改包含在应用文件中

usbd_ioreq.c/h —— 包含了USB规范列出的请求实现

 

三、使用STM32Cube MX配置USB

配置RCC时钟,激活HSE时钟源,作为USB时钟的输入,选择USB类为HID设备类

 

Configuration页面进行USB的相关设置、描述符设置,这里配置USB为用户自定义的HID设备,生成的MDK代码文件如下所示,建议先用工具生成报告描述符再根据它的长度进行配置

 

 

 

 分析描述符

首先是USB设备标准描述符,Cube MX 已经根据配置自动生成了

__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
  0x12,                       /*bLength */
  USB_DESC_TYPE_DEVICE,       /*bDescriptorType*/
  0x00,                       /*bcdUSB */
  0x02,
  0x00,                       /*bDeviceClass*/
  0x00,                       /*bDeviceSubClass*/
  0x00,                       /*bDeviceProtocol*/
  USB_MAX_EP0_SIZE,           /*bMaxPacketSize*/
  LOBYTE(USBD_VID),           /*idVendor*/
  HIBYTE(USBD_VID),           /*idVendor*/
  LOBYTE(USBD_PID_FS),        /*idProduct*/
  HIBYTE(USBD_PID_FS),        /*idProduct*/
  0x00,                       /*bcdDevice rel. 2.00*/
  0x02,
  USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
  USBD_IDX_PRODUCT_STR,       /*Index of product string*/
  USBD_IDX_SERIAL_STR,        /*Index of serial number string*/
  USBD_MAX_NUM_CONFIGURATION  /*bNumConfigurations*/
};

接下来是修改HID报告描述符,STM32HAL为用户提供了一个USB设备HID接口类的文件,即usbd_custom_hid_if.c/h,以便用户自行配置HID报告描述符,要修改的数组是CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE],建议使用 HID descriptor tool工具生成报告符。这里要注意的是报告描述符大小USBD_CUSTOM_HID_REPORT_DESC_SIZE,一定要与实际生成的报告描述符大小(使用HID descriptor tool可查看)相对应,否则会导致HID设备配置失败。

HID_Usage()等数值我在usbd_custom_hid_if.h中有定义

__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
  /* USER CODE BEGIN 0 */
  HID_UsagePageVendor(0xa0),   
	HID_Usage(0xa5),
	HID_Collection(0x01),
	HID_Usage(0xa6),
/* input  */
	HID_Usage(0xa7),
	HID_LogicalMin(0x00),
	HID_LogicalMax(0xFF),
	HID_ReportSize(8),
	HID_ReportCount(64),
	HID_Input(HID_Data | HID_Variable | HID_Absolute),



/*  output  */
	HID_Usage(0xa9),
	HID_LogicalMin(0x00),
	HID_LogicalMax(0xff),
	HID_ReportSize(8),
	HID_ReportCount(64),
	HID_Output(HID_Data | HID_Variable | HID_Absolute),
  /* USER CODE END 0 */
  0xC0    /*     END_COLLECTION	             */
};

到这里为止,下载程序后PC机就可以识别出HID设备了

发送数据:

使用USBD_CUSTOM_HID_SendReport,这个函数在usbd_customhid.c中定义,在while循环中调用这个函数

uint8_t USBD_CUSTOM_HID_SendReport     (USBD_HandleTypeDef  *pdev, 
                                 uint8_t *report,
                                 uint16_t len)
{
  USBD_CUSTOM_HID_HandleTypeDef     *hhid = (USBD_CUSTOM_HID_HandleTypeDef*)pdev->pClassData;
  
  if (pdev->dev_state == USBD_STATE_CONFIGURED )
  {
    if(hhid->state == CUSTOM_HID_IDLE)
    {
      hhid->state = CUSTOM_HID_BUSY;
      USBD_LL_Transmit (pdev, 
                        CUSTOM_HID_EPIN_ADDR,                                      
                        report,
                        len);
    }
  }
  return USBD_OK;
}
 /* USER CODE BEGIN WHILE */
  while (1)
  {
    USB_Status = USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS,InReport,64);
		HAL_Delay(100);
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER C

关于端点最大传输包大小和HID报告描述符中的ReportCount,在usbd_customhid.c中有如下定义

#define CUSTOM_HID_EPIN_ADDR                 0x81
#define CUSTOM_HID_EPIN_SIZE                 0x02

#define CUSTOM_HID_EPOUT_ADDR                0x01
#define CUSTOM_HID_EPOUT_SIZE                0x02

这里定义中断传输端点的最大传输包大小为2,但其实实际传输时仍然可以传输64个数据,原因是在HID报告描述符中有对Input和Output的传输数据包大小做定义,实际传输大小应该以这个为标准,即每次传输最大数据量为64个数据,每个数据8位。不过建议将CUSTOM_HID_EPIN_SIZE/CUSTOM_HID_EPOUT_SIZE修改成和报告符中定义的大小一致。

HID_ReportSize(8),
HID_ReportCount(64),

接收数据:

USB中断传输方式中,每次PC机发送数据后USB设备都会产生中断,设备每完成一次从PC机的Out data的接收都会响应一次OutEvent,因此可以通过修改usbd_custom_hid_if.c中的static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)来实现对接收到数据做处理。

我这里在OutEvent中置位一次接收完成的标志OutComplete,然后在main函数中处理数据

static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
{
  /* USER CODE BEGIN 6 */
	OutComplete = 1;
  return (USBD_OK);
  /* USER CODE END 6 */
}
  while (1)
  {
    USB_Status = USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS,InReport,256);
		if(OutComplete)
		{
			hhid = (USBD_CUSTOM_HID_HandleTypeDef*)hUsbDeviceFS.pClassData;  //µÃµ½½ÓÊյĵØÖ·
			for(uint16_t i=0;i<64;i++)
			  OutReport[i] = hhid->Report_buf[i];
			HAL_UART_Transmit(&huart2, OutReport, 64, HAL_MAX_DELAY);
			OutComplete = 0;
		}
		
		HAL_Delay(100);
		
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

这里有一个小插曲,我调用HAL_UART_Transmit函数时习惯给延时参数直接赋值10,然后发现串口助手每次只接收到OutReport的前12个数据,但我明明指定了传输长度为64,后来才知道是延时参数设置不当,串口还没发送完数据就被迫停止传输了,后来改成HAL_MAX_Delay后数据就正常了。

  • 21
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在使用STM32G0 HAL库配置USB口之前,需要先在CubeMX中启用USB功能。以下是配置步骤: 1. 打开CubeMX,并在“Pinout”选项卡中选择您的MCU型号。 2. 在左侧“Connectivity”菜单下,选中“USB_OTG_FS”(如果使用的是USB FS接口)或“USB_OTG_HS”(如果使用的是USB HS接口)。 3. 在右侧弹出的“USB_OTG_FS Properties”或“USB_OTG_HS Properties”窗口中,选择“Core”选项卡,并启用“Full Speed”或“High Speed”模式。 4. 在同一窗口中,选择“Clock Configuration”选项卡,并启用“PLLCLK”。 5. 在“Configuration”选项卡中,选择“Class”并选择“MSC”(如果您需要使用USB Mass Storage Class)。 6. 点击“Generate”按钮,CubeMX将会自动生初始化代码。 接下来,您可以根据需要调整生的代码,例如更改USB速度、配置USB中断等等。以下是一些常用的STM32G0 HAL库函数,可用于配置USB口: 1. HAL_PCD_Init():初始化USB控制器。 2. HAL_PCD_MspInit():初始化USB控制器的底层硬件资源,例如时钟、GPIO等。 3. HAL_PCD_IRQHandler():处理USB中断事件。 4. HAL_PCD_EP_Open():打开一个USB端点。 5. HAL_PCD_EP_Close():关闭一个USB端点。 6. HAL_PCD_EP_Transmit():向指定的USB端点发送数据。 7. HAL_PCD_EP_Receive():从指定的USB端点接收数据。 例如,以下代码片段演示了如何使用HAL库初始化USB控制器和打开一个USB端点: ```c PCD_HandleTypeDef hpcd; void USB_Init(void) { // 初始化USB控制器 hpcd.Instance = USB; hpcd.Init.dev_endpoints = 8; hpcd.Init.speed = PCD_SPEED_FULL; hpcd.Init.phy_itface = PCD_PHY_EMBEDDED; hpcd.Init.low_power_enable = DISABLE; HAL_PCD_Init(&hpcd); // 打开USB端点 HAL_PCD_EP_Open(&hpcd, 1, 64, EP_TYPE_BULK); } ``` 请注意,以上代码仅供参考。您需要根据实际情况进行修改和调试。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值