打印
[APM32E1]

【APM32E103xE测评】+USB手柄设备

[复制链接]
1981|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 WoodData 于 2022-5-9 08:46 编辑

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

    /** bLength */
    0X09,
    /** bDescriptorType */
    USB_DESC_INTERFACE,
    /** bInterfaceNumber */
    0X00,
    /** bAlternateSetting */
    0X00,
    /** bNumEndpoints */
    0X02,
    /** bInterfaceClass */
    0X03,
    /** bInterfaceSubClass */
    0X00,
    /** nInterfaceProtocol */
    0X00,
    /** iInterface */
    0X00,

    /** bLength */
    0X09,
    /** bDescriptorType = HID */
    0x21,
    /** bcdHID */
    0X00, 0X01,
    /** bCountryCode */
    0X00,
    /** bNumDescriptors */
    0X01,
    /** bDescriptorType */
    0X22,
    /** wItemLength */
    HID_MOUSE_REPORT_DESCRIPTOR_SIZE & 0XFF, HID_MOUSE_REPORT_DESCRIPTOR_SIZE >> 8,

    //IN endpoint
    /** bLength */
    0X07,
    /** bDescriptorType */
    USB_DESC_ENDPOINT,
    /** bEndpointAddress */
    0X81,
    /** bmAttributes */
    0X03,
    /** wMaxPacketSize */
    0X40, 0X00,
    /** bInterval */
    0X10,
   
    //OUT endpoint
    /** bLength */
    0X07,
    /** bDescriptorType */
    USB_DESC_ENDPOINT,
    /** bEndpointAddress */
    0X01,
    /** bmAttributes */
    0X03,
    /** wMaxPacketSize */
    0X40, 0X00,
    /** bInterval */
    0X10
};
然后就是手柄的报告描述符
/**
* [url=home.php?mod=space&uid=247401]@brief[/url]   HID report descriptor
*/
const uint8_t g_hidMouseReportDescriptor[HID_MOUSE_REPORT_DESCRIPTOR_SIZE] =
{
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x05,                    // USAGE (Game Pad)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x09, 0x01,                    //   USAGE (Pointer)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x09, 0x30,                    //     USAGE (X)
    0x09, 0x31,                    //     USAGE (Y)
    0x09, 0x33,                    //     USAGE (RX)
    0x09, 0x34,                    //     USAGE (RY)
    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
        
    0x09, 0x36,                    //   USAGE (Silder)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
        
    0x09, 0x39,                    //   USAGE (Hat switch)
    0x15, 0x01,                    //   LOGICAL_MINIMUM (1)
    0x25, 0x08,                    //   LOGICAL_MAXIMUM (8)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x42,                    //   INPUT (Data,Var,Abs,Null)
        
    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)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x10,                    //   REPORT_COUNT (16)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
   
    0x06, 0x00, 0xff,              //   USAGE_PAGE (Vendor Defined Page 1)
    0x09, 0x01,                    //   USAGE (Vendor Usage 1)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x04,                    //   REPORT_COUNT (4)
    0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)        
   
    0xc0                           // END_COLLECTION
};
下面是USB端点的初始化,这个初始化是在USB复位中处理的
void HidMouse_Reset(void)
{
    uint8_t i;

   s_usbConfigStatus = 0;  //usb not config,disable send data
   
    USBD_SetBufferTable(USB_BUFFER_TABLE_ADDR);
    //endpoint 0 init
    USBD_ResetEPKind(USBD_EP_0);
   
    USBD_SetEPType(USBD_EP_0, USBD_EP_TYPE_CONTROL);
    USBD_SetEPTxStatus(USBD_EP_0, USBD_EP_STATUS_STALL);
    USBD_SetEPTxAddr(USBD_EP_0, USB_EP0_TX_ADDR);
   
    USBD_SetEPRxStatus(USBD_EP_0, USBD_EP_STATUS_VALID);   
    USBD_SetEPRxAddr(USBD_EP_0, USB_EP0_RX_ADDR);
    USBD_SetEPRxCnt(USBD_EP_0, USB_EP_PACKET_SIZE);

    //endpoint 1 init
    USBD_SetEPType(USBD_EP_1, USBD_EP_TYPE_INTERRUPT);
    USBD_SetEPTxAddr(USBD_EP_1, USB_EP1_TX_ADDR);
    USBD_SetEPTxCnt(USBD_EP_1, 0x8);
   
    USBD_SetEPRxAddr(USBD_EP_1, USB_EP1_RX_ADDR);
    USBD_SetEPRxCnt(USBD_EP_1, 0x4);
    USBD_SetEPRxTxStatus(USBD_EP_1, USBD_EP_STATUS_NAK, USBD_EP_STATUS_VALID);
   
    //endpoint addr
    for(i = 0; i < USB_EP_NUM; i++)
    {
        USBD_SetEpAddr((USBD_EP_T)i, i);
    }
   
    USBD_SetDeviceAddr(0);
    USBD_Enable();
}
USB的输出端点处理
void HidMouse_EPHandler(uint8_t ep, uint8_t dir)
{
    if(dir == 0)    //out endpoint
    {
        switch(ep)
        {
            case    USBD_EP_0:
                break;
            case    USBD_EP_1:
                USBD_ReadDataFromEP(USBD_EP_1,s_usb_recv_buff,4);
                USBD_SetEPRxStatus(USBD_EP_1, USBD_EP_STATUS_VALID);    //recv data valid
                //recv data process   
                if(s_usb_recv_buff[0]&0x01)
                {
                    GPIO_ResetBits(GPIOE,GPIO_PIN_5);
                }else
                {
                    GPIO_SetBits(GPIOE,GPIO_PIN_5);
                }
               
                if(s_usb_recv_buff[1]&0x01)
                {
                    GPIO_ResetBits(GPIOE,GPIO_PIN_6);
                }else
                {
                    GPIO_SetBits(GPIOE,GPIO_PIN_6);
                }
               
                break;
            case    USBD_EP_2:
                break;
            case    USBD_EP_3:
                break;
            case    USBD_EP_4:
                break;
            case    USBD_EP_5:
                break;
            case    USBD_EP_6:
                break;
            case    USBD_EP_7:
                break;
        }        
    }else
    {
        //in endpoint
        switch(ep)
        {
            case    USBD_EP_0:
                break;
            case    USBD_EP_1:
                s_statusEP = 1; //endpoint1 can send data
                break;
            case    USBD_EP_2:
                break;
            case    USBD_EP_3:
                break;
            case    USBD_EP_4:
                break;
            case    USBD_EP_5:
                break;
            case    USBD_EP_6:
                break;
            case    USBD_EP_7:
                break;
        }        
    }

}
USB的输入报告处理
void HidMouse_Write(uint8_t key)
{
    static  int8_t x = 0;
    static  int8_t y = 0;
    uint8_t buffer[8] = {0, 0, 0, 0};
  
    switch (key)
    {
        case HID_MOUSE_KEY_LEFT:
            x -= 10;
            buffer[5] = 3;
            buffer[6] = 0x01;
        break;
        
        case HID_MOUSE_KEY_RIGHT:
            x += 10;
            buffer[5] = 7;
            buffer[6]  = 0x02;
        break;
        
        case HID_MOUSE_KEY_UP:
            y -= 10;
        break;
        
        case HID_MOUSE_KEY_DOWN:
            y += 10;
        break;
        
        default:
            return;
    }

    buffer[0] = x;
    buffer[1] = y;

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


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



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



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





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




使用特权

评论回复
沙发
gxliu08| | 2022-5-28 21:20 | 只看该作者
感谢分享,学习学习

使用特权

评论回复
板凳
地球十强666| | 2022-6-12 22:51 | 只看该作者
手动点赞,,另。。。国产芯片要走的路还很长啊。。

使用特权

评论回复
地板
isseed| | 2022-9-7 16:20 | 只看该作者
手柄应该怎么和单片机建立联系??

使用特权

评论回复
5
maudlu| | 2022-9-7 18:13 | 只看该作者
低成本USB单片机吗  

使用特权

评论回复
6
chenjun89| | 2022-9-7 18:17 | 只看该作者
可以自己做个游戏手柄吗?

使用特权

评论回复
7
biechedan| | 2022-9-7 19:45 | 只看该作者
单片机处理USB接口手柄程序可用于USB通信实现

使用特权

评论回复
8
Bowclad| | 2022-9-7 20:29 | 只看该作者
手柄怎么连接单片机?

使用特权

评论回复
9
sdlls| | 2022-9-7 20:51 | 只看该作者
USB手柄无需驱动程序?

使用特权

评论回复
10
232321122| | 2022-9-8 10:42 | 只看该作者
属于USB HID设备

使用特权

评论回复
11
typeof| | 2022-9-8 11:40 | 只看该作者
如何使用游戏手柄控制单片机控制电机

使用特权

评论回复
12
MessageRing| | 2022-10-4 20:31 | 只看该作者
这不就能diy了

使用特权

评论回复
13
jianjunbin| | 2023-4-12 17:53 | 只看该作者
mark一下,学习学习!

使用特权

评论回复
14
emanages| | 2023-12-6 14:58 | 只看该作者
感谢分享,学习学习

使用特权

评论回复
15
gx19890101| | 2024-4-10 13:49 | 只看该作者
看看 啊啊啊

使用特权

评论回复
16
OKAKAKO| | 2024-4-15 20:09 | 只看该作者
学习一下枚举的使用

使用特权

评论回复
17
szt1993| | 2024-4-16 19:44 | 只看该作者
枚举确实很有用

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

119

主题

4600

帖子

27

粉丝