发新帖本帖赏金 40.00元(功能说明)我要提问
返回列表
打印
[APM32F0]

APM32F072 USB键盘+鼠标

[复制链接]
1235|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Peixu|  楼主 | 2024-7-29 10:32 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Peixu 于 2024-8-2 09:55 编辑

[url=home.php?mod=space&uid=760190]@21小跑堂 #申请原创#[/url]
这次给大家介绍一下如何用APM32F072的USB HID配置一个 USB键盘+鼠标 复合设备的过程。
首先我们需要1个USB键盘的例程(官方有例程)
第二步我们需要1个USB 鼠标的例程  (官方有例程)
第三步将他们结合起来变成USB 键盘+鼠标

这里我们用USB鼠标的例程基础上添加键盘的功能。

第亿、打开USB_HID例程,修改USBD_ConfigDesc中的(USBD_CONFIG_DESCRIPTOR_SIZE)。
如下图所示的宏定义。配置集合的长度,由之前的34,改为41.


第二、USBD_ConfigDesc函数继续往下走找到
1、端点个数:由0x01变成0x02.
2、接口协议:由0x02(鼠标)变成0x01(键盘)。
这里主要还是以键盘功能为主,鼠标只是以一个附属功能加入到了键盘里。

3、在原来的鼠标例程上的最下面增加了一个输出端点的描述符:

第三,在usbd_hid.c修改USBD_HIDReportDesc函数报告描述符的长度:之前这里是鼠标的报告描述符,长度是74 改成117


接下来就是将键盘和鼠标的报告描述符合并为一个数组,分别在键盘和鼠标的报告描述符中放一个报告ID,
键盘的报告ID是1,鼠标的报告ID是2。这样USB主机就可以区分开收到的数据是键盘或是鼠标的数据。


这是加入后HID键盘+鼠标里的完整报告描述符
uint8_t USBD_HIDReportDesc[USBD_HID_MOUSE_REPORT_DESC_SIZE] =
{

    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x06,                    // USAGE (Keyboard)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x01,                    //   REPORT_ID (1)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x08,                    //   REPORT_COUNT (8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
    0x95, 0x05,                    //   REPORT_COUNT (5)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x05, 0x08,                    //   USAGE_PAGE (LEDs)
    0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
    0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
    0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x75, 0x03,                    //   REPORT_SIZE (3)
    0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
    0x95, 0x06,                    //   REPORT_COUNT (6)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
    0xc0,                           // END_COLLECTION
               
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x02,                    // USAGE (Mouse)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x02,                    //   REPORT_ID (2)
    0x09, 0x01,                    //   USAGE (Pointer)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x05, 0x09,                    //     USAGE_PAGE (Button)
    0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
    0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
    0x95, 0x03,                    //     REPORT_COUNT (3)
    0x75, 0x01,                    //     REPORT_SIZE (1)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x75, 0x05,                    //     REPORT_SIZE (5)
    0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
    0x09, 0x30,                    //     USAGE (X)
    0x09, 0x31,                    //     USAGE (Y)
    0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
    0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
    0x75, 0x08,                    //     REPORT_SIZE (8)
    0x95, 0x02,                    //     REPORT_COUNT (2)
    0x81, 0x06,                    //     INPUT (Data,Var,Rel)
    0xc0,                          //   END_COLLECTION
    0xc0                           // END_COLLECTION
};

这样,我们USB键盘+鼠标二合一就改好了, 那么需要怎么使用呢?
第三、鼠标和键盘的使用属性简单介绍:
1、Mouse 鼠标:
我们用的鼠标主要就四个属性:键位(左键、右键、中键),左右移动、上下移动、滑轮
第 1 个字节(buff[0]):按钮状态    0x01左键   0x02右键   0x04中键(滚轮按钮)
第 2 个字节(buff[1]):X 轴移动量
第 3 个字节(buff[2]):Y 轴移动量
第 4 个字节(buff[3]):滚轮移动量  0x01表示滚轮向前滚动一格;0xFF表示滚轮向后滚动一格;0x80是个中间值,不滚动。
以下是一个简单的鼠标使用发送函数示例:
void HidMouse_Write(uint8_t key)
{
    int8_t x = 0;
    int8_t y = 0;
       
    int8_t Button = 0;
    int8_t Wheel = 0;
       
    uint8_t buffer[4] = {0, 0, 0, 0};

    switch (key)
    {
        case HID_MOUSE_KEY_LEFT:
            x -= 10;                       
        break;

        case HID_MOUSE_KEY_RIGHT:
            x += 10;
        break;

        case HID_MOUSE_KEY_UP:
            y -= 10;               
        break;

        case HID_MOUSE_KEY_DOWN:
            y += 10;
        break;

        case HID_MOUSE_BUTTON:
            Button = 0x01;                        //0x01左键   0x02右键   0x04中键(滚轮按钮)
        break;
                               
        case HID_MOUSE_WHEEL:
            Wheel = 0xff;                //0x01表示滚轮向前滚动一格;0xFF表示滚轮向后滚动一格;0x80是个中间值,不滚动。
        break;                               
        default:
            return;
    }
    buffer[0] = Button;
    buffer[1] = x;
    buffer[2] = y;
    buffer[3] = Wheel;
               
    s_statusEP = 0;

    USBD_TxData(USBD_EP_1, buffer, sizeof(buffer));
}

2、Keyboard 键盘:
在键盘 HID 报告格式中,每个字节代表不同的含义:
第 1 个字节(buff[0]) 修饰键的状态(如 Ctrl、Alt、Shift 等)。
0x01 表示左 Ctrl 按下。
0x02 表示左 Shift 按下。
0x04 表示左 Alt 按下。
依此类推。
第 2 个字节(buff[1]):保留字节,通常为 0,不使用。
第 3 到第 8 个字节(buff[2] - buff[7]):按键代码,最多可以同时报告 6 个按键。
例如:
0x04 表示字母 'A' 键。
0x05 表示字母 'B' 键。
依此类推。
以下是一个简单的键盘使用发送函数示例:A-Z
void USB_DevUserApplication(void)
{
    static uint8_t userAppState = USER_APP_INIT;
    static uint8_t interval = 0;
    static uint8_t report[8] = { 0 };
    static uint8_t i = 4;

    switch (userAppState)
    {
        case USER_APP_INIT:
            interval = USBD_CUSTOM_HID_ReadInterval(&gUsbDeviceFS);

            report[0] = 0;
            report[1] = 0;
            report[2] = 0;
            report[3] = 0;
            userAppState = USER_APP_RUN;
            break;

        case USER_APP_RUN:
            if (!APM_MINI_PBGetState(BUTTON_KEY1))
            {
                APM_DelayMs(10);
                if (!APM_MINI_PBGetState(BUTTON_KEY1))
                {
                    if(i > 29)
                    {
                        i = 4;
                        report[2] = KEYBOARD_ENTER;
                        USBD_CUSTOM_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
                        APM_DelayMs(20);
                        report[2] = 0;
                        USBD_CUSTOM_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
                        APM_DelayMs(20);
                    }
                    
                    report[2] = i;
                    USBD_CUSTOM_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
                    
                    APM_DelayMs(20);
                    
                    report[2] = 0;
                    USBD_CUSTOM_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
                    
                    i++;
                    
                    while(!APM_MINI_PBGetState(BUTTON_KEY1));
                }
            }

            APM_DelayMs(interval);
            break;
    }
}

现在我们将它结合起来向USB主机发送数据的时候就需要做出改变了,现在的数组的第一个元素是报告ID,后面才是键盘数据或鼠标数据。
在上面的两个示例中,USB键盘我们定义了一个8元素的数组,USB鼠标我们定义了一个4元素的数组。
现在我们需要一个数组,在同一时间的时候只发送一种数据,再加上报告ID,所以变成9个.
以下是一个简单的键+鼠标使用发送函数示例
void USB_DevUserApplication(void)
{
    static uint8_t userAppState = USER_APP_INIT;
    static uint8_t interval = 0;

    uint8_t KeyBoard[9] = {1,0,0,0,0,0,0,0,0};
    uint8_t Mouse[9] = {2,0,0,0,0,0,0,0,0};
    static uint8_t i = 4;               

    switch (userAppState)
    {
        case USER_APP_INIT:
            interval = USBD_HID_ReadInterval(&gUsbDeviceFS);

            KeyBoard[0] = 0;
            KeyBoard[1] = 0;
            KeyBoard[2] = 0;
            KeyBoard[3] = 0;
            userAppState = USER_APP_RUN;
            break;

        case USER_APP_RUN:
            if (!APM_MINI_PBGetState(BUTTON_KEY1))
            {
                APM_DelayMs(10);
                if (!APM_MINI_PBGetState(BUTTON_KEY1))
                {
                    if(i > 29)
                    {
                        i = 4;
                        KeyBoard[3] = KEYBOARD_ENTER;
                        USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)KeyBoard, sizeof(KeyBoard));
                        APM_DelayMs(20);
                        KeyBoard[3] = 0;
                        USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)KeyBoard, sizeof(KeyBoard));
                        APM_DelayMs(20);
                    }
                                                                                KeyBoard[3] = i;
                    USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)KeyBoard, sizeof(KeyBoard));
                    
                    APM_DelayMs(20);
                    
                    KeyBoard[3] = 0;
                    USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)KeyBoard, sizeof(KeyBoard));
                    
                    i++;
                    
                    while(!APM_MINI_PBGetState(BUTTON_KEY1));
                }
            }

            if (!APM_MINI_PBGetState(BUTTON_KEY2))
            {
                APM_DelayMs(10);
                if (!APM_MINI_PBGetState(BUTTON_KEY2))
                {
                                                                                Mouse[3] -= 10;
                    USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)Mouse, sizeof(Mouse));
                }
            }

            APM_DelayMs(interval);
            break;
    }
}


使用特权

评论回复

打赏榜单

21小跑堂 打赏了 40.00 元 2024-07-31
理由:恭喜通过原创审核!期待您更多的原创作品~

评论
21小跑堂 2024-7-31 17:38 回复TA
基于M32F072单片机移植USB键盘加鼠标复合驱动,过程讲解详细,代码展出完整。 
沙发
gouguoccc| | 2024-8-1 08:13 | 只看该作者
我晕,一大饼代码还有乱码,看的心累啊。

使用特权

评论回复
发新帖 本帖赏金 40.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

42

帖子

0

粉丝