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

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那样的封装。

  • 6
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
STM32F103C8 Serial(UART) to USB HID Keyboard Mouse 串口 USB键盘鼠标 (1) 使用Composite Device 组合(复合)设备 (1.1) 1个Device -> 1个 Configuation -> 2个Interfance (Keyboard & Mouse) (1.2) Keyboard Interfance -> HID (boot mode) -> 2个Endpoint(IN_0x81 & OUT_0x01) -> KeyboardReportDescriptor(不使用Report ID) (1.3) Mouse Interfance -> HID (boot mode) -> 1个Endpoint(IN_0x82) -> MouseReportDescriptor(不使用Report ID) (1.4) 使用HID boot模式, 不使用Report ID, 以便兼容在 计算器设定BIOS模式 中的操作 (2) 串口接收 命令 (2.1) UART协议: 115200, n, 8, 1 (2.2) 1帧发送字符串格式, 以 '{'开始; '}'结束; ','分隔. 共9个10进制数字 例如: {1,2,3,4,5,6,7,8,9} (2.3) 第9位 区分 Keyboard(64) 或是 Mouse(128) 命令 例如: {0,0,0,0,0,0,0,0,64} --- 发送Keyboard命令 {0,0,0,0,0,0,0,0,128} --- 发送Keyboard命令 (3) 发送Keyboard键盘命令时 : 第1~8位 分别如下 (3.1) 第1位 : Key_Release = 0x00, Left_Control = 0x01, Left_Shift = 0x02, Left_Alt = 0x04, Left_GUI = 0x08, Right_Control = 0x10, Right_Shift = 0x20, Right_Alt = 0x40, Right_GUI = 0x80, 例如: {8,0,0,0,0,0,0,0,64} --- 发送 Win_Key键 {128,0,0,0,0,0,0,0,64} --- 发送 WinApp_Key键 {32,0,0,0,0,0,0,0,64} --- 发送 右Shift键 (3.2) 第2位 : 保留,不使用,一律填0 (3.3) 第3~8位 : 可以同时发送6个Keyboard按键 例如: {0,0,4,5,6,7,8,9,64} --- 发送 'abcdef'键 {2,0,4,5,6,7,8,9,64} --- 按住 左Shift 发送 'abcdef'键 => 'ABCDEF' {0,0,0,5,0,7,0,9,64} --- 发送 'bdf'键 (0表示 无按键) 按键码 可参阅: (HID Usage ID) http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf https://www.hiemalis.org/~keiji/PC/scancode-translate.pdf https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2 http://www.usb.org/developers/hidpage/Hut1_12v2.pdf (4) 发送Mouse鼠标命令时 : 第1~8位 分别如下 (4.1) 第1位 : Button_Release = 0x00, Left_Button = 0x01, Right_Button = 0x02, Mid_Button = 0x04, 例如: {1,0,0,0,0,0,0,0,128} --- 点击 左键 {2,0,0,0,0,0,0,0,128} --- 点击 右键 {4,0,0,0,0,0,0,0,128} --- 点击 中键 (4.2) 第2~4位 : 移动(X,Y), 滚轮(Wheel) X: -127~127:左右移动鼠标 Y: -127~127:上下移动鼠标 Wheel: -127~127:上下动滚轮 例如: {0,20,-10,0,0,0,0,0,128} --- 鼠标 右移20,上移10 {0,0,0,-30,0,0,0,0,128} --- 滚轮-30 (4.2) 第5~8位 : 保留,不使用,一律填0
CH9326 是一款HID 串口芯片。CH9326 支持双向数据传输,用于接收串口数据,并按照HID设备规范,将数据打包通过USB口上传给计算机,或者从计算机接收符合HID设备USB数据包,并从串口进行发送。通过提供的上位机软件,用户也可自行配置芯片的VID、PID,以及各种字符串描述符。 下图为其一般应用框图: HID串口评估板电路 PCB、原理图截图,见“相关文件”下载工程文件: 说明: P1是USB端口,USB总线包括一对5V电源线和一对数据信号线,通常,+5V电源线是红色,接地线是黑色,D+信号线是绿色,D-信号线是白色。USB总线提供的电源电流最大可以达到500mA,一般情况下,CH9326芯片和低功耗的USB产品可以直接使用USB总线提供的5V电源。 如果USB产品通过其它供电方式提供常备电源,那么CH9326也应该使用该常备电源,如果需要同时使用USB总线的电源,那么可以通过阻值约为1Ω的电阻连接USB总线的5V电源线与USB产品的5V常备电源,并且两者的接地线直接相连接。 P2是TTL串口,TXD是CH9326的串行发送引脚;RXD是CH9326的串行接收引脚。 P3是预留的用户可自行配置使用的4个普通IO引脚。 C3容量为4700pF到0.02μF,用于CH9326内部电源节点退耦,C2容量为0.1μF,用于外部电源退耦。晶体X1、电阻R1和电容C4用于时钟振荡电路。X1是频率为12MHz的石英晶体或者陶瓷晶体,C4和 C5是容量为20pF~47pF的独石或高频瓷片电容。如果X1选用低成本的陶瓷晶体,那么C4和C5的容量必须用该晶体厂家的推荐值,一般情况下是47pF。 附件内容包括:CH9326评估板说明及原理图和参考例程,包含各平台下应用程序库与操作例程。如截图:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值