Note: * is a required field,
please fill it out during the registration phase↓
* 1. Project function introduction
Many times, for space and convenience considerations, we hope to use a set of keyboard and mouse to control multiple PCs. Usually, this function can be achieved through KVM. Obviously, they use wired methods to connect, which still takes up a lot of space. This time, ESP32 is used to implement the wireless keyboard and mouse expansion function.
*2. Project attributes
Original project First public release
* 3. Open source agreement
GPL3.0 Open source agreement
Please fill in the competition phase↓
*4. Hardware part
In order to achieve this goal, the most popular Arduino development environment is selected, and it is implemented with ESP32. This time, two types of main control chips, ESP32 and ESP32 S2, are used.
First, the function of parsing USB keyboard and mouse must be realized. Usually, Arduino USB Host Shield can be used, but because we need to parse USB keyboard and mouse at the same time, such a solution will be more troublesome. Another reason is that the main chip of this Shield is Max3421e, which is now expensive (the price of LiChuang Mall is RMB 42-65). Therefore, CH9350 was selected (this is a domestic chip produced by Nanjing Qinheng WCH. The popular USB to serial port chip CH340 is also their product). CH9350 can convert the effective information of USB keyboard and mouse into serial port data. The chip features are as follows: • Support 12Mbps full-speed USB transmission and 1.5Mbps low-speed USB transmission, compatible with USB V2.0. • The USB port on the host side complies with the standard HID class protocol, no additional driver installation is required, and supports Windows, Linux, MAC and other operating systems with built-in HID class device drivers. • The same chip can be configured as host mode and slave mode, connecting USB-Host host and USB keyboard and mouse respectively. • Support USB keyboard and mouse in BIOS interface, support multimedia function keys, and support USB mouse with different resolutions. • Support various brands of USB keyboard and mouse, USB wireless keyboard and mouse, USB to PS2 cable, etc. • The host and slave sides support hot plugging. • Provide send status pin and support 485 communication. • The serial port supports 115200/57600/38400 serial communication baud rates. • Built-in crystal oscillator and power-on reset circuit, simple peripheral circuit. • Support 5V, 3.3V power supply voltage. • Provide LQFP-48 lead-free package, compatible with RoHS. At the same time, the price of this chip in LiChuang Mall is 25 yuan, which is much cheaper than Max3421. Then around this chip, a converter board is designed for DFRobot's FireBeetle main control board (the chip is ESP32D32), which can parse USB keyboard and mouse signals into serial port data.
The core is the CH9350 chip, which can support 2 USB Host interfaces at a time, USB1 and USB2 in the figure below. LED1 and LED2 are communication indicator lights. If the corresponding USB1 and USB2 have normal communication, the corresponding LED will go out. In addition, there is a USB_Power which is a USB male connector, which is used to draw power from the outside to avoid insufficient power supply of FireBeetle.
The PCB design is as follows:
The 3D preview is as follows:
This is what it looks like (the only drawback is that the board is slightly larger due to the presence of two USB female connectors. In addition, the pins of this chip are relatively dense, and it takes some effort to solder. If you are not confident in your soldering skills, it is recommended to directly SMT to avoid manual soldering):
Next, we also need to design the part that interacts with the user. This part of the circuit is relatively simple. There are four buttons for selecting the currently working receiver, and four indicator lights for indicating the currently working receiver.

The PCB design is as follows. What is more interesting is that the LED is reversely pasted (the luminous part faces the PCB direction) on the back of the PCB, and then a solder mask is used here, so that light can pass through the PCB to illuminate the writing on the front.
It is a pity that the 3D preview cannot show this effect.
Real-life photography:

So we have three cards: FireBeetle, USB keyboard and mouse Shield and the user interface card above. Plug the three together to work normally. The above is the transmitter.
We also use ESP32 as the receiver, but here we must use ESP32 S2 master control, because this model supports USB Device, which can easily realize a USB device. You can use the following ESP32 S2 development board that directly leads to USB Device (one is the CH340 download port, and the other is the USB Device port):
In addition, you can also directly purchase the ESP32 S2 module and design the USB Device pin yourself.
*5. Software part
Similarly, there are 2 software, one is the keyboard and mouse information transmitter, and the other is the data receiver, which is also responsible for simulating keyboard and mouse devices.
As mentioned earlier, we use CH9350 to parse keyboard and mouse data. The specific data format is described in the Data Sheet:
The parsed data will appear on FireBeetle's Serial2.
First explain the key code of the transmitter:
1. During initialization, use the following code to send data to CH9350, so that Ch9350 will only send valid information (that is, data will come out only when the mouse and keyboard are in action).
char SwitchToMode1[] = {0x57, 0xAB, 0x12, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x20};
for (int i = 0; i < sizeof(SwitchToMode1); i++) {
Serial2.write(SwitchToMode1[i]);
}
2.ESP32 has a built-in function called ESP-NOW, which only needs a simple code to make two ESP32s easily realize wireless interconnection.
// Initialize ESP-NOW WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; }
// Set the callback function for sending data //esp_now_register_send_cb(OnDataSent);
// Bind the data receiver. Here you need to know the MAC of the receiver first. At the beginning of the file, use the following code to give the MAC // MAC address of the receiving device // Red PCB 7C:DF:A1:06:70:EC // Dual TypeC development board 7C:DF:A1:06:5D:18 // Dual TypeC development board 7C:DF:A1:06:77:C0 // Large green development board 7C:DF:A1:06:70:A4
uint8_t Receiver1[] = {0x7C, 0xDF, 0xA1, 0x06, 0x70, 0xEC};uint8_t Receiver2[] = {0x7C, 0xDF, 0xA1, 0x06, 0x5D, 0x18};uint8_t Receiver3[] = {0x7C, 0xDF, 0xA1, 0x06, 0x70, 0xA4};uint8_t Receiver4[] = {0x7C, 0xDF, 0xA1, 0x06, 0x77, 0xC0};// Next bind the MAC of the receiver esp_now_peer_info_t peerInfo; memcpy(peerInfo.peer_addr, Receiver1, 6); peerInfo.channel = 0; peerInfo.encrypt = false;3. Use the CurrentDevice variable to record the current action of the receiver (sometimes we don't want to perform the same keyboard and mouse actions on multiple machines)
if (digitalRead(BUTTON1) == LOW) { delay(100); if (digitalRead(BUTTON1) == LOW) { if ((CurrentDevice & BIT0) == 0) { CurrentDevice |= BIT0; } else { CurrentDevice &= (~BIT0); } } }
Similarly, set the LED according to the current CurrentDevice value if (CurrentDevice != CurrentDeviceLast) { digitalWrite(LED1, (CurrentDevice & BIT0 ? 1 : 0)); digitalWrite(LED2, (CurrentDevice & BIT1 ? 1 : 0)); digitalWrite(LED3, (CurrentDevice & BIT2 ? 1 : 0)); digitalWrite(LED4, (CurrentDevice & BIT3 ? 1 : 0)); CurrentDeviceLast = CurrentDevice; Serial.println(CurrentDevice, HEX); }4. After receiving the actions of the USB keyboard and mouse, send them to different receiving ends according to the previous CurrentDevice status. Only the esp_now_send() function is needed to send the data:
if ((CurrentDevice & BIT0) != 0 0) { // Send data result = esp_now_send(Receiver1, Data, Counter);
// Check if data is sent successfully if (result == ESP_OK) { // Serial.println("Sent success Receiver1"); } else { // Serial.println("Error sending the data to Receiver1"); }}The above is the key code of the sender. Interested friends can directly read the complete code implementation. Pay special attention, because I use DFRobot's FireBeetle, the corresponding FireBeetle support package needs to be installed when compiling. Next, I will introduce the code of the receiver. Compared with the sender, the receiver is much simpler. Similarly, only the key parts are picked out for explanation: 1. The ESP-NOW code for wireless reception is also very simple. After initialization, just register the callback function. When the wireless signal is received, it will automatically enter the function given by esp_now_register_recv_cb() for processing
// Initialize ESP-NOW WiFi.mode(WIFI_STA); if (esp_now_init() != 0) { Serial.println("Error initializing ESP-NOW"); return; }
// Set the callback function for receiving data esp_now_register_recv_cb(OnDataRecv);
2. The verifyData() function is used in the processing code after receiving the data to verify the received data, and then device.directMS() and device.directKB are used to process it according to the data type.
// Data receiving callback function void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) { char *Starter = (char*)incomingData; if (len>72) {return;} while (Starter < (char *)(incomingData+len)) { if (verifyData((char*)Starter, Starter[3]+4)) { for (int i = 0; i < Starter[3]+4; i++) { Serial.print(Starter[i], HEX); Serial.print(" "); } Serial.println(" "); // If it is a mouse if (((Starter[4] >> 4) & 0x3) == 0x2) { device.directMS((char *)&Starter[5]); } // If it is a keyboard if ((((Starter[4] >> 4) & 0x3) == 0x3)||(((Starter[4] >> 4) & 0x3) == 0x1)) { device.directKB((char *)&Starter[5]); } } Starter=&Starter[Starter[3]+4]; }//while (Start < (incomingDatalen))}3. In order to simulate a USB keyboard and mouse, I used the TinyUSB library, which comes with a KB MS composite device code (hidcomposite.cpp). The only drawback is that the code does not support sending mouse and keyboard data in RAW format. To this end, add the following function to the code to support this function, that is, send the received data intact as the mouse or keyboard action: //LABZ_Debug_Startvoid HIDcomposite::directKB(char *data){ uint8_t keycode[6]={data[2],data[3],data[4],data[5],data[6],data[7]}; if (tud_hid_ready()) { // KEYBOARD: convenient helper to send keyboard report if application // use template layout report as defined by hid_keyboard_report_t tud_hid_keyboard_report(report_keyboard,data[0], keycode); }}//LABZ_Debug_End
//LABZ_Debug_Startvoid HIDcomposite::directMS(char *data){ if (tud_hid_ready()) { // uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal tud_hid_mouse_report(report_mouse, data[0], data[1], data[2], data[3], 0); }}//LABZ_Debug_End
*6、BOM清单
用户界面板
ID
Name
Designator
Footprint
Quantity
Manufacturer Part
Manufacturer
Supplier
Supplier Part
Price
1
KT-1206Red LED
LED1,LED2,LED3,LED4
LED1206-R-RD
4
KT-1206Red LED
KENTO
LCSC
C49018
0.0738
2
10K
R1,R2
R1206
2
CR1206F10K7P05
Ever Ohms Tech
LCSC
C245447
0.0391
3
FireBeelte ESP32
U1
DFROBOT FIREBEETLE
1
DFRobot
4
10K
R3,R4
R1206
2
CR1206F10K7P05
Ever Ohms Tech
LCSC
C245447
0.0391
5
1TS005A-2700-5001
DEV1,DEV2,DEV3,DEV4
SW-TH_4P-L6.0-W6.0-P4.50-LS6.5
4
1TS005A-2700-5001
HY P
LCSC
C319408
0.161
CH9350 Shield
ID
Name
Designator
Footprint
Quantity
Manufacturer Part
Manufacturer
Supplier
Supplier Part
Price
1
3.3uf
C2
C1206
1
TCC1206X7R561K501DT
CCTC
LCSC
C377112
0.1299
2
0.1uf
C3
C1206
1
TCC1206X7R561K501DT
CCTC
LCSC
C377112
0.1299
3
100uf
C5,C4
C1206
2
TCC1206X7R561K501DT
CCTC
LCSC
C377112
0.1299
4
2.54mm 1*2P
DPOWER1
HDR-TH_2P-P2.54-VM
1
2.54mm 1*2P
ReliaPro
LCSC
C36717
0.0372
5
Shorting resistor
JP2
Shorting pad
1
TTOOAADD
6
LED
LED2,LED1
LED1206-R-RD
2
KT-1206Red LED
KENTO
LCSC
C49018 7 1K R3,R4 R1206 2 R1206RXX102XJ04LTC Shenzhen Eyang Tech Development LCSC C267247 0.0201 8 CH9350L U1 LQFP-
48_L 7.0-W7.0-P0.50-LS9.0-BL 1 CH9350L WCH LCSC C109472 25.69 9 FireBeelte ESP32 U2 DFROBOT FIREBEETLE 1 DFRobot 10 U2 USB1,USB2 USB-A-TH_U-A-24DD-Y-1 2 U-A-24DD-Y-1 Rectangular Connectors - Contacts LCSC C193133 0.8234 11 USB-212-BCW USB-POWER USB-A-SMD_USB-212-BCW 1 USB-212-BCW XUNPU LCSC C720521 0.4174 *7. Competition LOGO verification * 8. Demonstrate your project and record it into a video to upload Video requirements: Please shoot horizontally, the resolution should not be less than 1280×720, the format should be Mp4/Mov, and the size of a single video should be within 100M; Video title: Lichuang Electric Competition: {Project Name}-{Video Module Name}; For example, Lichuang Electric Competition: "Autonomous Driving"-Team Introduction. More details: https://diy.szlcsc.com/posts/06c94d90c2c447dfbd9ed7339ff4a5b1