基于WCH CH583蓝牙芯片的手机远程控制键盘/鼠标通用方案
前言
有没有想过,用手机就能远程操控电脑的键盘和鼠标?
这个需求其实很常见——远程演示PPT、躺在床上操控HTPC、或者给嵌入式设备做无线调试输入。市面上的方案要么贵,要么不够灵活。今天分享一个基于WCH CH583芯片的通用方案,成本低、实现简洁,核心思路是:
手机 → BLE → CH583 → USB HID → 电脑
手机端发送键鼠指令,CH583通过蓝牙接收后,转换为标准USB HID协议输出给电脑。电脑端零驱动,即插即用。
为什么选CH583?

在做芯片选型的时候,对比了几款常见的BLE SoC:
| 特性 | CH583 | ESP32-C3 | nRF52832 |
|---|---|---|---|
| 内核 | RISC-V 32位 | RISC-V 32位 | ARM Cortex-M4 |
| BLE版本 | 5.3 | 5.0 | 5.0 |
| USB | 2路(Host+Device) | 无原生USB | 无原生USB |
| Flash | 512KB | 4MB(外挂) | 512KB |
| SRAM | 32KB | 400KB | 64KB |
| 单价(散片参考) | ~3元 | ~8元 | ~15元 |
| 触摸按键 | 14路 | 无 | 无 |
选CH583的核心原因就三个字:便宜、够用、有USB。
很多BLE芯片不带原生USB Device控制器,要模拟HID设备还得外挂CH340之类的桥接芯片,增加成本和复杂度。CH583自带2路全速USB,一路做Device输出HID,另一路做Host都行,方案天然简洁。
BLE 5.3的协议栈也是WCH官方提供的,省去了自己移植的麻烦。
系统架构
整体方案分三层:
┌─────────────┐ BLE 5.3 ┌─────────────┐ USB HID ┌──────────┐
│ 手机APP │ ──────────────→ │ CH583 │ ────────────→ │ 电脑 │
│ (Android/iOS)│ GATT通信 │ BLE + USB │ 键盘/鼠标 │ (免驱动) │
└─────────────┘ └─────────────┘ └──────────┘
数据流很清晰:
- 手机APP采集用户的触摸/按键操作,封装成自定义协议包
- 通过BLE GATT Characteristic写入CH583
- CH583解析协议包,转换为标准USB HID Report
- 电脑识别为标准键盘/鼠标设备,无需安装任何驱动
硬件设计
最小系统非常简单,CH583本身集成度很高,外围器件极少。
核心电路
CH583 最小系统
┌──────────────────┐
│ │
32MHz晶振 ──→│ XI/XO │
│ │
32.768K晶振 →│ X32KI/X32KO │──→ USB D+/D- → 电脑USB口
│ │
天线匹配网络 ←│ RF │
│ │
3.3V LDO ──→│ VCC │
│ │
│ GPIO (可选) │──→ 状态LED / 物理按键
└──────────────────┘
BOM清单(核心部分)
| 器件 | 型号/规格 | 数量 | 说明 |
|---|---|---|---|
| MCU | CH583M/F | 1 | 主控 |
| 晶振 | 32MHz | 1 | 主时钟 |
| 晶振 | 32.768KHz | 1 | RTC/低功耗时钟 |
| 天线 | 2.4G陶瓷天线或PCB天线 | 1 | BLE射频 |
| 匹配网络 | 电感电容若干 | - | 参考官方参考设计 |
| LDO | 3.3V | 1 | 供电 |
| USB座 | Type-C | 1 | 连接电脑 |
| LED | 0603 | 1-2 | 状态指示 |
整板BOM成本可以控制在10元以内(不含PCB),非常适合DIY和小批量。
软件架构
固件端(CH583)
CH583的固件主要做两件事:BLE通信 + USB HID输出。
CH583 固件架构
├── BLE层
│ ├── GAP:广播、连接管理
│ ├── GATT Server
│ │ ├── HID Control Service(自定义)
│ │ │ ├── Keyboard Characteristic(Write)
│ │ │ ├── Mouse Characteristic(Write)
│ │ │ └── Config Characteristic(Read/Write)
│ │ └── Device Info Service
│ └── 协议栈回调处理
├── USB层
│ ├── USB Device初始化
│ ├── HID Keyboard Report Descriptor
│ ├── HID Mouse Report Descriptor
│ └── Report发送逻辑
├── 协议解析层
│ ├── BLE数据包解析
│ ├── 键盘指令 → USB Keyboard Report
│ └── 鼠标指令 → USB Mouse Report
└── 系统层
├── 低功耗管理
├── 状态LED控制
└── 看门狗
BLE自定义协议
为了通用性和扩展性,定义一个简洁的通信协议:
// 协议包格式(最大20字节,适配BLE MTU)
typedef struct {
uint8_t type; // 0x01=键盘, 0x02=鼠标, 0x03=多媒体, 0xFF=配置
uint8_t length; // 数据长度
uint8_t data[]; // 变长数据
} __attribute__((packed)) ble_hid_packet_t;
// 键盘数据格式(兼容USB HID标准)
typedef struct {
uint8_t modifier; // 修饰键(Ctrl/Shift/Alt/GUI)
uint8_t reserved;
uint8_t keycode[6]; // 最多6个同时按键
} __attribute__((packed)) keyboard_report_t;
// 鼠标数据格式
typedef struct {
uint8_t buttons; // 按键状态(左/右/中)
int8_t x; // X轴相对移动 (-127~127)
int8_t y; // Y轴相对移动
int8_t wheel; // 滚轮
} __attribute__((packed)) mouse_report_t;
USB HID描述符(关键代码)
CH583需要同时模拟键盘和鼠标,使用复合HID设备:
// USB HID Report Descriptor - 复合设备(键盘+鼠标)
const uint8_t HID_ReportDescriptor[] = {
// ========== 键盘部分 ==========
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
// 修饰键(8个bit)
0x05, 0x07, // Usage Page (Keyboard/Keypad)
0x19, 0xE0, // Usage Minimum (Left Control)
0x29, 0xE7, // Usage Maximum (Right GUI)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data, Variable, Absolute)
// 保留字节
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Constant)
// 按键数组(6个键)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0xFF, // Logical Maximum (255)
0x05, 0x07, // Usage Page (Keyboard/Keypad)
0x19, 0x00, // Usage Minimum (0)
0x29, 0xFF, // Usage Maximum (255)
0x81, 0x00, // Input (Data, Array)
0xC0, // End Collection
// ========== 鼠标部分 ==========
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x85, 0x02, // Report ID (2)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
// 鼠标按键(3个bit + 5个padding)
0x05, 0x09, // Usage Page (Buttons)
0x19, 0x01, // Usage Minimum (Button 1)
0x29, 0x03, // Usage Maximum (Button 3)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x03, // Report Count (3)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x75, 0x05, // Report Size (5)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Constant)
// X, Y, Wheel
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x03, // Report Count (3)
0x81, 0x06, // Input (Data, Variable, Relative)
0xC0, // End Collection
0xC0, // End Collection
};
BLE接收与USB发送的桥接逻辑
// BLE GATT写入回调 → 解析 → USB HID发送
void on_ble_data_received(uint8_t *data, uint16_t len) {
ble_hid_packet_t *pkt = (ble_hid_packet_t *)data;
switch (pkt->type) {
case 0x01: { // 键盘
keyboard_report_t *kb = (keyboard_report_t *)pkt->data;
uint8_t report[9];
report[0] = 0x01; // Report ID
report[1] = kb->modifier;
report[2] = 0x00; // Reserved
memcpy(&report[3], kb->keycode, 6);
USB_HID_SendReport(report, sizeof(report));
break;
}
case 0x02: { // 鼠标
mouse_report_t *ms = (mouse_report_t *)pkt->data;
uint8_t report[5];
report[0] = 0x02; // Report ID
report[1] = ms->buttons;
report[2] = (uint8_t)ms->x;
report[3] = (uint8_t)ms->y;
report[4] = (uint8_t)ms->wheel;
USB_HID_SendReport(report, sizeof(report));
break;
}
case 0x03: // 多媒体键(扩展)
// TODO: 音量、播放/暂停等
break;
}
}
手机APP端
APP端的核心功能是BLE连接管理和触摸输入采集。
功能模块
手机APP
├── BLE管理
│ ├── 扫描/连接CH583设备
│ ├── 服务发现
│ └── 断线重连
├── 键盘模式
│ ├── 全键盘布局
│ ├── 快捷键组合(Ctrl+C等)
│ └── 文本直接输入
├── 鼠标/触控板模式
│ ├── 触摸区域 → 相对移动
│ ├── 单击/双击/右键
│ └── 双指滚动
└── 设置
├── 鼠标灵敏度
├── 按键映射自定义
└── 设备管理
Android端关键代码(BLE发送)
// 发送键盘按键
fun sendKeyPress(modifier: Int, keycode: Int) {
val packet = ByteArray(10)
packet[0] = 0x01 // type: keyboard
packet[1] = 0x08 // length
packet[2] = modifier.toByte()
packet[3] = 0x00 // reserved
packet[4] = keycode.toByte()
// packet[5..9] = 0x00 (其余按键为空)
bleCharacteristic?.let { char ->
char.value = packet
bleGatt?.writeCharacteristic(char)
}
}
// 发送鼠标移动
fun sendMouseMove(dx: Int, dy: Int, buttons: Int = 0) {
val packet = ByteArray(6)
packet[0] = 0x02 // type: mouse
packet[1] = 0x04 // length
packet[2] = buttons.toByte()
packet[3] = dx.coerceIn(-127, 127).toByte()
packet[4] = dy.coerceIn(-127, 127).toByte()
packet[5] = 0x00 // wheel
bleCharacteristic?.let { char ->
char.value = packet
bleGatt?.writeCharacteristic(char)
}
}
触控板手势处理
// 触控板区域的触摸事件处理
class TouchpadView(context: Context) : View(context) {
private var lastX = 0f
private var lastY = 0f
private val sensitivity = 1.5f
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
lastX = event.x
lastY = event.y
}
MotionEvent.ACTION_MOVE -> {
val dx = ((event.x - lastX) * sensitivity).toInt()
val dy = ((event.y - lastY) * sensitivity).toInt()
if (dx != 0 || dy != 0) {
sendMouseMove(dx, dy)
lastX = event.x
lastY = event.y
}
}
MotionEvent.ACTION_UP -> {
// 短按判定为点击
val duration = event.eventTime - event.downTime
if (duration < 200) {
sendMouseClick()
}
}
}
return true
}
}
低功耗设计
既然是蓝牙设备,功耗管理很重要。CH583本身支持多种低功耗模式:
// 空闲时进入低功耗模式
void enter_low_power(void) {
if (ble_connected && no_data_timeout > 5000) {
// BLE连接状态下,拉长连接间隔
GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, 2, &interval_max);
// 进入Idle模式,保持BLE连接
LowPower_Idle();
} else if (!ble_connected && adv_timeout > 30000) {
// 长时间无连接,进入深度睡眠
// 通过GPIO按键唤醒
LowPower_Shutdown(RB_SLP_GPIO_WAKE);
}
}
| 工作状态 | 典型电流 |
|---|---|
| BLE广播 | ~0.3mA (1s间隔) |
| BLE连接空闲 | ~0.1mA |
| BLE收发+USB发送 | ~8mA |
| 深度睡眠 | ~0.3μA |
用一颗200mAh的纽扣电池,待机可以撑很久。
实际应用场景
这个方案的通用性体现在几个方面:
- 远程演示:手机当PPT翻页器,上下键翻页,鼠标指哪打哪
- HTPC控制:躺在沙发上用手机操控客厅电脑
- 嵌入式调试:给没有键盘接口的设备通过USB输入
- 游戏手柄(扩展):映射WASD和鼠标,手机变手柄
- 无障碍辅助:为行动不便的用户提供替代输入方式
开发资源
WCH官方提供了比较完整的开发资源:
- SDK:MounRiver Studio(基于Eclipse的RISC-V IDE)
- BLE协议栈:官方提供lib,有HID键盘/鼠标的例程
- USB例程:SDK中包含USB HID Device的完整示例
- 参考设计:官方EVT开发板原理图
基本上把官方的BLE HID例程和USB HID例程合并,再加上协议解析层,固件的主体框架就出来了。
总结
CH583做这类BLE转USB HID的桥接方案,确实是性价比很高的选择。RISC-V内核+BLE 5.3+原生USB的组合,在同价位几乎找不到对手。整个方案的核心就是三件事:
- BLE收数据
- 解析协议
- USB发HID Report
硬件简单,软件逻辑清晰,很适合作为一个通用的无线HID方案来推广。后续还可以扩展多媒体键、手写输入、甚至语音转文字输入等功能,可玩性很高。
如果你也对这个方案感兴趣,欢迎留言交流。后续会更新实际的PCB设计和完整固件代码。