news 2026/5/15 20:21:23

【低功耗蓝牙】⑤ 蓝牙HID协议实战:从键盘到游戏手柄的ESP32实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【低功耗蓝牙】⑤ 蓝牙HID协议实战:从键盘到游戏手柄的ESP32实现

1. 蓝牙HID协议入门指南

第一次接触蓝牙HID协议时,我完全被那些专业术语搞晕了。HID全称Human Interface Device,翻译过来就是"人机交互设备"。简单来说,就是键盘、鼠标、游戏手柄这些我们天天用的输入设备。以前这些设备都是通过USB线连接,现在用蓝牙无线连接,方便多了。

蓝牙HID设备有个专业术语叫HOGP(HID over GATT Profile)。这个协议规定了蓝牙设备如何模拟传统USB HID设备的功能。我在开发过程中发现,ESP32特别适合用来做这类项目,因为它内置蓝牙功能,价格便宜,而且社区支持很好。

2. 蓝牙HID设备开发基础

2.1 必备条件

要让ESP32变成一个蓝牙HID设备,需要满足两个基本条件:

首先,广播数据里要包含HID的UUID和设备外观信息。HID服务的UUID固定是0x1812,不同设备的外观代码不一样:键盘是0x03C1,鼠标是0x03C2,游戏手柄是0x03C3。这个信息很重要,电脑或手机就是靠这个识别你是什么设备的。

其次,要在GATT服务中实现HID规范要求的服务和特性。这里涉及到几个关键特性:

  • 0x2A4A:HID信息,包含版本号、国家代码等
  • 0x2A4B:Report Map,定义数据格式
  • 0x2A4C:控制点,用于主机和设备通信
  • 0x2A4D:数据交互特性
  • 0x2A4E:协议模式

2.2 开发环境准备

我用的是MicroPython开发环境,版本要在1.16以上。安装好固件后,记得导入必要的模块:

from machine import Pin import ubluetooth from bluetooth import UUID

3. 蓝牙键盘实战

3.1 键盘实现原理

键盘的实现核心在于Report Map的设计。这个数据结构定义了按键信息的编码方式。我刚开始做的时候,经常搞混各个字节的含义,后来画了个示意图才明白:

第一个字节是修饰键(Ctrl、Shift等),第二位保留,后面6个字节可以表示6个普通按键。比如发送0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00就表示按下A键。

3.2 完整代码解析

下面是我调试通过的键盘实现代码:

ble = ubluetooth.BLE() ble.active(True) ble.config(gap_name="ESP Keyboard") ble.config(mtu=23) HIDS = ( UUID(0x1812), ( (UUID(0x2A4A), ubluetooth.FLAG_READ), (UUID(0x2A4B), ubluetooth.FLAG_READ), (UUID(0x2A4C), ubluetooth.FLAG_WRITE), (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, ((UUID(0x2908), 1),)), (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE, ((UUID(0x2908), 1),)), (UUID(0x2A4E), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE), ), )

这里有个小技巧:键盘需要两个0x2A4D特性,一个用于发送按键信息,一个用于接收指示灯状态。而鼠标和游戏手柄通常只需要一个。

4. 蓝牙自拍杆的特殊实现

4.1 自拍杆的本质

你可能想不到,蓝牙自拍杆其实是个简化版的键盘!它利用了手机的一个特性:在相机界面,音量键可以当快门用。所以自拍杆本质上就是模拟按下音量键的动作。

4.2 媒体按键的实现

实现媒体控制功能需要特殊的Report Map:

MEDIA_REPORT = bytes([ 0x05, 0x0C, # Usage Page (Consumer) 0x09, 0x01, # Usage (Consumer Control) 0xA1, 0x01, # Collection (Application) 0x85, 0x01, # Report Id (1) # 省略部分字节... 0x09, 0xEA, # Usage (Volume Down) 0x81, 0x06, # Input (Data,Value,Relative,Bit Field) 0xC0 # End Collection ])

这个设计很巧妙,只用一个字节就能表示各种媒体控制功能。比如0x10表示音量减,0x20表示音量加。我在项目中测试时发现,不同手机对这个协议的支持程度可能不一样,需要多测试几款设备。

5. 蓝牙鼠标开发详解

5.1 鼠标数据格式

鼠标的数据格式和键盘完全不同。通常用4个字节表示:

  • 第一个字节:按键状态(左键、右键、中键)
  • 第二个字节:X轴移动量(-127到127)
  • 第三个字节:Y轴移动量
  • 第四个字节:滚轮状态

5.2 实战代码

这是我调试通过的鼠标实现:

MOUSE_REPORT = bytes([ 0x05, 0x01, # USAGE_PAGE (Generic Desktop) 0x09, 0x02, # USAGE (Mouse) 0xa1, 0x01, # COLLECTION (Application) 0x85, 0x01, # REPORT_ID (1) # 省略部分字节... 0x81, 0x06, # Input(Data, Variable, Relative); 3 position bytes 0xc0, # END_COLLECTION 0xc0 # END_COLLECTION ])

实际使用时要注意,移动量是相对值,不是绝对坐标。我刚开始犯了个错误,以为是要传绝对位置,结果鼠标指针乱飞。

6. 蓝牙游戏手柄开发

6.1 手柄数据结构

游戏手柄的数据结构最复杂,通常包含:

  • 摇杆的X/Y轴坐标(各1字节)
  • 多个按钮状态(通常用1个字节的各个位表示)

6.2 完整实现方案

这是我做的一个简易手柄实现:

JOY_REPORT = bytes([ 0x05, 0x01, # USAGE_PAGE (Generic Desktop) 0x09, 0x04, # USAGE (Joystick) 0xa1, 0x01, # COLLECTION (Application) 0x85, 0x01, # REPORT_ID (1) # 省略部分字节... 0x81, 0x02, # Input (Data, Variable, Absolute) 0xc0, # END_COLLECTION 0xc0 # END_COLLECTION ])

摇杆的坐标范围是-127到127,中间位置是0。按钮状态用位表示,比如0x01表示第一个按钮按下,0x03表示前两个按钮都按下。

7. 开发中的常见问题

7.1 连接稳定性问题

我遇到过设备配对后无法自动连接的问题。后来发现需要在代码中添加重连逻辑,或者每次使用前手动删除配对信息。这不是ESP32的问题,而是蓝牙HID协议的特性决定的。

7.2 数据格式一致性

Report Map和实际发送的数据必须严格匹配。我有次修改了Report Map但忘了更新发送代码,结果设备完全没反应。调试这类问题时,建议先用现成的例子测试,确保基础功能正常后再修改。

7.3 添加额外服务

实际产品中,通常还需要添加设备信息服务(DIS)和电池服务(BAS)。这两个服务不是必须的,但有了它们,用户体验会好很多。比如电池服务可以让用户知道手柄还剩多少电量。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 21:16:12

永动虾:OpenClaw 一键部署,开启 AI 全自动办公新时代

2025 年底爆火的OpenClaw(龙虾 AI),作为颠覆传统的开源 AI 智能体,彻底改变 AI “只说不做” 的局限,为大模型装上 “数字手脚”,能直接操控电脑、手机自主完成全流程任务。而永动虾,正是基于 O…

作者头像 李华
网站建设 2026/4/11 19:51:42

关闭ollama开机自启动

不同操作系统关闭Ollama开机自启动的方法有所不同,以下是常见操作系统的具体方法:Windows 系统 通过任务管理器:按Ctrl Shift Esc打开任务管理器,切换到“启动”选项卡,在列表中找到Ollama(或相关条目&am…

作者头像 李华
网站建设 2026/4/16 23:20:30

网盘直链下载助手:突破下载限制的本地解析解决方案

网盘直链下载助手:突破下载限制的本地解析解决方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘…

作者头像 李华
网站建设 2026/4/12 18:01:07

高效自动化剪辑:Python控制剪映的全面实战指南

高效自动化剪辑:Python控制剪映的全面实战指南 【免费下载链接】JianYingApi Third Party JianYing Api. 第三方剪映Api 项目地址: https://gitcode.com/gh_mirrors/ji/JianYingApi Python剪映自动化、第三方剪映API、JianYingApi实战应用——如果你正在寻找…

作者头像 李华
网站建设 2026/4/13 17:49:08

Puppeteer实战:从零构建完美PDF的终极指南

1. Puppeteer与PDF生成基础 Puppeteer是Google Chrome团队维护的一个Node库,它提供了高级API来控制无头版Chrome或Chromium。想象一下,你有一个看不见的浏览器,可以按照你的指令自动完成各种操作,这就是Puppeteer的核心能力。在PD…

作者头像 李华
网站建设 2026/5/4 8:28:27

WSL 2 发行版自由切换:从默认安装到个性化配置指南

1. WSL 2 入门:为什么你需要多发行版自由切换? 第一次接触WSL 2时,很多人都会直接安装默认的Ubuntu发行版。这就像去餐厅吃饭,服务员直接给你推荐了招牌菜,确实不会出错,但可能并不完全符合你的口味。作为一…

作者头像 李华