CH554 USB Host配合 ESP32-C3实现USB键盘转蓝牙

之前使用 Ch9350制作过一个 USB Host Shield 【参考1】,能够读取USB键盘鼠标的输入。最近在研究 Ch554 ,使用Ch554e制作了一个同样功能的Shield,配合ESP32-C3 能够实现USB 键盘转蓝牙的功能。

使用 Ch554 的有优点如下:

  1. 价格较低,相对于Ch9350 10元的价格,最便宜的 Ch554e 只要不到1.5元;
  2. 焊接友好,对于 TSSOP-20/SOP-16或者MSOP-10普通人都能够很好的进行焊接;
  3. 如果你的设计对于体积敏感,可以选择MSOP-10 封装的 Ch554e;
  4. 外围电路简单,只需要2个电容和1个电阻

缺点:

  1. 需要自己使用 keil 编写程序;
  2. 兼容性比不上 Ch9350,可能出现无法驱动的USB设备;

这次带来就是基于 Ch554e的设计。硬件部分设计如下:

下方就是CH554e的最小系统,外部配合2个0.1uf电容,以及1个10K电阻即可工作。下载方法是:上电之前短接 DL 位置,然后再上电使用WCHISPStudio即可。不过在研发阶段建议专门准备一个开发板便于操作。同时,官方的例子都是用第一个UART作为调试输出,而Ch554只有第2个 Uart可供使用。

根据上述电路设计的PCB如下:

这是一个底板,上面直接连接 DFRobot ESP32-C3即可。焊接后的板卡如下:

直接安装在 ESP32-C3上即可使用:

接下来开始代码的设计,首先设计的是 Ch554的代码,这里直接使用官方的代码进行简单修改。

为了便于使用我们使用和Ch9350相同的输出格式:

0-157 AB数据头,固定数值
0288表示有效帧值
03NN后续数据长度,从04开始到最后的校验和
0410  固定值 [7:6]:00 - 保留 [5:4]:01 - 鼠标 [3]  :0  - 保留 [2:1]:00 - 未知 [0]  :0  - 端口1
05-AA BB CC…..MM键盘数据,例如:08 00 00 00 00 00 00 00
XXNum帧序列号
XXCheckSum校验和,从05开始的数据和

例如:实际发送的一个数据:

57 AB 88 0B 10 08 00 00 00 00 00 00 00 00 08

代码是基于WCH 官方修改而来的,基本原理是:比较每一次收到的数据(RxBuffer)是否和上一次(LastBuffer)相同,如果不同,那么进行上报。使用上面介绍的数据报文格式:

                        IsSame=TRUE;
                        for ( i = 0; i < len; i ++ ){
                            if (LastBuffer[i]!=RxBuffer[i]) {
                                IsSame=FALSE;
                                LastBuffer[i]=RxBuffer[i];
                            }
                        }
                        //只有与前一次不同才进行输出
                        if (IsSame==FALSE) {
                            checksum=0x00;
                            CH554UART1SendByte(0x57);CH554UART1SendByte(0xAB);CH554UART1SendByte(0x88);CH554UART1SendByte(len+3);CH554UART1SendByte(0x10);
                            for ( i = 0; i < len; i ++ ){
                                CH554UART1SendByte(RxBuffer[i]);
                                checksum=checksum+RxBuffer[i];
                            }
                            checksum=checksum+counter;
                            CH554UART1SendByte(counter); CH554UART1SendByte(checksum);
                            counter++;
                        }

代码使用 Keil4 编译通过。

ESP32-C3代码如下:

#include <Arduino.h>
#include <BleKeyboard.h>

BleKeyboard bleKeyboard;

#define DEBUGMODE 0

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200, SERIAL_8N1, RX, TX);

  bleKeyboard.begin();

}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();
    if (c == '1') {
      Serial.println("get1");
    }
    if (c == '3') {
      ESP.restart();
    }
  }

  //根据 CH9350 Spec 每次最多输出 72Bytes
  byte Data[72];
  unsigned int CounterLast = Serial1.available();
  unsigned int CounterCurrent = 0;


  // 如果当前串口有数据
  if (CounterLast != 0) {
    // 进行简单测试,如果当前还在传输数据那么持续接收
    while (CounterCurrent != CounterLast) {
      CounterLast = Serial1.available();
      delayMicroseconds(500);
      CounterCurrent = Serial1.available();
    }
  }

  if (CounterCurrent > 0) {
    // 一次性将数据收取下来
    Serial1.readBytes(Data, CounterCurrent);
    unsigned int i = 0;
    unsigned int Length;
    while (i < CounterCurrent) {
      // 识别帧头
      if ((Data[i] == 0x57) && (Data[i + 1] == 0xAB)) {
        // 有效键值帧
        if (Data[i + 2] == 0x88) {
          // 获得数据长度
          Length = Data[i + 3];
          if (DEBUGMODE) {
            //Serial.print("Ln:");Serial.print(Length);
            for (int j = 1; j < Length + 1; j++) {
              if (Data[i + 3  + j] < 16) {
                Serial.print("0");
              }
              Serial.print(Data[i + 3  + j], HEX);
              Serial.print(" ");
            }
            Serial.println(" ");
          }

          //如果是键盘
          if (Data[i + 4] == 0x10) {
            if (DEBUGMODE) {
              Serial.print("Key");
              for (int j = 1; j < Length + 1; j++) {
                Serial.print(Data[i + 3  + j], HEX);
                Serial.print(" ");
              }
              Serial.println(" ");
            }
            
            //判断为Dostyle键盘
            if (Data[i + 3  + 1] == 0x10) { 
              if (bleKeyboard.isConnected() == true) {
                bleKeyboard.sendReport((KeyReport*)(&Data[i + 3  + 2]));
              }
            }
          }
          i = i + 3 + Length;
        } else if (Data[i + 2] == 0x82) {
          i = i + 3; // 跳过
        }
      }
      i++;
    } // while (i < Counter)
  }

}

使用时,只需要给ESP32-C3供电,连接好USB键盘后就可以搜索蓝牙键盘进行连接使用了。工作的测试视频在:

https://www.bilibili.com/video/BV1zi421a7NM/?vd_source=cf6121716e06cb669a27c10276f9c920

 Ch554 的代码:

ESP32 C3 代码:

参考:

1. https://mc.dfrobot.com.cn/thread-316678-1-1.html