无线能够给用户带来极大的便利,对于我这样工作台很乱的人来说,无线大大降低了线路绊倒水杯之类物品的可能行。现在的计算机特别是笔记本电脑都随着 WIFI 模块自带了蓝牙功能,这次介绍的作品就是使用ESP32 S3 将有线的 USB 键盘转化为一个蓝牙键盘,这样就可以直接连接到工作的计算机上。
具体的使用方法可以通过下面的视频了解:
接下来就开始介绍如何实现。这次设计的核心是ESP32-S3 ,它是一款2020年底推出的,集成 2.4 GHz Wi-Fi 和 Bluetooth 5 (LE) 的 MCU 芯片。这款搭载 Xtensa® 32 位 LX7 双核处理器,主频高达 240 MHz,内置 512 KB SRAM,具有 45 个可编程 GPIO 管脚和丰富的通信接口。从名称上也可以看出,它是ESP32-S2 的继承者,相比 S2 芯片,S3 仍然有 USB OTG 功能,同时增加了对于蓝牙的支持。这次的作品就是基于这两个功能实现的:OTG 将自身设定为 USB Host,负责解析键盘数据;蓝牙负责和主机进行通讯。这样USB键盘的操作就会以蓝牙键盘操作的形式出现在主机上。
和之前的设计一样,首先介绍硬件。整体有7部分:
左上角是5V转3.3V的电路,核心是TI生产的SOT-223 封装的TLV1117LV线性稳压器,这款器件功耗极低,与传统 1117 稳压器相比低 500 倍,适用于需要超低静态电流的应用。TLV1117LV 系列 LDO 还可在 0mA 负载电流下保持稳定,不存在最低负载要求,因此适用于必须在待机模式为超小型负载供电的稳压器,在正常运行状态下需要 1A 大电流时同样如此。TLV1117LV 可提供出色的线路与负载瞬态性能,从而可在负载电流要求由不足 1mA 变为超过 500mA 时产生幅值极低的下冲与过冲输出电压。特别的,和之前 AMS1117 相比外部只需要2个1uf的电容即可,无需钽电容。
接下来是用于从外部取电的USB公头,用于给整体提供电力:
接下来是一个负载消耗设计,前面提到我们会用USB公头从外部取电,供电的可能是充电宝之类,这种移动电源为了节省电力当外部负载小于100ma时,会切断电源。为了避免这种情况,这里预留负载消耗的电路设计。如果有需要,可以间隔一定时间拉出一个负载避免电源自动关闭(实际上根据经验大部分USB键盘功耗就会超过100ma,只是预留不上件也没有关系)。
接下来是USB母头,用于连接USB键盘
板子上还有预留的烧写接口,这个接口是自定义的,可以看到是串口通讯,此外还有 IO0和EN_AUTO 配合DTR/RTS 能够实现自动烧写,无需手工按键。响应的,我还设计了一个基于CH343P 芯片的的串口小板,在【参考1】 可以看到。
串口测试小卡上自带了5V和3.3V供电,在调试时,焊接完成 ESP32 S3最小系统后,即可通过上面串口和3.3V 供电进行调试,这样方便调试可以及时发现问题。
最后,就是整个设计的核心 ESP32-S3 ,下图也是这个 MCU 的最小系统,外部通过有一个 0.1uf ,一个22uf电容,以及一个10K 电阻即可让 ESP32-S3 工作起来:
PCB 设计如下,因为元件不多,设计并不复杂:
3D预览如下:
焊接后的照片:
硬件完成后即可着手软件设计。
首先,需要完成的是USB Host 部分。使用 esp32-usb-host-demos-main 库【参考2】,这个库能够在 ESP32 S2 和 S3 上实现 USB Host ,经过我的测试功能正常。其中的usbhhidboot 是解析支持 BOOT_PROTCOL 键盘的例子。所谓 BOOT_PROTCOL是一种USB键盘的协议,主机通知USB键盘使用这个协议之后,键盘就会按照固定的格式发送数据,BOOT_PROTCOL最初的设计是为了处理计算机进入 BIOS Setup后的按键。因为键盘发送固定格式的数据,所以主机无需再根据描述符拆解数据,因此可以大大降低固件设计的复杂度。
在下面的函数中完成按键信息的解析:
void keyboard_transfer_cb(usb_transfer_t *transfer)
{
if (Device_Handle == transfer->device_handle) {
isKeyboardPolling = false;
if (transfer->status == 0) {
if (transfer->actual_num_bytes == 8) {
uint8_t *const p = transfer->data_buffer;
ESP_LOGI("", "HID report: %02x %02x %02x %02x %02x %02x %02x %02x",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
}
else {
ESP_LOGI("", "Keyboard boot hid transfer too short or long");
}
}
else {
ESP_LOGI("", "transfer->status %d", transfer->status);
}
}
}
为了实现 ESP32-S3 的BLE 键盘,我们使用 ESP32-BLE-Keyboard库【参考2】,同样的这个库提供了按键的示例。对于我们来说只需要用下面的方法声明一个 BLE 键盘:
BleKeyboard bleKeyboard;
接下来判断如果当前蓝牙已经连接,即可将敲击的键盘数据发送出去
if(bleKeyboard.isConnected()) {
bleKeyboard.sendReport((KeyReport*) p);
}
从上面可以看到 Arduino 设计的魅力就在于无需深入了解原理,简单拼接即可实现功能。因为对于大多数人来说,功能是他们更关心的而不是如何实现 ,有兴趣的朋友可以在 Arduino 中文社区上看到完整的代码。
下面是本文提到的电路图和 PCB 以及 Arduino 代码下载:
参考: