900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > STM32 USB Host 同时连接多个设备样例(如鼠标和键盘)--原创

STM32 USB Host 同时连接多个设备样例(如鼠标和键盘)--原创

时间:2023-10-18 21:41:26

相关推荐

STM32 USB Host 同时连接多个设备样例(如鼠标和键盘)--原创

STM32 USB Host 同时连接多个设备样例(如鼠标和键盘)

在网上搜了很多都是USB Host单独连接鼠标或键盘的样例, 而当前很多无线鼠标键盘都是并到一个USB口上的, 也就是同一个USB有两个interface. 而官方提供的USB Host库中只会对一个Interface进行处理, 要么键盘要么鼠标, 所以为了能够同时使用键盘和鼠标要对USB Host库进行修改才行.

具体修改如下:

首先使用CubeMX创建了一个带USB HID类功能的工程, 创建步骤很简单网上有很多文档不在这里讨论.

接着进入正题, 修改USB Host库文件.

usbh_def.h

修改USBH_ClassTypeDef, 使当前Class支持多接口:

/* USB Host Class structure */typedef struct{const char*Name;uint8_t ClassCode;USBH_StatusTypeDef(*Init)(struct _USBH_HandleTypeDef *phost);USBH_StatusTypeDef(*DeInit)(struct _USBH_HandleTypeDef *phost);USBH_StatusTypeDef(*Requests)(struct _USBH_HandleTypeDef *phost);USBH_StatusTypeDef(*BgndProcess)(struct _USBH_HandleTypeDef *phost);USBH_StatusTypeDef(*SOFProcess)(struct _USBH_HandleTypeDef *phost);/* [ */void*pData[USBH_MAX_NUM_INTERFACES]; /* HID interfaces Handle */uint8_t InterfaceNum; /* interface 数量 */__IO uint8_t CurrInterface; /* 当前interface *//* ] */} USBH_ClassTypeDef;

修改HID_HandleTypeDef, 记录interface的协议类型:

/* Structure for HID process */typedef struct _HID_Process{uint8_t OutPipe;uint8_t InPipe;HID_StateTypeDefstate;uint8_t OutEp;uint8_t InEp;HID_CtlStateTypeDef ctl_state;FIFO_TypeDef fifo;uint8_t *pData;uint16_t length;uint8_t ep_addr;uint16_t poll;uint32_t timer;uint8_t DataReady;HID_DescTypeDefHID_Desc;USBH_StatusTypeDef(* Init)(USBH_HandleTypeDef *phost);/* [ */uint8_t Protocol; /* 协议类型: HID_KEYBRD_BOOT_CODE / HID_MOUSE_BOOT_CODE *//* ] */} HID_HandleTypeDef;

usbh_hid.c

修改USBH_HID_InterfaceInit函数, 在初始化的时候判断当前枚举了几个HID接口, 如果有多个接口, 则创建多个HID_HandleTypeDef:

static USBH_StatusTypeDef USBH_HID_InterfaceInit(USBH_HandleTypeDef *phost){USBH_StatusTypeDef status = USBH_OK;HID_HandleTypeDef *HID_Handle;uint8_t max_ep;uint8_t num = 0U;/* [ */uint8_t boot = HID_KEYBRD_BOOT_CODE;uint8_t interface_num = 0;uint8_t interface;for (interface_num = 0; interface_num < phost->device.CfgDesc.bNumInterfaces; interface_num++){interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, HID_BOOT_CODE, boot);/* ] */if ((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES)) /* No Valid Interface */{USBH_DbgLog("Cannot Find the interface for %s class.", phost->pActiveClass->Name);status = USBH_FAIL;break;}status = USBH_SelectInterface(phost, interface);if (status != USBH_OK){return USBH_FAIL;}/* [ */phost->pActiveClass->pData[interface_num] = (HID_HandleTypeDef *)USBH_malloc(sizeof(HID_HandleTypeDef));phost->pActiveClass->InterfaceNumber++;phost->pActiveClass->CurrInterface = interface_num;HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData[interface_num];/* ] */if (HID_Handle == NULL){USBH_DbgLog("Cannot allocate memory for HID Handle");return USBH_FAIL;}/* Initialize hid handler */USBH_memset(HID_Handle, 0, sizeof(HID_HandleTypeDef));HID_Handle->state = HID_ERROR;/*Decode Bootclass Protocol: Mouse or Keyboard*/HID_Handle->Protocol = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol;....../* 配置完成 [ */if (boot == HID_KEYBRD_BOOT_CODE)boot = HID_MOUSE_BOOT_CODE;elseboot = HID_KEYBRD_BOOT_CODE;/* ] */}return status;}

修改USBH_HID_Process, 在POLL空闲时如果10次连续空闲未收到有效数据则切换接口, 使下次执行Process的时候切换到另一个接口:

static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost){USBH_StatusTypeDef status = USBH_OK;HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData[phost->pActiveClass->CurrInterface];uint32_t XferSize;/* [ */uint8_t interface;uint8_t protocol;static __IO uint16_t num = 0;/* ] */switch (HID_Handle->state){...case HID_POLL:if (USBH_LL_GetURBState(phost, HID_Handle->InPipe) == USBH_URB_DONE){XferSize = USBH_LL_GetLastXferSize(phost, HID_Handle->InPipe);if ((HID_Handle->DataReady == 0U) && (XferSize != 0U)){USBH_HID_FifoWrite(&HID_Handle->fifo, HID_Handle->pData, HID_Handle->length);HID_Handle->DataReady = 1U;USBH_HID_EventCallback(phost);#if (USBH_USE_OS == 1U)phost->os_msg = (uint32_t)USBH_URB_EVENT;#if (osCMSIS < 0x20000U)(void)osMessagePut(phost->os_event, phost->os_msg, 0U);#else(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);#endif#endif/* 如果检测到有效数据, 则清除空闲计数 [ */num = 0;/* ] */}}else{/* 如果空闲计数达到10次, 则切换到其他interface [ */num++;if (num > 10){if (phost->pActiveClass->InterfaceNumber > 1){if (phost->pActiveClass->CurrInterface == 0)phost->pActiveClass->CurrInterface = 1;elsephost->pActiveClass->CurrInterface = 0;protocol = ((HID_HandleTypeDef *)phost->pActiveClass->pData[phost->pActiveClass->CurrInterface])->Protocol;interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, HID_BOOT_CODE, protocol);USBH_SelectInterface(phost, interface);}num = 0;}/* ] *//* IN Endpoint Stalled */if (USBH_LL_GetURBState(phost, HID_Handle->InPipe) == USBH_URB_STALL){/* Issue Clear Feature on interrupt IN endpoint */if (USBH_ClrFeature(phost, HID_Handle->ep_addr) == USBH_OK){/* Change state to issue next IN token */HID_Handle->state = HID_GET_DATA;}}}break;...}}

另外其他涉及到"phost->pActiveClass->pData"的地方全部改为"phost->pActiveClass->pData[phost->pActiveClass->CurrInterface]", 因为pData已经不再是一个结构体指针而是一个结构体指针数组, 主要涉及的文件包括:

usbh_hid.c, usbh_hid_keybs.c, usbh_hid_mouse.c

3. 修改键盘和鼠标的驱动

最后就是按照键盘鼠标的协议定义相应的回调函数, 因为不同的无线鼠标键盘有不同的协议, 在此不做描述. 主要涉及的文件包括:

usb_host.c, usbh_hid_keybs.c, usbh_hid_mouse.c

做好驱动以后就可以同时使用键盘和鼠标了, 此方法也可适用于USB连接其他多设备场景, 只要USB初始化的时候能够检测到相应的设备.

测试视频:

STM32 USB Host同时连接鼠标和键盘演示视频

转载请注明出处.

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。