[APM32E1] 【APM32E103xE测评】+USB手柄设备

[复制链接]
2775|18
 楼主| WoodData 发表于 2022-5-8 23:54 | 显示全部楼层 |阅读模式
本帖最后由 WoodData 于 2022-5-9 08:46 编辑

    有幸中了一块极海的APM32E103开发板,初次接触极海的MCU。板子上主要是最小系统,IO全部引出,很简洁的板子。看到板子上有USB接口,就想试试USB外设做个设备。下载了开发板的资料和开发包,发现关于USB的例子只有一个USB鼠标。好好研究了一下这个例子。就准备试试改一下做成USB手柄设备。下面就是记录下做的手柄设备过程。   
首先照着usb鼠标的例子修改一下,改改USB设备相关的描述符。
配置描述符,鼠标只用了一个输入端点,而手柄一般需要输入和输出各一个端点。描述符修改如下
  1. /**
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]   Configuration descriptor
  3. */
  4. const uint8_t g_hidMouseConfigDescriptor[HID_MOUSE_CONFIG_DESCRIPTOR_SIZE] =
  5. {
  6.     /** bLength */
  7.     0x09,
  8.     /** bDescriptorType */
  9.     USB_DESC_CONFIGURATION,
  10.     /** wTotalLength */
  11.     HID_MOUSE_CONFIG_DESCRIPTOR_SIZE & 0XFF, HID_MOUSE_CONFIG_DESCRIPTOR_SIZE >> 8,
  12.    
  13.     /** bNumInterfaces */
  14.     0X01,
  15.     /** bConfigurationValue */
  16.     0X01,
  17.     /** iConfiguration */
  18.     0X00,
  19.     /** bmAttributes */
  20.     0XE0,
  21.     /** MaxPower */
  22.     0X32,

  23.     /** bLength */
  24.     0X09,
  25.     /** bDescriptorType */
  26.     USB_DESC_INTERFACE,
  27.     /** bInterfaceNumber */
  28.     0X00,
  29.     /** bAlternateSetting */
  30.     0X00,
  31.     /** bNumEndpoints */
  32.     0X02,
  33.     /** bInterfaceClass */
  34.     0X03,
  35.     /** bInterfaceSubClass */
  36.     0X00,
  37.     /** nInterfaceProtocol */
  38.     0X00,
  39.     /** iInterface */
  40.     0X00,

  41.     /** bLength */
  42.     0X09,
  43.     /** bDescriptorType = HID */
  44.     0x21,
  45.     /** bcdHID */
  46.     0X00, 0X01,
  47.     /** bCountryCode */
  48.     0X00,
  49.     /** bNumDescriptors */
  50.     0X01,
  51.     /** bDescriptorType */
  52.     0X22,
  53.     /** wItemLength */
  54.     HID_MOUSE_REPORT_DESCRIPTOR_SIZE & 0XFF, HID_MOUSE_REPORT_DESCRIPTOR_SIZE >> 8,

  55.     //IN endpoint
  56.     /** bLength */
  57.     0X07,
  58.     /** bDescriptorType */
  59.     USB_DESC_ENDPOINT,
  60.     /** bEndpointAddress */
  61.     0X81,
  62.     /** bmAttributes */
  63.     0X03,
  64.     /** wMaxPacketSize */
  65.     0X40, 0X00,
  66.     /** bInterval */
  67.     0X10,
  68.    
  69.     //OUT endpoint
  70.     /** bLength */
  71.     0X07,
  72.     /** bDescriptorType */
  73.     USB_DESC_ENDPOINT,
  74.     /** bEndpointAddress */
  75.     0X01,
  76.     /** bmAttributes */
  77.     0X03,
  78.     /** wMaxPacketSize */
  79.     0X40, 0X00,
  80.     /** bInterval */
  81.     0X10
  82. };
然后就是手柄的报告描述符
  1. /**
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]   HID report descriptor
  3. */
  4. const uint8_t g_hidMouseReportDescriptor[HID_MOUSE_REPORT_DESCRIPTOR_SIZE] =
  5. {
  6.     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
  7.     0x09, 0x05,                    // USAGE (Game Pad)
  8.     0xa1, 0x01,                    // COLLECTION (Application)
  9.     0x09, 0x01,                    //   USAGE (Pointer)
  10.     0xa1, 0x00,                    //   COLLECTION (Physical)
  11.     0x09, 0x30,                    //     USAGE (X)
  12.     0x09, 0x31,                    //     USAGE (Y)
  13.     0x09, 0x33,                    //     USAGE (RX)
  14.     0x09, 0x34,                    //     USAGE (RY)
  15.     0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
  16.     0x25, 0x7f,                        //     LOGICAL_MAXIMUM (127)        
  17.     0x75, 0x08,                    //     REPORT_SIZE (8)
  18.     0x95, 0x04,                    //     REPORT_COUNT (4)
  19.     0x81, 0x02,                    //     INPUT (Data,Var,Abs)
  20.     0xc0,                          //     END_COLLECTION
  21.         
  22.     0x09, 0x36,                    //   USAGE (Silder)
  23.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
  24.     0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
  25.     0x75, 0x08,                    //   REPORT_SIZE (8)
  26.     0x95, 0x01,                    //   REPORT_COUNT (1)
  27.     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
  28.         
  29.     0x09, 0x39,                    //   USAGE (Hat switch)
  30.     0x15, 0x01,                    //   LOGICAL_MINIMUM (1)
  31.     0x25, 0x08,                    //   LOGICAL_MAXIMUM (8)
  32.     0x75, 0x08,                    //   REPORT_SIZE (8)
  33.     0x95, 0x01,                    //   REPORT_COUNT (1)
  34.     0x81, 0x42,                    //   INPUT (Data,Var,Abs,Null)
  35.         
  36.     0x05, 0x09,                    //   USAGE_PAGE (Button)
  37.     0x19, 0x01,                    //   USAGE_MINIMUM (Button 1)
  38.     0x29, 0x10,                    //   USAGE_MAXIMUM (Button 16)
  39.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
  40.     0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
  41.     0x75, 0x01,                    //   REPORT_SIZE (1)
  42.     0x95, 0x10,                    //   REPORT_COUNT (16)
  43.     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
  44.    
  45.     0x06, 0x00, 0xff,              //   USAGE_PAGE (Vendor Defined Page 1)
  46.     0x09, 0x01,                    //   USAGE (Vendor Usage 1)
  47.     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
  48.     0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
  49.     0x75, 0x08,                    //   REPORT_SIZE (8)
  50.     0x95, 0x04,                    //   REPORT_COUNT (4)
  51.     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)        
  52.    
  53.     0xc0                           // END_COLLECTION
  54. };
下面是USB端点的初始化,这个初始化是在USB复位中处理的
  1. void HidMouse_Reset(void)
  2. {
  3.     uint8_t i;

  4.    s_usbConfigStatus = 0;  //usb not config,disable send data
  5.    
  6.     USBD_SetBufferTable(USB_BUFFER_TABLE_ADDR);
  7.     //endpoint 0 init
  8.     USBD_ResetEPKind(USBD_EP_0);
  9.    
  10.     USBD_SetEPType(USBD_EP_0, USBD_EP_TYPE_CONTROL);
  11.     USBD_SetEPTxStatus(USBD_EP_0, USBD_EP_STATUS_STALL);
  12.     USBD_SetEPTxAddr(USBD_EP_0, USB_EP0_TX_ADDR);
  13.    
  14.     USBD_SetEPRxStatus(USBD_EP_0, USBD_EP_STATUS_VALID);   
  15.     USBD_SetEPRxAddr(USBD_EP_0, USB_EP0_RX_ADDR);
  16.     USBD_SetEPRxCnt(USBD_EP_0, USB_EP_PACKET_SIZE);

  17.     //endpoint 1 init
  18.     USBD_SetEPType(USBD_EP_1, USBD_EP_TYPE_INTERRUPT);
  19.     USBD_SetEPTxAddr(USBD_EP_1, USB_EP1_TX_ADDR);
  20.     USBD_SetEPTxCnt(USBD_EP_1, 0x8);
  21.    
  22.     USBD_SetEPRxAddr(USBD_EP_1, USB_EP1_RX_ADDR);
  23.     USBD_SetEPRxCnt(USBD_EP_1, 0x4);
  24.     USBD_SetEPRxTxStatus(USBD_EP_1, USBD_EP_STATUS_NAK, USBD_EP_STATUS_VALID);
  25.    
  26.     //endpoint addr
  27.     for(i = 0; i < USB_EP_NUM; i++)
  28.     {
  29.         USBD_SetEpAddr((USBD_EP_T)i, i);
  30.     }
  31.    
  32.     USBD_SetDeviceAddr(0);
  33.     USBD_Enable();
  34. }
USB的输出端点处理
  1. void HidMouse_EPHandler(uint8_t ep, uint8_t dir)
  2. {
  3.     if(dir == 0)    //out endpoint
  4.     {
  5.         switch(ep)
  6.         {
  7.             case    USBD_EP_0:
  8.                 break;
  9.             case    USBD_EP_1:
  10.                 USBD_ReadDataFromEP(USBD_EP_1,s_usb_recv_buff,4);
  11.                 USBD_SetEPRxStatus(USBD_EP_1, USBD_EP_STATUS_VALID);    //recv data valid
  12.                 //recv data process   
  13.                 if(s_usb_recv_buff[0]&0x01)
  14.                 {
  15.                     GPIO_ResetBits(GPIOE,GPIO_PIN_5);
  16.                 }else
  17.                 {
  18.                     GPIO_SetBits(GPIOE,GPIO_PIN_5);
  19.                 }
  20.                
  21.                 if(s_usb_recv_buff[1]&0x01)
  22.                 {
  23.                     GPIO_ResetBits(GPIOE,GPIO_PIN_6);
  24.                 }else
  25.                 {
  26.                     GPIO_SetBits(GPIOE,GPIO_PIN_6);
  27.                 }
  28.                
  29.                 break;
  30.             case    USBD_EP_2:
  31.                 break;
  32.             case    USBD_EP_3:
  33.                 break;
  34.             case    USBD_EP_4:
  35.                 break;
  36.             case    USBD_EP_5:
  37.                 break;
  38.             case    USBD_EP_6:
  39.                 break;
  40.             case    USBD_EP_7:
  41.                 break;
  42.         }        
  43.     }else
  44.     {
  45.         //in endpoint
  46.         switch(ep)
  47.         {
  48.             case    USBD_EP_0:
  49.                 break;
  50.             case    USBD_EP_1:
  51.                 s_statusEP = 1; //endpoint1 can send data
  52.                 break;
  53.             case    USBD_EP_2:
  54.                 break;
  55.             case    USBD_EP_3:
  56.                 break;
  57.             case    USBD_EP_4:
  58.                 break;
  59.             case    USBD_EP_5:
  60.                 break;
  61.             case    USBD_EP_6:
  62.                 break;
  63.             case    USBD_EP_7:
  64.                 break;
  65.         }        
  66.     }

  67. }
USB的输入报告处理
  1. void HidMouse_Write(uint8_t key)
  2. {
  3.     static  int8_t x = 0;
  4.     static  int8_t y = 0;
  5.     uint8_t buffer[8] = {0, 0, 0, 0};
  6.   
  7.     switch (key)
  8.     {
  9.         case HID_MOUSE_KEY_LEFT:
  10.             x -= 10;
  11.             buffer[5] = 3;
  12.             buffer[6] = 0x01;
  13.         break;
  14.         
  15.         case HID_MOUSE_KEY_RIGHT:
  16.             x += 10;
  17.             buffer[5] = 7;
  18.             buffer[6]  = 0x02;
  19.         break;
  20.         
  21.         case HID_MOUSE_KEY_UP:
  22.             y -= 10;
  23.         break;
  24.         
  25.         case HID_MOUSE_KEY_DOWN:
  26.             y += 10;
  27.         break;
  28.         
  29.         default:
  30.             return;
  31.     }

  32.     buffer[0] = x;
  33.     buffer[1] = y;

  34.     s_statusEP = 0; //send over flag
  35.    
  36.     USBD_WriteDataToEP(USBD_EP_1, buffer, sizeof(buffer));  //write data to buffer
  37.     USBD_SetEPTxStatus(USBD_EP_1, USBD_EP_STATUS_VALID);    //send data valid
  38. }
主要修改以上内容,中间经过多次调试,最终成功枚举到USB手柄设备,并且输入输出数据正常。
1.jpg

下面是识别的USB手柄。用了 板上的2个按键模拟数据。
2.png


下面输出数据,调试可以看到接收数据。
3.png
4.png

在调试的过程中也发现了一些问题。
首先USB那个1.5k电阻上拉是跳线帽控制的,这个很不方便,每次还要手动拔插一下。
再就是用户手册文档USB那块发现一些明显错误,明显是从其他那抄来的,都不检查一下。开始看得奇奇怪怪的。
6.png
5.png
7.png


程序下面:
游客,如果您要查看本帖隐藏内容请回复




gxliu08 发表于 2022-5-28 21:20 | 显示全部楼层
感谢分享,学习学习
地球十强666 发表于 2022-6-12 22:51 | 显示全部楼层
手动点赞,,另。。。国产芯片要走的路还很长啊。。
isseed 发表于 2022-9-7 16:20 | 显示全部楼层
手柄应该怎么和单片机建立联系??
maudlu 发表于 2022-9-7 18:13 | 显示全部楼层
低成本USB单片机吗  
chenjun89 发表于 2022-9-7 18:17 来自手机 | 显示全部楼层
可以自己做个游戏手柄吗?
biechedan 发表于 2022-9-7 19:45 | 显示全部楼层
单片机处理USB接口手柄程序可用于USB通信实现
Bowclad 发表于 2022-9-7 20:29 | 显示全部楼层
手柄怎么连接单片机?
sdlls 发表于 2022-9-7 20:51 | 显示全部楼层
USB手柄无需驱动程序?
232321122 发表于 2022-9-8 10:42 | 显示全部楼层
属于USB HID设备
typeof 发表于 2022-9-8 11:40 | 显示全部楼层
如何使用游戏手柄控制单片机控制电机
MessageRing 发表于 2022-10-4 20:31 | 显示全部楼层
这不就能diy了
jianjunbin 发表于 2023-4-12 17:53 | 显示全部楼层
mark一下,学习学习!
emanages 发表于 2023-12-6 14:58 | 显示全部楼层
感谢分享,学习学习
gx19890101 发表于 2024-4-10 13:49 | 显示全部楼层
看看 啊啊啊
OKAKAKO 发表于 2024-4-15 20:09 | 显示全部楼层
学习一下枚举的使用
szt1993 发表于 2024-4-16 19:44 | 显示全部楼层
枚举确实很有用
zhuozhixin 发表于 2025-8-26 01:41 | 显示全部楼层
感谢分享,学习学习
您需要登录后才可以回帖 登录 | 注册

本版积分规则

127

主题

4784

帖子

28

粉丝
快速回复 在线客服 返回列表 返回顶部