[活动]

【APM32F107VCT6 MINI开发板测评】+USB HIDKeyboard评测

[复制链接]
223|11
手机看帖
扫描二维码
随时随地手机跟帖
袁胜富|  楼主 | 2023-3-9 21:23 | 显示全部楼层 |阅读模式
本帖最后由 袁胜富 于 2023-3-9 22:48 编辑

一、概述

          在自动化测试项目中,在启动测试按钮等功能的实现具有一定的抉择,最近做项目一开始的方案是利用串口发数据向下位机读取启动引脚的状态,但是由于系统的实时性响应需要很快,数据不停的发,以及其他操作导致系统不稳定,通信时常出现断开现象,软件改来改去没有得到最大的改善于是就考虑使用主板冗余的一个USB端口开模拟HIDKeyboar的方式来模拟键盘按键按下,然后软件采用全局热键的方式来进行设备测试的启停,经过这么一改,目前来说,没有发现问题。所以USB模拟HIDKeyboard用在一些测试场合是很不错的一个选择。借此机会,向大家介绍一下APM32F107VCT6使用USB模拟键盘。

二、实现过程


          USB开发方面的例程极海半导体官网有相关的例程,HIDKeyBoard是在HID例程修改而来的。
usbd_hidkeyboard.h头文件
/* Define to prevent recursive inclusion */
#ifndef _USBD_HIDKEYBOARD_H_
#define _USBD_HIDKEYBOARD_H_

/* Includes */
#include "usbd_core.h"

/** @addtogroup APM32_USB_Library
  @{
  */

/** @addtogroup USBD_HID_Class
  @{
  */

/** @defgroup USBD_HID_Macros Macros
  @{
*/

#define USBD_HID_KEYBOARD_REPORT_DESC_SIZE                                 62
#define USBD_HID_KEYBOARDDESC_SIZE                      9
#define USBD_HID_KEYBOARDFS_INTERVAL                    10
#define USBD_HID_KEYBOARDHS_INTERVAL                    7
#define USBD_HID_KEYBOARDIN_EP_ADDR                     0x81
#define USBD_HID_KEYBOARDIN_EP_SIZE                     0x08
#define USBD_HID_KEYBOARDFS_MP_SIZE                     0x40

#define USBD_CLASS_SET_IDLE                     0x0A
#define USBD_CLASS_GET_IDLE                     0x02

#define USBD_CLASS_SET_REPORT                   0x09
#define USBD_CLASS_GET_REPORT                   0x01

#define USBD_CLASS_SET_PROTOCOL                 0x0B
#define USBD_CLASS_GET_PROTOCOL                 0x03

/**@} end of group USBD_HID_Macros*/

/** @defgroup USBD_HID_Enumerates Enumerates
  @{
  */

/**
* @brief    HID state type
*/
typedef enum
{
    USBD_HID_IDLE,
    USBD_HID_BUSY,
} USBD_HID_STATE_T;

/**@} end of group USBD_HID_Enumerates*/

/** @defgroup USBD_HID_Structures Structures
  @{
  */

/**
* @brief    HID information management
*/
typedef struct
{
    uint8_t             state;
    uint8_t             epInAddr;
    uint8_t             altSettingStatus;
    uint8_t             idleStatus;
    uint8_t             protocol;
} USBD_HID_INFO_T;

extern USBD_CLASS_T USBD_HID_CLASS;

/**@} end of group USBD_HID_Structures*/

/** @defgroup USBD_HID_Functions Functions
  @{
  */

uint8_t USBD_HID_ReadInterval(USBD_INFO_T* usbInfo);
USBD_STA_T USBD_HID_TxReport(USBD_INFO_T* usbInfo, uint8_t* report, uint16_t length);
#endif

usbd_hidkeyboard.c源文件
/*!
* @file        usbd_hid.c
*
* @brief       usb device hid class handler
*
* @version     V1.0.0
*
* @date        2023-01-16
*
* @attention
*
*  Copyright (C) 2023 Geehy Semiconductor
*
*  You may not use this file except in compliance with the
*  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
*  The program is only for reference, which is distributed in the hope
*  that it will be useful and instructional for customers to develop
*  their software. Unless required by applicable law or agreed to in
*  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
*  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
*  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
*  and limitations under the License.
*/

/* Includes */
#include "usbd_hidkeyboard.h"
#include "usbd_stdReq.h"
#include "usbd_dataXfer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/** @addtogroup APM32_USB_Library
  @{
  */

/** @addtogroup USBD_HID_Class
  @{
  */

/** @defgroup USBD_HID_Functions Functions
  @{
  */

static USBD_STA_T USBD_HID_ClassInitHandler(USBD_INFO_T* usbInfo, uint8_t cfgIndex);
static USBD_STA_T USBD_HID_ClassDeInitHandler(USBD_INFO_T* usbInfo, uint8_t cfgIndex);
static USBD_STA_T USBD_HID_SOFHandler(USBD_INFO_T* usbInfo);
static USBD_STA_T USBD_HID_SetupHandler(USBD_INFO_T* usbInfo, USBD_REQ_SETUP_T* req);
static USBD_STA_T USBD_HID_DataInHandler(USBD_INFO_T* usbInfo, uint8_t epNum);

static USBD_DESC_INFO_T USBD_HID_ReportDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_HID_DescHandler(uint8_t usbSpeed);

/**@} end of group USBD_HID_Functions */

/** @defgroup USBD_HID_Structures Structures
  @{
  */

/* HID class handler */
USBD_CLASS_T USBD_HID_CLASS =
{
    /* Class handler */
    "Class HID",
    NULL,
    USBD_HID_ClassInitHandler,
    USBD_HID_ClassDeInitHandler,
    USBD_HID_SOFHandler,

    /* Control endpoint */
    USBD_HID_SetupHandler,
    NULL,
    NULL,
    /* Specific endpoint */
    USBD_HID_DataInHandler,
    NULL,
    NULL,
    NULL,
};

/**@} end of group USBD_HID_Structures*/

/** @defgroup USBD_HID_Variables Variables
  @{
  */

/**
* @brief   HID descriptor
*/
uint8_t USBD_HIDDesc[USBD_HID_KEYBOARDDESC_SIZE] =
{
    /* bLength */
    0x09,
    /* bDescriptorType: HID */
    USBD_DESC_HID,
    /* bcdHID */
    0x11, 0x01,
    /* bCountryCode */
    0x00,
    /* bNumDescriptors */
    0x01,
    /* bDescriptorType */
    USBD_DESC_HID_REPORT,
    /* wItemLength */
    USBD_HID_KEYBOARD_REPORT_DESC_SIZE & 0xFF, USBD_HID_KEYBOARD_REPORT_DESC_SIZE >> 8,

};

/**
* @brief   HID mouse report descriptor
*/
uint8_t USBD_HIDReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_SIZE] =
{
    0x05, 0x01,                                             // Usage Page (Generic Desktop)
    0x09, 0x06,                                             // Usage (Keyboard)
    0xA1, 0x01,                                             // Collection (Application)
    0x05, 0x07,                                             // Usage Page (Key Codes)
    0x19, 0xE0,                                             // Usage Minimum (224)
    0x29, 0xE7,                                             // Usage Maximum (231)
    0x15, 0x00,                                             // Logical Minimum (0)
    0x25, 0x01,                                             // Logical Maximum (1)
    0x75, 0x01,                                             // Report Size (1)
    0x95, 0x08,                                             // Report Count (8)
    0x81, 0x02,                                             // Input (Data,Variable,Absolute)
    0x95, 0x01,                                             // Report Count (1)
    0x75, 0x08,                                             // Report Size (8)
    0x81, 0x01,                                             // Input (Constant)
    0x95, 0x03,                                             // Report Count (3)
    0x75, 0x01,                                             // Report Size (1)
    0x05, 0x08,                                             // Usage Page (LEDs)
    0x19, 0x01,                                             // Usage Minimum (1)
    0x29, 0x03,                                             // Usage Maximum (3)
    0x91, 0x02,                                             // Output (Data,Variable,Absolute)
    0x95, 0x05,                                             // Report Count (5)
    0x75, 0x01,                                             // Report Size (1)
    0x91, 0x01,                                             // Output (Constant,Array,Absolute)
    0x95, 0x06,                                             // Report Count (6)
    0x75, 0x08,                                             // Report Size (8)
    0x26, 0xFF, 0x00,                                       // Logical Maximum (255)
    0x05, 0x07,                                             // Usage Page (Key Codes)
    0x19, 0x00,                                             // Usage Minimum (0)
    0x29, 0x91,                                             // Usage Maximum (145)
    0x81, 0x00,                                             // Input(Data,Array,Absolute)
    0xC0                                                    // End Collection                      */
};

/**@} end of group USBD_HID_Variables*/

/** @defgroup USBD_HID_Functions Functions
  @{
  */

/*!
* @brief       USB device HID configuration handler
*
* @param       usbInfo: usb device information
*
* @param       cfgIndex: configuration index
*
* @retval      USB device operation status
*/
static USBD_STA_T USBD_HID_ClassInitHandler(USBD_INFO_T* usbInfo, uint8_t cfgIndex)
{
    USBD_STA_T usbStatus = USBD_OK;

    USBD_HID_INFO_T* usbDevHID;

    /* Link class data */
    usbInfo->devClass[usbInfo->classID]->classData = (USBD_HID_INFO_T*)malloc(sizeof(USBD_HID_INFO_T));
    usbDevHID = (USBD_HID_INFO_T*)usbInfo->devClass[usbInfo->classID]->classData;
    memset(usbDevHID, 0, sizeof(USBD_HID_INFO_T));

    USBD_USR_Debug("USBD_HID_INFO_T size %d\r\n", sizeof(USBD_HID_INFO_T));

    if (usbDevHID == NULL)
    {
        USBD_USR_LOG("usbDevHID is NULL");
        return USBD_FAIL;
    }

    usbDevHID->epInAddr = USBD_HID_KEYBOARDIN_EP_ADDR;

    if (usbInfo->devSpeed == USBD_SPEED_FS)
    {
        usbInfo->devEpIn[usbDevHID->epInAddr & 0x0F].interval = USBD_HID_KEYBOARDFS_INTERVAL;
    }
    else
    {
        usbInfo->devEpIn[usbDevHID->epInAddr & 0x0F].interval = USBD_HID_KEYBOARDHS_INTERVAL;
    }

    /* Open endpoint */
    USBD_EP_OpenCallback(usbInfo, usbDevHID->epInAddr, EP_TYPE_INTERRUPT, USBD_HID_KEYBOARDIN_EP_SIZE);
    usbInfo->devEpIn[usbDevHID->epInAddr & 0x0F].useStatus = ENABLE;

    usbDevHID->state = USBD_HID_IDLE;

    return usbStatus;
}

/*!
* @brief       USB device HID reset handler
*
* @param       usbInfo: usb device information
*
* @param       cfgIndex: configuration index
*
* @retval      USB device operation status
*/
static USBD_STA_T USBD_HID_ClassDeInitHandler(USBD_INFO_T* usbInfo, uint8_t cfgIndex)
{
    USBD_STA_T usbStatus = USBD_OK;
    USBD_HID_INFO_T* usbDevHID = (USBD_HID_INFO_T*)usbInfo->devClass[usbInfo->classID]->classData;

    /* Close HID EP */
    USBD_EP_CloseCallback(usbInfo, usbDevHID->epInAddr);
    usbInfo->devEpIn[usbDevHID->epInAddr & 0x0F].interval = 0;
    usbInfo->devEpIn[usbDevHID->epInAddr & 0x0F].useStatus = DISABLE;

    if (usbInfo->devClass[usbInfo->classID]->classData != NULL)
    {
        free(usbInfo->devClass[usbInfo->classID]->classData);
        usbInfo->devClass[usbInfo->classID]->classData = 0;
    }

    return usbStatus;
}

/*!
* @brief       USB device HID SOF handler
*
* @param       usbInfo: usb device information
*
* @retval      USB device operation status
*/
static USBD_STA_T USBD_HID_SOFHandler(USBD_INFO_T* usbInfo)
{
    USBD_STA_T  usbStatus = USBD_BUSY;

    return usbStatus;
}

/*!
* @brief       USB device HID SETUP handler
*
* @param       usbInfo: usb device information
*
* @param       req: setup request
*
* @retval      USB device operation status
*/
static USBD_STA_T USBD_HID_SetupHandler(USBD_INFO_T* usbInfo, USBD_REQ_SETUP_T* req)
{
    USBD_STA_T  usbStatus = USBD_OK;
    USBD_HID_INFO_T* usbDevHID = (USBD_HID_INFO_T*)usbInfo->devClass[usbInfo->classID]->classData;

    USBD_DESC_INFO_T descInfo;
    uint8_t request;
    uint8_t reqType;
    uint16_t wValue = req->DATA_FIELD.wValue[0] | req->DATA_FIELD.wValue[1] << 8;
    uint16_t wLength = req->DATA_FIELD.wLength[0] | req->DATA_FIELD.wLength[1] << 8;
    uint16_t status = 0x0000;

    if (usbDevHID == NULL)
    {
        USBD_USR_LOG("usbDevHID is NULL");
        return USBD_FAIL;
    }

    request = req->DATA_FIELD.bRequest;
    reqType = usbInfo->reqSetup.DATA_FIELD.bmRequest.REQ_TYPE_B.type;

    switch (reqType)
    {
        case USBD_REQ_TYPE_STANDARD:
            switch (request)
            {
                /* HID descriptor */
                case USBD_STD_GET_DESCRIPTOR:
                    switch (req->DATA_FIELD.wValue[1])
                    {
                        case USBD_DESC_HID_REPORT:
                            descInfo = USBD_HID_ReportDescHandler(usbInfo->devSpeed);

                            descInfo.size = descInfo.size < wLength ? descInfo.size : wLength;
                            break;

                        case USBD_DESC_HID:
                            descInfo = USBD_HID_DescHandler(usbInfo->devSpeed);

                            descInfo.size = descInfo.size < wLength ? descInfo.size : wLength;
                            break;

                        default:
                            USBD_REQ_CtrlError(usbInfo, req);
                            usbStatus = USBD_FAIL;
                            break;
                    }

                    if (descInfo.desc != NULL)
                    {
                        USBD_CtrlSendData(usbInfo, descInfo.desc, descInfo.size);
                    }

                    break;

                case USBD_STD_GET_STATUS:
                    if (usbInfo->devState == USBD_DEV_CONFIGURE)
                    {
                        USBD_CtrlSendData(usbInfo, (uint8_t*)&status, 2);
                    }
                    else
                    {
                        USBD_REQ_CtrlError(usbInfo, req);
                        usbStatus = USBD_FAIL;
                    }
                    break;

                case USBD_STD_GET_INTERFACE:
                    if (usbInfo->devState == USBD_DEV_CONFIGURE)
                    {
                        USBD_CtrlSendData(usbInfo, (uint8_t*)&usbDevHID->altSettingStatus, 1);
                    }
                    else
                    {
                        USBD_REQ_CtrlError(usbInfo, req);
                        usbStatus = USBD_FAIL;
                    }
                    break;

                case USBD_STD_SET_INTERFACE:
                    if (usbInfo->devState == USBD_DEV_CONFIGURE)
                    {
                        usbDevHID->altSettingStatus = wValue;
                    }
                    else
                    {
                        USBD_REQ_CtrlError(usbInfo, req);
                        usbStatus = USBD_FAIL;
                    }
                    break;

                case USBD_STD_CLEAR_FEATURE:
                    break;

                default:
                    USBD_REQ_CtrlError(usbInfo, req);
                    usbStatus = USBD_FAIL;
                    break;
            }
            break;

        case USBD_REQ_TYPE_CLASS:
            switch (request)
            {
                case USBD_CLASS_SET_IDLE:
                    usbDevHID->idleStatus = req->DATA_FIELD.wValue[1];
                    break;

                case USBD_CLASS_GET_IDLE:
                    USBD_CtrlSendData(usbInfo, (uint8_t*)&usbDevHID->idleStatus, 1);
                    break;

                case USBD_CLASS_SET_PROTOCOL:
                    usbDevHID->protocol = req->DATA_FIELD.wValue[0];
                    break;

                case USBD_CLASS_GET_PROTOCOL:
                    USBD_CtrlSendData(usbInfo, (uint8_t*)&usbDevHID->protocol, 1);
                    break;

                default:
                    USBD_REQ_CtrlError(usbInfo, req);
                    usbStatus = USBD_FAIL;
                    break;
            }
            break;

        case USBD_REQ_TYPE_VENDOR:
            USBD_REQ_CtrlError(usbInfo, req);
            usbStatus = USBD_FAIL;
            break;

        default:
            usbStatus = USBD_FAIL;
            USBD_REQ_CtrlError(usbInfo, req);
            break;
    }

    return usbStatus;
}

/*!
* @brief       USB device HID IN data handler
*
* @param       usbInfo: usb device information
*
* @param       epNum: endpoint number
*
* @retval      USB device operation status
*/
static USBD_STA_T USBD_HID_DataInHandler(USBD_INFO_T* usbInfo, uint8_t epNum)
{
    USBD_STA_T  usbStatus = USBD_OK;
    USBD_HID_INFO_T* usbDevHID = (USBD_HID_INFO_T*)usbInfo->devClass[usbInfo->classID]->classData;

    if (usbDevHID == NULL)
    {
        return USBD_FAIL;
    }

    usbDevHID->state = USBD_HID_IDLE;

    return usbStatus;
}

/*!
* @brief     USB device HID report descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_HID_ReportDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo.desc = USBD_HIDReportDesc;
    descInfo.size = sizeof(USBD_HIDReportDesc);

    return descInfo;
}

/*!
* @brief     USB device HID descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_HID_DescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo.desc = USBD_HIDDesc;
    descInfo.size = sizeof(USBD_HIDDesc);

    return descInfo;
}

/*!
* @brief     USB device HID send report descriptor
*
* @param     usbInfo: usb device information
*
* @param     report: report buffer
*
* @param     length: report data length
*
* @retval    usb descriptor information
*/
USBD_STA_T USBD_HID_TxReport(USBD_INFO_T* usbInfo, uint8_t* report, uint16_t length)
{
    USBD_STA_T  usbStatus = USBD_OK;
    USBD_HID_INFO_T* usbDevHID = (USBD_HID_INFO_T*)usbInfo->devClass[usbInfo->classID]->classData;

    if (usbDevHID == NULL)
    {
        return USBD_FAIL;
    }

    switch (usbInfo->devState)
    {
        case USBD_DEV_CONFIGURE:
            if (usbDevHID->state == USBD_HID_IDLE)
            {
                usbDevHID->state = USBD_HID_BUSY;
                USBD_EP_TransferCallback(usbInfo, usbDevHID->epInAddr, report, length);
            }
            break;

        default:
            break;
    }

    return usbStatus;
}

/*!
* @brief     USB device HID read interval
*
* @param     usbInfo: usb device information
*
* @retval    usb interval
*/
uint8_t USBD_HID_ReadInterval(USBD_INFO_T* usbInfo)
{
    uint8_t interval;

    if (usbInfo->devSpeed == USBD_SPEED_FS)
    {
        interval = USBD_HID_KEYBOARDFS_INTERVAL;
    }
    else
    {
        interval = ((1 << (USBD_HID_KEYBOARDHS_INTERVAL - 1)) / 8);
    }

    return interval;
}usbd_descriptor.h头文件
/*!
* @file        usbd_descriptor.h
*
* @brief       usb device descriptor
*
* @version     V1.0.0
*
* @date        2023-01-16
*
* @attention
*
*  Copyright (C) 2023 Geehy Semiconductor
*
*  You may not use this file except in compliance with the
*  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
*  The program is only for reference, which is distributed in the hope
*  that it will be useful and instructional for customers to develop
*  their software. Unless required by applicable law or agreed to in
*  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
*  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
*  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
*  and limitations under the License.
*/

/* Define to prevent recursive inclusion */
#ifndef _USBD_DESCRIPTOR_H_
#define _USBD_DESCRIPTOR_H_

/* Includes */
#include "usbd_core.h"

/** @addtogroup Examples
  * @brief OTGD HID examples
  @{
  */

/** @addtogroup OTGD_HID
  @{
  */

/** @defgroup OTGD_HID_Macros Macros
  @{
*/

#define USBD_DEVICE_DESCRIPTOR_SIZE             18
#define USBD_CONFIG_DESCRIPTOR_SIZE             34
#define USBD_SERIAL_STRING_SIZE                 26
#define USBD_LANGID_STRING_SIZE                 4
#define USBD_DEVICE_QUALIFIER_DESCRIPTOR_SIZE   10
#define USBD_BOS_DESCRIPTOR_SIZE                12

#define USBD_DEVICE_CAPABILITY_TYPE             0x10
#define USBD_20_EXTENSION_TYPE                  0x02

#define USBD_HID_ITF_CLASS_ID                   0x03
#define USBD_HID_SUB_CLASS_BOOT                 0x01
#define USBD_HID_SUB_CLASS_NBOOT                0x00
#define USBD_HID_ITF_PORTOCOL_NONE              0x00
#define USBD_HID_ITF_PORTOCOL_KEYBOARD          0x01
#define USBD_HID_ITF_PORTOCOL_MOUSE             0x02

/**@} end of group OTGD_HID_Macros*/

/** @defgroup OTGD_HID_Variables Variables
  @{
  */

extern USBD_DESC_T USBD_DESC_FS;

/**@} end of group OTGD_HID_Variables*/

/** @defgroup OTGD_HID_Functions Functions
  @{
  */

/**@} end of group OTGD_HID_Functions */
/**@} end of group OTGD_HID */
/**@} end of group Examples */

#endif
usbd_descriptor.c头文件
/*!
* @file        usbd_descriptor.c
*
* @brief       usb device descriptor configuration
*
* @version     V1.0.0
*
* @date        2023-01-16
*
* @attention
*
*  Copyright (C) 2023 Geehy Semiconductor
*
*  You may not use this file except in compliance with the
*  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
*  The program is only for reference, which is distributed in the hope
*  that it will be useful and instructional for customers to develop
*  their software. Unless required by applicable law or agreed to in
*  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
*  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
*  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
*  and limitations under the License.
*/

/* Includes */
#include "usbd_descriptor.h"
#include "usbd_hidkeyboard.h"
#include <stdio.h>
#include <string.h>

/** @addtogroup Examples
  * @brief OTGD HID examples
  @{
  */

/** @addtogroup OTGD_HID
  @{
  */

/** @defgroup OTGD_HID_Macros Macros
  @{
*/

#define USBD_GEEHY_VID              12619
#define USBD_FS_PID                 1001
#define USBD_LANGID_STR             0x0409
#define USBD_MANUFACTURER_STR       "Geehy"
#define USBD_PRODUCT_STR            "APM32 HIDKeyboard"
#define USBD_CONFIGURATION_STR      "HIDKeyboard Config"
#define USBD_INTERFACE_STR          "HIDKeyboard Interface"

/**@} end of group OTGD_HID_Macros*/

/** @defgroup OTGD_HID_Functions Functions
  @{
  */

static USBD_DESC_INFO_T USBD_FS_DeviceDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_FS_ConfigDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_FS_InterfaceDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_FS_LangIdDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_FS_ManufacturerDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_FS_ProductDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_FS_SerialDescHandler(uint8_t usbSpeed);
#if USBD_SUP_LPM
static USBD_DESC_INFO_T USBD_FS_BosDescHandler(uint8_t usbSpeed);
#endif
static USBD_DESC_INFO_T USBD_OtherSpeedConfigDescHandler(uint8_t usbSpeed);
static USBD_DESC_INFO_T USBD_DevQualifierDescHandler(uint8_t usbSpeed);

/**@} end of group OTGD_HID_Functions */

/** @defgroup OTGD_HID_Structures Structures
  @{
  */

/* USB device descripotr handler */
USBD_DESC_T USBD_DESC_FS =
{
    "HID Keyborad Descriptor",
    USBD_FS_DeviceDescHandler,
    USBD_FS_ConfigDescHandler,
    USBD_FS_InterfaceDescHandler,
    USBD_FS_LangIdDescHandler,
    USBD_FS_ManufacturerDescHandler,
    USBD_FS_ProductDescHandler,
    USBD_FS_SerialDescHandler,
#if USBD_SUP_LPM
    USBD_FS_BosDescHandler,
#endif
    NULL,
    USBD_OtherSpeedConfigDescHandler,
    USBD_DevQualifierDescHandler,
};

/**@} end of group OTGD_HID_Structures*/

/** @defgroup OTGD_HID_Variables Variables
  @{
  */

/**
* @brief   Device descriptor
*/
uint8_t USBD_DeviceDesc[USBD_DEVICE_DESCRIPTOR_SIZE] =
{
    /* bLength */
    0x12,
    /* bDescriptorType */
    USBD_DESC_DEVICE,
    /* bcdUSB */
#if USBD_SUP_LPM
    0x01,            /*<! For resume test of USBCV3.0. Only support LPM USB device */
#else
    0x00,
#endif
    0x02,
    /* bDeviceClass */
    0x00,
    /* bDeviceSubClass */
    0x00,
    /* bDeviceProtocol */
    0x00,
    /* bMaxPacketSize */
    USBD_EP0_PACKET_MAX_SIZE,
    /* idVendor */
    USBD_GEEHY_VID & 0xFF, USBD_GEEHY_VID >> 8,
    /* idProduct */
    USBD_FS_PID & 0xFF, USBD_FS_PID >> 8,
    /* bcdDevice = 2.00 */
    0x00, 0x02,
    /* Index of string descriptor describing manufacturer */
    USBD_DESC_STR_MFC,
    /* Index of string descriptor describing product */
    USBD_DESC_STR_PRODUCT,
    /* Index of string descriptor describing the device serial number */
    USBD_DESC_STR_SERIAL,
    /* bNumConfigurations */
    USBD_SUP_CONFIGURATION_MAX_NUM,
};

/**
* @brief   Configuration descriptor
*/
uint8_t USBD_ConfigDesc[USBD_CONFIG_DESCRIPTOR_SIZE] =
{
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_CONFIGURATION,
    /* wTotalLength */
    USBD_CONFIG_DESCRIPTOR_SIZE & 0xFF,
    USBD_CONFIG_DESCRIPTOR_SIZE >> 8,

    /* bNumInterfaces */
    0x01,
    /* bConfigurationValue */
    0x01,
    /* iConfiguration */
    0x00,
    /* bmAttributes */
#if USBD_SUP_SELF_PWR
    0xE0,
#else
    0xA0,
#endif
    /* MaxPower */
    0x32,

    /* HID Keyboard Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    0x00,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x01,
    /* bInterfaceClass */
    USBD_HID_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    USBD_HID_SUB_CLASS_BOOT,
    /* bInterfaceProtocol */
    USBD_HID_ITF_PORTOCOL_KEYBOARD,
    /* iInterface */
    0x00,

    /* HID descriptor of Keyboard */
    /* bLength */
    0x09,
    /* bDescriptorType: HID */
    USBD_DESC_HID,
    /* bcdHID */
    0x11, 0x01,
    /* bCountryCode */
    0x00,
    /* bNumDescriptors */
    0x01,
    /* bDescriptorType */
    USBD_DESC_HID_REPORT,
    /* wItemLength */
    USBD_HID_KEYBOARD_REPORT_DESC_SIZE  & 0xFF, USBD_HID_KEYBOARD_REPORT_DESC_SIZE  >> 8,

    /* HID Keyboard Endpoint */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_HID_KEYBOARDIN_EP_ADDR,
    /* bmAttributes */
    0x03,
    /* wMaxPacketSize: */
    USBD_HID_KEYBOARDIN_EP_SIZE & 0xFF,
    USBD_HID_KEYBOARDIN_EP_SIZE >> 8,
    /* bInterval: */
    USBD_HID_KEYBOARDFS_INTERVAL,
};

/**
* @brief   Other speed configuration descriptor
*/
uint8_t USBD_OtherSpeedCfgDesc[USBD_CONFIG_DESCRIPTOR_SIZE] =
{
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_OTHER_SPEED,
    /* wTotalLength */
    USBD_CONFIG_DESCRIPTOR_SIZE & 0xFF,
    USBD_CONFIG_DESCRIPTOR_SIZE >> 8,

    /* bNumInterfaces */
    0x01,
    /* bConfigurationValue */
    0x01,
    /* iConfiguration */
    0x00,
    /* bmAttributes */
#if USBD_SUP_SELF_PWR
    0xE0,
#else
    0xA0,
#endif
    /* MaxPower */
    0x32,

    /* HID Mouse Interface */
    /* bLength */
    0x09,
    /* bDescriptorType */
    USBD_DESC_INTERFACE,
    /* bInterfaceNumber */
    0x00,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x01,
    /* bInterfaceClass */
    USBD_HID_ITF_CLASS_ID,
    /* bInterfaceSubClass */
    USBD_HID_SUB_CLASS_BOOT,
    /* bInterfaceProtocol */
    USBD_HID_ITF_PORTOCOL_MOUSE,
    /* iInterface */
    0x00,

    /* HID descriptor of Mouse */
    /* bLength */
    0x09,
    /* bDescriptorType: HID */
    USBD_DESC_HID,
    /* bcdHID */
    0x11, 0x01,
    /* bCountryCode */
    0x00,
    /* bNumDescriptors */
    0x01,
    /* bDescriptorType */
    USBD_DESC_HID_REPORT,
    /* wItemLength */
    USBD_HID_KEYBOARD_REPORT_DESC_SIZE  & 0xFF, USBD_HID_KEYBOARD_REPORT_DESC_SIZE  >> 8,

    /* HID Mouse Endpoint */
    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    USBD_DESC_ENDPOINT,
    /* bEndpointAddress */
    USBD_HID_KEYBOARDIN_EP_ADDR,
    /* bmAttributes */
    0x03,
    /* wMaxPacketSize: */
    USBD_HID_KEYBOARDIN_EP_SIZE & 0xFF,
    USBD_HID_KEYBOARDIN_EP_SIZE >> 8,
    /* bInterval: */
    USBD_HID_KEYBOARDFS_INTERVAL,
};

#if USBD_SUP_LPM
/**
* @brief   BOS descriptor
*/
uint8_t USBD_BosDesc[USBD_BOS_DESCRIPTOR_SIZE] =
{
    /* bLength */
    0x05,
    /* bDescriptorType */
    USBD_DESC_BOS,
    /* wtotalLength */
    0x0C, 0x00,
    /* bNumDeviceCaps */
    0x01,

    /* Device Capability */
    /* bLength */
    0x07,
    /* bDescriptorType */
    USBD_DEVICE_CAPABILITY_TYPE,
    /* bDevCapabilityType */
    USBD_20_EXTENSION_TYPE,
    /* bmAttributes */
    0x02, 0x02, 0x00, 0x00,
};
#endif

/**
* @brief   Serial string descriptor
*/
uint8_t USBD_SerialStrDesc[USBD_SERIAL_STRING_SIZE] =
{
    USBD_SERIAL_STRING_SIZE,
    USBD_DESC_STRING,

    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '0', 0,
    '1', 0
};

/**
* @brief   Language ID string descriptor
*/
uint8_t USBD_LandIDStrDesc[USBD_LANGID_STRING_SIZE] =
{
    /* Size */
    USBD_LANGID_STRING_SIZE,
    /* bDescriptorType */
    USBD_DESC_STRING,
    USBD_LANGID_STR & 0xFF, USBD_LANGID_STR >> 8
};

/**
* @brief   Device qualifier descriptor
*/
uint8_t USBD_DevQualifierDesc[USBD_DEVICE_QUALIFIER_DESCRIPTOR_SIZE] =
{
    /* Size */
    USBD_DEVICE_QUALIFIER_DESCRIPTOR_SIZE,
    /* bDescriptorType */
    USBD_DESC_DEVICE_QUALIFIER,
    0x00,
    0x02,
    0x00,
    0x00,
    0x00,
    USBD_HID_KEYBOARDFS_MP_SIZE, /* In FS device*/
    0x01,
    0x00,
};

/**@} end of group OTGD_HID_Variables*/

/** @defgroup OTGD_HID_Functions Functions
  @{
  */

/*!
* @brief     USB device convert ascii string descriptor to unicode format
*
* @param     desc : descriptor string
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_DESC_Ascii2Unicode(uint8_t* desc)
{
    USBD_DESC_INFO_T descInfo;
    uint8_t* buffer;
    uint8_t str[USBD_SUP_STR_DESC_MAX_NUM];

    uint8_t* unicode = str;
    uint16_t length;
    uint8_t index = 0;

    if (desc == NULL)
    {
        descInfo.desc = NULL;
        descInfo.size = 0;
    }
    else
    {
        buffer = desc;
        length = (strlen((char*)buffer) * 2) + 2;
        /* Get unicode descriptor */
        unicode[index] = length;

        index++;
        unicode[index] = USBD_DESC_STRING;
        index++;

        while (*buffer != '\0')
        {
            unicode[index] = *buffer;
            buffer++;
            index++;

            unicode[index] = 0x00;
            index++;
        }
    }

    descInfo.desc = unicode;
    descInfo.size = length;

    return descInfo;
}

/*!
* @brief     USB device FS device descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_FS_DeviceDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo.desc = USBD_DeviceDesc;
    descInfo.size = sizeof(USBD_DeviceDesc);

    return descInfo;
}

/*!
* @brief     USB device FS configuration descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_FS_ConfigDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo.desc = USBD_ConfigDesc;
    descInfo.size = sizeof(USBD_ConfigDesc);

    return descInfo;
}

#if USBD_SUP_LPM
/*!
* @brief     USB device FS BOS descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_FS_BosDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo.desc = USBD_BosDesc;
    descInfo.size = sizeof(USBD_BosDesc);

    return descInfo;
}
#endif

/*!
* @brief     USB device FS interface descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_FS_InterfaceDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo = USBD_DESC_Ascii2Unicode((uint8_t*)USBD_INTERFACE_STR);

    return descInfo;
}

/*!
* @brief     USB device FS LANG ID string descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_FS_LangIdDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo.desc = USBD_LandIDStrDesc;
    descInfo.size = sizeof(USBD_LandIDStrDesc);

    return descInfo;
}

/*!
* @brief     USB device FS manufacturer string descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_FS_ManufacturerDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo = USBD_DESC_Ascii2Unicode((uint8_t*)USBD_MANUFACTURER_STR);

    return descInfo;
}

/*!
* @brief     USB device FS product string descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_FS_ProductDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo = USBD_DESC_Ascii2Unicode((uint8_t*)USBD_PRODUCT_STR);

    return descInfo;
}

/*!
* @brief     USB device FS serial string descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_FS_SerialDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    descInfo.desc = USBD_SerialStrDesc;
    descInfo.size = sizeof(USBD_SerialStrDesc);

    return descInfo;
}

/*!
* @brief     USB device other speed configuration descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_OtherSpeedConfigDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    /* Use FS configuration */
    descInfo.desc = USBD_OtherSpeedCfgDesc;
    descInfo.size = sizeof(USBD_OtherSpeedCfgDesc);

    return descInfo;
}

/*!
* @brief     USB device device qualifier descriptor
*
* @param     usbSpeed : usb speed
*
* @retval    usb descriptor information
*/
static USBD_DESC_INFO_T USBD_DevQualifierDescHandler(uint8_t usbSpeed)
{
    USBD_DESC_INFO_T descInfo;

    /* Use FS configuration */
    descInfo.desc = USBD_DevQualifierDesc;
    descInfo.size = sizeof(USBD_DevQualifierDesc);

    return descInfo;
}
usb_device_user.h头文件

/*!
* @file        usb_device_user.h
*
* @brief       usb device user function
*
* @version     V1.0.0
*
* @date        2023-01-16
*
* @attention
*
*  Copyright (C) 2023 Geehy Semiconductor
*
*  You may not use this file except in compliance with the
*  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
*  The program is only for reference, which is distributed in the hope
*  that it will be useful and instructional for customers to develop
*  their software. Unless required by applicable law or agreed to in
*  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
*  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
*  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
*  and limitations under the License.
*/

/* Define to prevent recursive inclusion */
#ifndef _USB_DEVICE_USER_H_
#define _USB_DEVICE_USER_H_

/* Includes */
#include "apm32f10x.h"
#include "usbd_core.h"

/** @addtogroup Examples
  * @brief OTGD HID examples
  @{
  */

/** @addtogroup OTGD_HID
  @{
  */

/** @defgroup OTGD_HID_Enumerates Enumerates
  @{
  */

/**
* @brief    USB device application status
*/
typedef enum
{
    USBD_APP_IDLE,
    USBD_APP_SUSPEND,
    USBD_APP_READY,
} USBD_APP_STA_T;

/**@} end of group OTGD_HID_Enumerates*/

/** @defgroup OTGD_HID_Variables Variables
  @{
  */

extern USBD_APP_STA_T gUsbDevAppStatus;
extern USBD_INFO_T gUsbDeviceFS;

/**@} end of group OTGD_HID_Variables*/

/** @defgroup OTGD_HID_Functions Functions
  @{
  */

void USB_DeviceInit(void);
void USB_DeviceReset(void);
void USB_DevUserApplication(void);

/**@} end of group OTGD_HID_Functions */
/**@} end of group OTGD_HID */
/**@} end of group Examples */

#endif

usb_device_user.c源文件
/*!
* @file        usb_device_user.c
*
* @brief       usb device user configuration
*
* @version     V1.0.0
*
* @date        2023-01-16
*
* @attention
*
*  Copyright (C) 2023 Geehy Semiconductor
*
*  You may not use this file except in compliance with the
*  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
*  The program is only for reference, which is distributed in the hope
*  that it will be useful and instructional for customers to develop
*  their software. Unless required by applicable law or agreed to in
*  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
*  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
*  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
*  and limitations under the License.
*/

/* Includes */
#include "usb_device_user.h"
#include "usbd_descriptor.h"
#include "usbd_hid.h"
#include <stdio.h>

/** @addtogroup Examples
  * @brief OTGD HID examples
  @{
  */

/** @addtogroup OTGD_HID
  @{
  */

/** @defgroup OTGD_HID_Variables Variables
  @{
  */

USBD_INFO_T gUsbDeviceFS;

USBD_APP_STA_T gUsbDevAppStatus = USBD_APP_IDLE;

/**@} end of group OTGD_HID_Variables*/

/** @defgroup OTGD_HID_Functions Functions
  @{
  */

/*!
* @brief       User application
*
* @param       None
*
* @retval      None
*/
__weak void USB_DevUserApplication(void)
{
    static USBD_APP_STA_T preAppStatus = USBD_APP_IDLE;

    uint8_t status = gUsbDevAppStatus;

    if (preAppStatus != gUsbDevAppStatus)
    {
        switch (status)
        {
            case USBD_APP_SUSPEND:
                USBD_USR_LOG("USBD_APP_SUSPEND");
                break;

            case USBD_APP_READY:
                USBD_USR_LOG("USBD_APP_READY");
                break;
        }

        preAppStatus = gUsbDevAppStatus;
    }
}

/*!
* @brief       USB device user handler
*
* @param       usbInfo
*
* @param       userStatus
*
* @retval      None
*/
static void USB_DevUserHandler(USBD_INFO_T* usbInfo, uint8_t userStatus)
{
    switch (userStatus)
    {
        case USBD_USER_RESET:
            break;

        case USBD_USER_RESUME:
            break;

        case USBD_USER_SUSPEND:
            gUsbDevAppStatus = USBD_APP_SUSPEND;
            break;

        case USBD_USER_CONNECT:
            break;

        case USBD_USER_DISCONNECT:
            break;

        case USBD_USER_ERROR:
            USBD_USR_Debug("User error");
            break;

        default:
            break;
    }
}

/*!
* @brief       USB device init
*
* @param       None
*
* @retval      None
*/
void USB_DeviceInit(void)
{
    /* USB device and class init */
    USBD_Init(&gUsbDeviceFS, USBD_SPEED_FS, &USBD_DESC_FS, &USBD_HID_CLASS, USB_DevUserHandler);
}

/*!
* @brief       USB device reset
*
* @param       None
*
* @retval      None
*/
void USB_DeviceReset(void)
{
    USBD_DeInit(&gUsbDeviceFS);
}

/**@} end of group OTGD_HID_Functions */
/**@} end of group OTGD_HID */
/**@} end of group Examples */


Keyboard.h头文件
#ifndef KEYBOARD_H
#define KEYBOARD_H

#include "usbd_hidkeyboard.h"


//================================================================================
//================================================================================
//  Keyboard

#define KEY_LEFT_CTRL   0x80
#define KEY_LEFT_SHIFT    0x81
#define KEY_LEFT_ALT    0x82
#define KEY_LEFT_GUI    0x83
#define KEY_RIGHT_CTRL    0x84
#define KEY_RIGHT_SHIFT   0x85
#define KEY_RIGHT_ALT   0x86
#define KEY_RIGHT_GUI   0x87

#define KEY_UP_ARROW    0xDA
#define KEY_DOWN_ARROW    0xD9
#define KEY_LEFT_ARROW    0xD8
#define KEY_RIGHT_ARROW   0xD7
#define KEY_BACKSPACE   0xB2
#define KEY_TAB       0xB3
#define KEY_RETURN      0xB0
#define KEY_ESC       0xB1
#define KEY_INSERT      0xD1
#define KEY_DELETE      0xD4
#define KEY_PAGE_UP     0xD3
#define KEY_PAGE_DOWN   0xD6
#define KEY_HOME      0xD2
#define KEY_END       0xD5
#define KEY_CAPS_LOCK   0xC1
#define KEY_F1        0xC2
#define KEY_F2        0xC3
#define KEY_F3        0xC4
#define KEY_F4        0xC5
#define KEY_F5        0xC6
#define KEY_F6        0xC7
#define KEY_F7        0xC8
#define KEY_F8        0xC9
#define KEY_F9        0xCA
#define KEY_F10       0xCB
#define KEY_F11       0xCC
#define KEY_F12       0xCD

typedef struct
{
    void    (*begin)(void);
    size_t  (*write)(uint8_t k);
    size_t  (*press)(uint8_t k);
    size_t  (*release)(uint8_t k);
    void    (*releaseAll)(void);
    void    (*printf)(char *fmt,...);
}_KeyBorad;


extern _KeyBorad   KeyBorad;

//  Low level key report: up to 6 keys and shift, ctrl etc at once
typedef struct {
  uint8_t modifiers;
  uint8_t reserved;
  uint8_t keys[6];
} KeyReport;

void sendReport(KeyReport *keys);
void begin(void);
size_t write(uint8_t k);
size_t press(uint8_t k);
size_t release(uint8_t k);
void releaseAll(void);

#endif/*KEYBOARD_H*/


Keyboard.c源文件
#include "Keyboard.h"
#include "String.h"
#include "Stdlib.h"
#include "Stdio.h"
#include "Stdarg.h"
#include "board.h"
#include "bsp_delay.h"
#include "apm32f10x_misc.h"
#include "apm32f10x_usart.h"
#include "usb_device_user.h"
#include "usbd_hidkeyboard.h"
#include <stdio.h>
//================================================================================
//================================================================================
//  Keyboard
/**
* @brief User application state
*/






KeyReport _keyReport;


void begin(void)
{
    /* Init USB device */
    USB_DeviceInit();
}


void sendReport(KeyReport *keys)
{
  uint8_t buf[8] = {keys->modifiers, keys->reserved, keys->keys[0], keys->keys[1],
                    keys->keys[2], keys->keys[3], keys->keys[4], keys->keys[5]
                   };
        USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)buf, 8);/*端点上传数据*/


  //delay required to prevent persistent key when call print
  APM_DelayMs(10);
}


//extern const uint8_t _asciimap[128] PROGMEM;


#define SHIFT 0x80
const uint8_t _asciimap[128] = {
  0x00,             // NUL
  0x00,             // SOH
  0x00,             // STX
  0x00,             // ETX
  0x00,             // EOT
  0x00,             // ENQ
  0x00,             // ACK
  0x00,             // BEL
  0x2a,     // BS Backspace
  0x2b,     // TAB  Tab
  0x28,     // LF Enter
  0x00,             // VT
  0x00,             // FF
  0x00,             // CR
  0x00,             // SO
  0x00,             // SI
  0x00,             // DEL
  0x00,             // DC1
  0x00,             // DC2
  0x00,             // DC3
  0x00,             // DC4
  0x00,             // NAK
  0x00,             // SYN
  0x00,             // ETB
  0x00,             // CAN
  0x00,             // EM
  0x00,             // SUB
  0x00,             // ESC
  0x00,             // FS
  0x00,             // GS
  0x00,             // RS
  0x00,             // US


  0x2c,      //  ' '
  0x1e | SHIFT,  // !
  0x34 | SHIFT,  // "
  0x20 | SHIFT,  // #
  0x21 | SHIFT,  // $
  0x22 | SHIFT,  // %
  0x24 | SHIFT,  // &
  0x34,          // '
  0x26 | SHIFT,  // (
  0x27 | SHIFT,  // )
  0x25 | SHIFT,  // *
  0x2e | SHIFT,  // +
  0x36,          // ,
  0x2d,          // -
  0x37,          // .
  0x38,          // /
  0x27,          // 0
  0x1e,          // 1
  0x1f,          // 2
  0x20,          // 3
  0x21,          // 4
  0x22,          // 5
  0x23,          // 6
  0x24,          // 7
  0x25,          // 8
  0x26,          // 9
  0x33 | SHIFT,    // :
  0x33,          // ;
  0x36 | SHIFT,    // <
  0x2e,          // =
  0x37 | SHIFT,    // >
  0x38 | SHIFT,    // ?
  0x1f | SHIFT,    // @
  0x04 | SHIFT,    // A
  0x05 | SHIFT,    // B
  0x06 | SHIFT,    // C
  0x07 | SHIFT,    // D
  0x08 | SHIFT,    // E
  0x09 | SHIFT,    // F
  0x0a | SHIFT,    // G
  0x0b | SHIFT,    // H
  0x0c | SHIFT,    // I
  0x0d | SHIFT,    // J
  0x0e | SHIFT,    // K
  0x0f | SHIFT,    // L
  0x10 | SHIFT,    // M
  0x11 | SHIFT,    // N
  0x12 | SHIFT,    // O
  0x13 | SHIFT,    // P
  0x14 | SHIFT,    // Q
  0x15 | SHIFT,    // R
  0x16 | SHIFT,    // S
  0x17 | SHIFT,    // T
  0x18 | SHIFT,    // U
  0x19 | SHIFT,    // V
  0x1a | SHIFT,    // W
  0x1b | SHIFT,    // X
  0x1c | SHIFT,    // Y
  0x1d | SHIFT,    // Z
  0x2f,          // [
  0x31,          // bslash

  0x23 | SHIFT,  // ^
  0x2d | SHIFT,  // _
  0x35,          // `
  0x04,          // a
  0x05,          // b
  0x06,          // c
  0x07,          // d
  0x08,          // e
  0x09,          // f
  0x0a,          // g
  0x0b,          // h
  0x0c,          // i
  0x0d,          // j
  0x0e,          // k
  0x0f,          // l
  0x10,          // m
  0x11,          // n
  0x12,          // o
  0x13,          // p
  0x14,          // q
  0x15,          // r
  0x16,          // s
  0x17,          // t
  0x18,          // u
  0x19,          // v
  0x1a,          // w
  0x1b,          // x
  0x1c,          // y
  0x1d,          // z
  0x2f | SHIFT,  // {
  0x31 | SHIFT,  // |
  0x30 | SHIFT,  // }
  0x35 | SHIFT,  // ~
  0       // DEL
};


#define pgm_read_byte(addr) (*(const unsigned char *)(addr))




size_t press(uint8_t k)
{
  uint8_t i;
  if (k >= 136) {     // it's a non-printing key (not a modifier)
    k = k - 136;
  } else if (k >= 128) {  // it's a modifier key
    _keyReport.modifiers |= (1 << (k - 128));
    k = 0;
  } else {        // it's a printing key
    k = pgm_read_byte(_asciimap + k);
    if (!k) {
      return 0;
    }
    if (k & 0x80) {           // it's a capital letter or other character reached with shift
      _keyReport.modifiers |= 0x02; // the left shift modifier
      k &= 0x7F;
    }
  }


  // Add k to the key report only if it's not already present
  // and if there is an empty slot.
  if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
      _keyReport.keys[2] != k && _keyReport.keys[3] != k &&
      _keyReport.keys[4] != k && _keyReport.keys[5] != k) {


    for (i = 0; i < 6; i++) {
      if (_keyReport.keys == 0x00) {
        _keyReport.keys = k;
        break;
      }
    }
    if (i == 6) {
     return 0;
    }
  }
  sendReport(&_keyReport);
  return 1;
}


// release() takes the specified key out of the persistent key report and
// sends the report.  This tells the OS the key is no longer pressed and that
// it shouldn't be repeated any more.
size_t release(uint8_t k)
{
  uint8_t i;
  if (k >= 136) {     // it's a non-printing key (not a modifier)
    k = k - 136;
  } else if (k >= 128) {  // it's a modifier key
    _keyReport.modifiers &= ~(1 << (k - 128));
    k = 0;
  } else {        // it's a printing key
    k = pgm_read_byte(_asciimap + k);
    if (!k) {
      return 0;
    }
    if (k & 0x80) {             // it's a capital letter or other character reached with shift
      _keyReport.modifiers &= ~(0x02);  // the left shift modifier
      k &= 0x7F;
    }
  }


  // Test the key report to see if k is present.  Clear it if it exists.
  // Check all positions in case the key is present more than once (which it shouldn't be)
  for (i = 0; i < 6; i++) {
    if (0 != k && _keyReport.keys == k) {
      _keyReport.keys = 0x00;

    }
  }


  sendReport(&_keyReport);
  return 1;
}


void releaseAll(void)
{
  _keyReport.keys[0] = 0;
  _keyReport.keys[1] = 0;
  _keyReport.keys[2] = 0;
  _keyReport.keys[3] = 0;
  _keyReport.keys[4] = 0;
  _keyReport.keys[5] = 0;
  _keyReport.modifiers = 0;
  sendReport(&_keyReport);
}


size_t write(uint8_t c)
{
  uint8_t p = press(c);  // Keydown
  release(c);            // Keyup
  return p;              // just return the result of press() since release() almost always returns 1
}


/**
* 自动格式输出
*/
void print(char *fmt,...)
{
    char T1_Bufferr[128];
    uint16_t i,j;
    va_list ap;
    va_start(ap,fmt);
    vsprintf(T1_Bufferr,fmt,ap);
    va_end(ap);
    i=strlen(T1_Bufferr);
    for(j=0;j<i;j++)
    {
        write(T1_Bufferr[j]);
    }
}


//结构体初始化
_KeyBorad   KeyBorad =
{
        begin,
        write,
        press,
        release,
        releaseAll,
        print
};
main.c源文件

/*!
* @file        main.c
*
* @brief       Main program body
*
* @version     V1.0.0
*
* @date        2023-01-16
*
* @attention
*
*  Copyright (C) 2023 Geehy Semiconductor
*
*  You may not use this file except in compliance with the
*  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
*  The program is only for reference, which is distributed in the hope
*  that it will be useful and instructional for customers to develop
*  their software. Unless required by applicable law or agreed to in
*  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
*  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
*  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
*  and limitations under the License.
*/

/* Includes */
#include "board.h"
#include "bsp_delay.h"
#include "apm32f10x_misc.h"
#include "apm32f10x_usart.h"
#include "usb_device_user.h"
#include "usbd_hidkeyboard.h"
#include <stdio.h>
#include "Keyboard.h"
#define DEBUG_USART    USART1

/*!
* @brief       Main program
*
* @param       None
*
* @retval      int
*/
int main(void)
{
    /* Set the Vector Table base address at 0x08000000 */
    NVIC_ConfigVectorTable(NVIC_VECT_TAB_FLASH, 0x0000);

    USART_Config_T usartConfigStruct;

    /* USART configuration */
    USART_ConfigStructInit(&usartConfigStruct);
    usartConfigStruct.baudRate      = 115200;
    usartConfigStruct.mode          = USART_MODE_TX_RX;
    usartConfigStruct.parity        = USART_PARITY_NONE;
    usartConfigStruct.stopBits      = USART_STOP_BIT_1;
    usartConfigStruct.wordLength    = USART_WORD_LEN_8B;
    usartConfigStruct.hardwareFlow  = USART_HARDWARE_FLOW_NONE;

    /* COM1 init*/
    APM_MINI_COMInit(COM1, &usartConfigStruct);
    APM_MINI_PBInit(BUTTON_KEY1, BUTTON_MODE_GPIO);
    APM_MINI_PBInit(BUTTON_KEY2, BUTTON_MODE_GPIO);

                KeyBorad.begin();

    printf("USB Device HIDKeyboard Application\r\n");

    while (1)
    {
                        if(!APM_MINI_PBGetState(BUTTON_KEY1))
                        {
                                APM_DelayMs(10);
                                if(!APM_MINI_PBGetState(BUTTON_KEY1))
                                {
                                        KeyBorad.printf("Button1 Pressed\n");
                                }
                                while(!APM_MINI_PBGetState(BUTTON_KEY1));
                        }
                        if(!APM_MINI_PBGetState(BUTTON_KEY2))
                        {
                                APM_DelayMs(10);
                                if(!APM_MINI_PBGetState(BUTTON_KEY2))
                                {
                                        KeyBorad.printf("Button2 Pressed\n");
                                }
                                while(!APM_MINI_PBGetState(BUTTON_KEY2));
                        }
                        
    }
}


/*!
* @brief       Redirect C Library function printf to serial port.
*              After Redirection, you can use printf function.
*
* @param       ch:  The characters that need to be send.
*
* @param       *f:  pointer to a FILE that can recording all information
*              needed to control a stream
*
* @retval      The characters that need to be send.
*/
int fputc(int ch, FILE* f)
{
    /* send a byte of data to the serial port */
    USART_TxData(DEBUG_USART, (uint8_t)ch);

    /* wait for the data to be send  */
    while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

    return (ch);
}

三、测试效果

按钮1按下文本里输入
Button1 Pressed,
按钮2按下文本里输入Button2 Pressed,如下图所示
USB测试.png

打开设备管理器,会有HID Keyboard Device,如下图


设备管理器查看.png



蓝牙和其他设备.png

四、使用感想

       国产芯片越来越好了,USB还是挺不错的,接下来有空再测试其他功能模块。感谢极海半导体和21ic共同开展了此次评测活动,有幸参与其中。




   

OTGD_HIDKeyboard.zip

5.66 MB

使用特权

评论回复
评论
forgot 2023-6-28 17:07 回复TA
很好 
forgot| | 2023-6-28 17:07 | 显示全部楼层
感谢楼主的分享,很全面,学习一下,期待更多好的内容

使用特权

评论回复
zerorobert| | 2023-7-10 14:06 | 显示全部楼层
单片机读取电脑USB键盘该怎么弄

使用特权

评论回复
uiint| | 2023-7-10 14:17 | 显示全部楼层
这个hid需要注意什么?
              

使用特权

评论回复
sdCAD| | 2023-7-10 14:50 | 显示全部楼层
APM32F107VCT6 的功能真是强大呢。

使用特权

评论回复
saservice| | 2023-7-10 15:24 | 显示全部楼层
这个HID例程是在哪里下载的?              

使用特权

评论回复
mikewalpole| | 2023-7-10 15:59 | 显示全部楼层
开发HIDKeyboard可以做成触摸的吗?

使用特权

评论回复
maqianqu| | 2023-7-10 16:33 | 显示全部楼层
如何提高反应的灵敏度?              

使用特权

评论回复
zerorobert| | 2023-7-10 17:07 | 显示全部楼层
USB模拟HIDKeyboard确实不错。

使用特权

评论回复
wilhelmina2| | 2023-7-10 17:42 | 显示全部楼层
是自己diy的产品吗?              

使用特权

评论回复
wengh2016| | 2023-7-10 18:21 | 显示全部楼层
USB接口上配置HID描述符,包括发送和接收的数据格式、数据长度等信息。

使用特权

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

本版积分规则

23

主题

131

帖子

2

粉丝