HID设备(USB键鼠/扫码枪)转串口(UART)键盘键值及字符处理示例——CH9350

本文详细介绍了CH9350 USB转串口通讯控制芯片的功能和应用,该芯片能够将USB键盘鼠标与USB主机之间的通讯转换为异步串口方式,适用于USB HOST或SLAVE模式。文章提供了芯片的引脚描述、工作模式设置及键盘报文示例,适合嵌入式系统设计者参考。
该文章已生成可运行项目,

CH9350是USB键盘鼠标转串口通讯控制芯片,需成对使用。结合异步串口简单易用的特点,实现将USB键盘鼠标和USB主机之间USB通讯方式扩展为异步串口(UART)的方式。这个芯片可以拿来做USB的HOST或SLAVE,HOST模式可以连接两个HID子设备,接收USB键鼠或者扫码枪的输入。当然现阶段也有很多的高端系列的单片机本身芯片就自带USB的HOST,也可以进行选用。

CH系列比较出名的是CH340,和CH9350是同一家的,手册官网地址 http://www.wch.cn/downloads/CH9350DS_PDF.html

这是官方的原理图示意:

引脚描述:

TTL读取HID设备,需要将SEL悬空或上拉,设置为下位机模式;然后将S0或S1一个或两个脚拉低,去除芯片上电的状态查询,或者不拉低使用TTL回复一下终止状态查询也可以。LED1,LED2指示灯当有消息的时候会拉低消息结束拉高,可以作为接收到消息的中断触发。然后就是按照指定报文处理,获取输入的数据。

以键盘为例(扫码枪一般模拟键盘输入)报文示例如下:

全键盘码值表如下提供参考:

//Keybord keyvalue define
#define KEY_NULL 0x00          // NULL
#define KEY_A 0x04             // A
#define KEY_B 0x05             // B
#define KEY_C 0x06             // C
#define KEY_D 0x07             // D
#define KEY_E 0x08             // E
#define KEY_F 0x09             // F
#define KEY_G 0x0A             // G
#define KEY_H 0x0B             // H
#define KEY_I 0x0C             // I
#define KEY_J 0x0D             // J
#define KEY_K 0x0E             // K
#define KEY_L 0x0F             // L
#define KEY_M 0x10             // M
#define KEY_N 0x11             // N
#define KEY_O 0x12             // O
#define KEY_P 0x13             // P
#define KEY_Q 0x14             // Q
#define KEY_R 0x15             // R
#define KEY_S 0x16             // S
#define KEY_T 0x17             // T
#define KEY_U 0x18             // U
#define KEY_V 0x19             // V
#define KEY_W 0x1A             // W
#define KEY_X 0x1B             // X
#define KEY_Y 0x1C             // Y
#define KEY_Z 0x1D             // Z
#define KEY_1 0x1E             // 1 and !
#define KEY_2 0x1F             // 2 and @
#define KEY_3 0x20             // 3 and #
#define KEY_4 0x21             // 4 and $
#define KEY_5 0x22             // 5 and %
#define KEY_6 0x23             // 6 and ^
#define KEY_7 0x24             // 7 and &
#define KEY_8 0x25             // 8 and *
#define KEY_9 0x26             // 9 and (
#define KEY_0 0x27             // 10 and )
#define KEY_ENTER 0x28         // ENTER
#define KEY_ESC 0x29           // ESC
#define KEY_BACKSPACE 0x2A     // BACKSPACE
#define KEY_TAB 0x2B           // TAB
#define KEY_SPACE 0x2C         // SPACE
#define KEY_SUB 0x2D           // - and _
#define KEY_EQUAL 0x2E         // = and +
#define KEY_LEFT_BRACKET 0x2F  // [ and {
#define KEY_RIGHT_BRACKET 0x30 // ] and }
#define KEY_VERTICAL_LINE 0x31 // "\" and |
#define KEY_WAVE 0x32          // ` and ~
#define KEY_SEMICOLON 0x33     // ; and :
#define KEY_QUOTE 0x34         // ' and "
#define KEY_THROW 0x35         // ~ and `
#define KEY_COMMA 0x36         // , and <
#define KEY_DOT 0x37           // . and >
#define KEY_QUESTION 0x38      // / and ?
#define KEY_CAPS_LOCK 0x39     // CAPS
#define KEY_F1 0x3A
#define KEY_F2 0x3B
#define KEY_F3 0x3C
#define KEY_F4 0x3D
#define KEY_F5 0x3E
#define KEY_F6 0x3F
#define KEY_F7 0x40
#define KEY_F8 0x41
#define KEY_F9 0x42
#define KEY_F10 0x43
#define KEY_F11 0x44
#define KEY_F12 0x45
#define KEY_PRT_SCR 0x46
#define KEY_SCOLL_LOCK 0x47
#define KEY_PAUSE 0x48
#define KEY_INS 0x49
#define KEY_HOME 0x4A
#define KEY_PAGEUP 0x4B
#define KEY_DEL 0x4C
#define KEY_END 0x4D
#define KEY_PAGEDOWN 0x4E
#define KEY_RIGHT_ARROW 0x4F
#define KEY_LEFT_ARROW 0x50
#define KEY_DOWN_ARROW 0x51
#define KEY_UP_ARROW 0x52
//Num Pad
#define KEY_PAD_NUMLOCK 0x53
#define KEY_PAD_DIV 0x54
#define KEY_PAD_MUL 0x55
#define KEY_PAD_SUB 0x56
#define KEY_PAD_ADD 0x57
#define KEY_PAD_ENTER 0x58
#define KEY_PAD_1 0x59
#define KEY_PAD_2 0x5A
#define KEY_PAD_3 0x5B
#define KEY_PAD_4 0x5C
#define KEY_PAD_5 0x5D
#define KEY_PAD_6 0x5E
#define KEY_PAD_7 0x5F
#define KEY_PAD_8 0x60
#define KEY_PAD_9 0x61
#define KEY_PAD_0 0x62
#define KEY_PAD_DOT 0x63
#define KEY_PRESSED 0x00
#define KEY_RELEASED 0x01
// Control
#define KEY_LCTRL 0xE0  // left ctrl // #define KEY_LCTRL 0x01
#define KEY_LALT 0xE2   // left Alt // #define KEY_LALT 0x04
#define KEY_LSHFIT 0xE1 // left Shift // #define KEY_LSHFIT 0x02
#define KEY_LWIN 0xE3   // left windows // #define KEY_LWIN 0x08
#define KEY_RWIN 0xE7   // right windows // #define KEY_RWIN 0x80
#define KEY_RSHIFT 0xE5 // right Shift // #define KEY_RSHIFT 0x20
#define KEY_RALT 0xE6   // right Alt // #define KEY_RALT 0x40
#define KEY_RCTRL 0xE4  // right Ctrl // #define KEY_RCTRL 0x10
#define KEY_APP 0x65    // Application // #define KEY_APP 0x65
#define KEY_K14 0x89    // international key
#define KEY_KR_L 0x91
#define KEY_K107 0x85
#define KEY_K45 0x64
#define KEY_K42 0x32
#define KEY_K131 0x8b
#define KEY_K132 0x8a
#define KEY_K133 0x88
#define KEY_K56 0x87
#define KEY_KR_R 0x90

可以根据自己的需要编写中断处理如下(FreeRTOS示例):

void UART1_IRQHandler(void)
{
    u8 u8InChar = 0xFF;
    u8 u8ASCII;
    u32 u32IntSts = UART1->INTSTS;
    signed portBASE_TYPE xHigherPriorityTaskWoken;

    xHigherPriorityTaskWoken = pdFALSE;
    if (u32IntSts & UART_INTSTS_RDAINT_Msk)
    {
        if(1) 
        {
            /* Get all the input characters */
            while (UART_IS_RX_READY(UART1))
            {
                /* Get the character from UART Buffer */
                u8InChar = UART_READ(UART1);
                if(0x57 == u8InChar && 0 == USB_READ_CNT)
                {
                    USB_READ_CNT = 1;
                }
                else if(0xAB == u8InChar)
                {
                    USB_READ_CNT = 2;
                }
                else if (2 == USB_READ_CNT)
                {
                    if(0x86 == u8InChar)
                    {
                        /* USB Unplug: 57 ab 86 */
                        USB_READ_CNT = 0;
                        xSemaphoreGiveFromISR( sem_usb_unplug, &xHigherPriorityTaskWoken );
                        if( xHigherPriorityTaskWoken != pdFALSE )
                        {
                            vPortYieldFromISR();
                        }
                    }
                    else if(0x80 == u8InChar)
                    {
                        /* USB Plug in: 57 ab 80 31 */
                        USB_READ_CNT = 0;
                        xSemaphoreGiveFromISR( sem_usb_plug, &xHigherPriorityTaskWoken );
                        if( xHigherPriorityTaskWoken != pdFALSE )
                        {
                            vPortYieldFromISR();
                        }
                    }else
                    {
                        /* DATA Frame: 57 ab 01 00 00 28 00 00 00 00 00 */
                        USB_READ_CNT = 3;
                    }                    
                }
                else
                {
                    if(USB_READ_CNT > 3)
                    {
                        /* USB value TO ASCII value */
                        u8ASCII = USB_TO_ASCII(u8InChar); 
                        if(u8ASCII)
                        {
                            USB_BUFF[USB_BUFF_CNT] = u8ASCII;
                            USB_BUFF_CNT++;
                        }
                    }
                    USB_READ_CNT++;
                    if(USB_READ_CNT >= 11) USB_READ_CNT = 0;/* last(8th) DATA in Frame */
                }
            }
        }
    }
}

信号量和USB键值转ASCII键值的处理就不贴了。这个片子用下来的不足就是封装太大,估计是量太少,还没能做到像CH340/CH340-E那样的封装。

本文章已经生成可运行项目
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值