
1. 项目概述从零打造你的专属无线键盘控制器如果你玩过Arduino或者树莓派肯定遇到过这样的场景想给项目加个无线遥控或者做个自定义的游戏手柄但一想到要处理蓝牙协议栈、HID报告描述符这些底层细节就头大。几年前我第一次接触蓝牙HID开发时光是搞明白那一堆USB HID规范文档就花了一周更别提调试配对问题了。直到后来用上了Adafruit的Bluefruit EZ-Key模块我才发现原来DIY一个蓝牙键盘控制器可以这么简单——简单到几乎不需要写代码一个下午就能从零件堆里变出一个能实际控制电脑的无线设备。Bluefruit EZ-Key本质上是一个集成了蓝牙HID键盘固件的CSR BlueCore模块。它最大的价值在于把复杂的蓝牙协议和HID报告封装成了一个“黑盒”你只需要关心两件事怎么给它供电以及怎么告诉它“现在该按哪个键”。它提供了12个GPIO引脚每个引脚默认映射了一个按键比如上、下、左、右箭头空格回车等你只需要把一个开关的一端接到这些引脚上另一端接地按下开关就相当于按下了对应的键。更厉害的是它还有一个串口UART你可以用任何单片机比如Arduino通过发送简单的ASCII字符或者原始的HID报告数据包来模拟任何键盘操作甚至控制鼠标光标和多媒体按键。这个模块的适用场景非常广泛。比如你可以用它做一个无线演示笔按一下按钮就翻页做一个智能家居的中控面板用大按钮控制音乐播放或者给树莓派项目加个无线键盘不用接显示器就能输入命令。它支持3-16V的宽电压输入意味着你可以用3节AA电池、一块9V电池或者USB 5V电源给它供电灵活性很高。接下来我会带你从开箱到高级应用完整走一遍这个模块的实战流程并分享一些官方文档里没写的细节和踩过的坑。2. 模块深度解析硬件接口与设计逻辑刚拿到Bluefruit EZ-Key模块时你可能会被板子上两排引脚和几个LED搞懵。别急我们把它拆开来看。整个模块的核心是一颗CSR的蓝牙芯片Adafruit为它烧录了定制固件让它一上电就伪装成一个标准的蓝牙键盘。周围的电路都是为这个核心服务的“配套设施”。2.1 电源与控制引脚稳定运行的基石模块顶部的一排引脚主要负责供电和基础控制。Vin和GND是最关键的它们接受3V到16V的直流电压。为什么范围这么宽这是为了兼容各种电源方案。比如你想做一个便携设备用3.7V的锂电池单节供电刚好或者你想从旧设备里拆个12V电源来用也完全没问题。模块内部有一个线性稳压器会把输入电压降到芯片工作的3.3V。这里有个经验虽然标称3-16V但实测用5V供电是最“舒服”的发热小工作也最稳定。如果你用接近16V的电压虽然模块不会坏但那个稳压芯片会有点烫手长期用最好加个小散热片。3V引脚是一个输出引脚它能提供大约100mA的3.3V电源。这个设计非常贴心意味着你可以用它来给外接的传感器或者一个小型单片机比如ATTiny85供电省去了再单独准备一个3.3V稳压电路的麻烦。不过要记住这100mA是“羊毛出在羊身上”如果你的主输入电源比如电池容量本身就不大这个额外负载会加快耗电。旁边的几个控制引脚各有妙用RS (Reset)复位引脚。拉低到地GND会让模块重启但不会清除已配对的设备信息。这个功能在程序跑飞或者需要硬重启时有用。L2配对状态LED红色的驱动引脚。板载的红色LED就是接在这里的。如果你想把这个模块装进一个不透明的外壳里可以从这个引脚引出一根线接上一个你自己的LED记得串联一个1KΩ的限流电阻到地这样就能在外面看到配对状态了。PB (Pair Button)配对按钮引脚。它内部连接到了板载的那个小按钮。如果你想做一个外置的、更大更漂亮的配对按钮可以接一个开关一端接这个引脚另一端接3V注意是3V不是地。按下开关就相当于按下了板载按钮。L1按键触发LED绿色的驱动引脚。每次有按键被触发无论是GPIO还是串口这个绿灯都会闪一下。同样你可以外接LED来做指示。RX/TX串口通信引脚。这是高级功能的入口。RX可以接受3V或5V的TTL电平信号波特率固定为9600。通过它你可以用单片机发送命令实现远超12个GPIO的复杂控制。TX则输出3V电平的调试信息通常我们只接RX就够了。2.2 12个GPIO按键引脚即插即用的快乐底部的12个引脚GPIO #0 到 #11就是最简单的使用方式了。每个引脚内部都有一个上拉电阻拉到3.3V。当引脚悬空时它被内部电阻拉高模块认为“没有按键”。当你用一根导线或者一个开关把这个引脚连接到GND时引脚被拉低模块就会立即发送一个对应的“按键按下”KEYDOWN报告当你断开连接它就发送“按键释放”KEYUP报告。这里有三个非常重要的注意事项绝对不要输入5V电压这些引脚直接连接到了蓝牙芯片的GPIO芯片逻辑电平是3.3V。如果你不小心把5V接上去很可能瞬间烧毁芯片。如果你的控制电路是5V系统比如经典的Arduino Uno在连接这些引脚前必须使用电平转换模块或者最简单的用两个电阻做一个分压电路。内部上拉电阻这意味着你不需要在外部再接上拉电阻了。直接接开关到地就行。开关类型不限可以是轻触开关、拨动开关、甚至是用两块导电海绵做的压力传感器——只要它能实现“通”和“断”两种状态。6键无冲模块支持最多同时按下6个键并正确上报。这是蓝牙HID协议的一个限制不是模块的缺陷。对于大多数应用比如游戏手柄的WASD空格跳跃来说完全够用。2.3 神秘的6针端口与默认键位映射模块左侧有一个6针的端口看起来很像常见的FTDI编程口。这里是个大坑务必注意这个端口是工厂用于测试和编程的用户绝对不要连接任何东西接错了线很可能导致模块永久性损坏俗称“变砖”。我们所有的操作无论是供电、按键还是串口通信都只使用顶部和底部的两排引脚。模块出厂时12个GPIO引脚已经有了默认的键位映射GPIO #0: 上箭头GPIO #1: 下箭头GPIO #2: 左箭头GPIO #3: 右箭头GPIO #4: 回车 (Enter/Return)GPIO #5: 空格 (Space)GPIO #6: 数字 ‘1’GPIO #7: 数字 ‘2’GPIO #8: 字母 ‘w’GPIO #9: 字母 ‘a’GPIO #10: 字母 ‘s’GPIO #11: 字母 ‘d’这个默认映射显然是考虑了游戏控制WASD移动和基础导航箭头、空格、回车。如果你要做的是一个简单的无线游戏手柄或者演示器焊上12个按钮接好线配对完就能直接用几乎零代码。3. 跨平台配对实战Windows、macOS与Linux配对是使用任何蓝牙设备的第一步。EZ-Key的优势在于它在系统中将自己模拟成一个标准的蓝牙键盘因此配对流程和配对一个普通的蓝牙键盘一模一样。你只需要操作一次之后模块只要上电并且在你的电脑蓝牙开启范围内就会自动重连。3.1 通用准备与LED状态解读在开始配对任何系统之前你需要先准备好模块焊接引脚模块默认是不带排针的。你需要自己焊接一排0.1英寸间距的直针或弯针或者直接焊上导线。建议至少把Vin、GND和你想用的几个GPIO引脚焊上。供电用一根USB转DC线、电池盒或者可调电源给Vin和GND供电5V最佳。上电后板载的红色LED配对指示灯会开始闪烁。进入配对模式找到板子上那个小小的配对按钮靠近L2引脚用镊子或者笔尖按住它5秒钟然后松开。这个操作会清除模块内部之前保存的所有配对信息让它进入“可被发现”的配对模式。此时红色LED会变成规律的每秒闪烁一次。这个状态表示“我已准备好快来发现我吧”整个配对过程中红色LED的状态就是你的“语言”快速不规则闪烁刚上电或者正在寻找/尝试连接已配对的设备。每秒1次规律闪烁已进入配对模式等待被新设备发现和连接。每2-3秒缓慢闪烁一次配对成功并且已连接到主机。这是正常工作状态。常亮或常灭通常表示异常检查电源或尝试复位。3.2 Windows系统配对详解在Windows上配对90%的问题出在蓝牙适配器上。很多老旧笔记本自带的或者网上买的廉价USB蓝牙适配器只支持蓝牙2.0或2.0EDR。EZ-Key模块需要蓝牙2.1或以上版本才能正常配对。蓝牙2.0缺少安全简单配对SSP机制会导致配对失败。如何判断如果你的适配器是近几年买的或者是笔记本电脑自带的2010年后的机型一般都没问题。如果不确定可以花几十块钱买一个明确标注支持蓝牙4.0的USB适配器它肯定向下兼容2.1。步骤实操将蓝牙适配器插入电脑USB口等待Windows自动安装驱动通常几秒就好。给EZ-Key上电并长按配对按钮5秒使其进入每秒闪烁一次的配对模式。打开Windows控制面板找到“设备和打印机”然后点击“添加设备”。在较新的Win10/Win11中你也可以直接点击任务栏右下角的通知中心打开“蓝牙”快捷设置面板然后选择“添加蓝牙或其他设备”。系统会开始扫描。稍等片刻通常30秒内列表中会出现一个名为“Adafruit EZ-Key”或类似名称的设备。选中它点击“下一步”。此时系统可能会弹出一个对话框要求输入配对码。对于EZ-Key这个配对码固定是1234。输入并确认。Windows会自动安装“蓝牙键盘”的驱动这个过程可能需要1-3分钟期间可能会显示“正在设置设备”这是正常的。完成后你会看到设备已添加成功。观察模块上的红色LED它会变为缓慢闪烁约2-3秒一次这表示配对并连接成功。踩坑记录有一次我在一台Win7老机器上配对始终找不到设备。后来发现是那个USB蓝牙适配器驱动太旧且只支持2.0。换了蓝牙4.0适配器后立刻成功。另一个常见问题是如果你之前配对过又删除了模块里可能还残留信息。务必确保执行了“长按5秒”的清空配对列表操作。3.3 macOS与Linux树莓派配对macOS的配对过程最为简单因为苹果全系产品都内置了符合标准的蓝牙模块。步骤和连接AirPods差不多给模块上电并进入配对模式然后打开“系统偏好设置” - “蓝牙”在设备列表里找到“Adafruit EZ-Key”点击“连接”即可。通常不会要求输入配对码。连接成功后如果弹出键盘设置助手直接关闭就行不需要进行任何配置。Linux系统以树莓派Raspbian为例的配对稍微需要一些命令行操作但也不复杂。核心是使用bluez这个蓝牙协议栈工具包。树莓派配对步骤硬件与系统准备如果你的树莓派没有内置蓝牙比如老款Pi 3之前型号需要先插入一个USB蓝牙适配器同样要求2.1以上。通过SSH或直接接显示器打开终端。安装BlueZ首先更新软件包列表并安装必要的工具。sudo apt-get update sudo apt-get install bluez bluez-tools修改配对代理关键步骤为了让配对过程无需输入配对码EZ-Key期望的流程我们需要修改一个配置文件。使用sudo nano /etc/bluetooth/main.conf打开蓝牙主配置找到[Policy]部分确保或添加一行AutoEnabletrue然后我们需要修改或创建一个简单的配对代理脚本。一个可靠的方法是使用bluetoothctl命令行工具这是新版BlueZ推荐的方式。使用bluetoothctl配对sudo bluetoothctl进入bluetoothctl交互界面后依次输入以下命令power on # 确保蓝牙适配器开启 agent on # 启用代理 default-agent # 设为默认代理 scan on # 开始扫描等待几秒在扫描结果中你应该能看到类似Device 00:18:96:XX:XX:XX Adafruit EZ-Key的信息。记下它的MAC地址00:18:96:...。scan off # 停止扫描 pair 00:18:96:XX:XX:XX # 将XX替换为你的模块MAC地址 trust 00:18:96:XX:XX:XX # 信任该设备 connect 00:18:96:XX:XX:XX # 连接设备在pair命令后可能会提示配对请求选择yes即可。整个过程完成后输入quit退出bluetoothctl。验证配对成功后模块的红色LED会变为缓慢闪烁。你可以在树莓派的文本编辑器如nano里测试短接某个GPIO到地看是否会输入对应的字符比如GPIO #6会输入数字1。Linux配对心得不同Linux发行版的蓝牙管理工具可能不同如Ubuntu用gnome-bluetooth但底层都是bluez。如果图形界面配对失败回归命令行使用bluetoothctl几乎总是有效的。配对信息保存在/var/lib/bluetooth/[适配器MAC地址]/目录下如果以后想彻底删除配对可以在这里删除对应的文件夹或者用bluetoothctl里的remove命令。4. 串口控制进阶从发送字符到原始HID报告当你不再满足于12个固定按键想要实现输入任意文本、组合键如CtrlC甚至控制鼠标时串口UART功能就派上用场了。通过RX引脚你可以让单片机Arduino、ESP8266、树莓派GPIO等成为EZ-Key的大脑实现动态、复杂的输入逻辑。4.1 硬件连接与基础通信连接非常简单将你的单片机的TX引脚连接到EZ-Key的RX引脚。务必再将两者的GND连接在一起为信号提供共同的参考地否则通信会不稳定甚至无法进行。EZ-Key的RX引脚兼容3V-5V逻辑电平所以无论你的单片机是3.3V如ESP32、树莓派还是5V如Arduino Uno都可以直接连接无需电平转换。通信参数固定为9600波特率8位数据位无奇偶校验1位停止位9600 8N1。这是模块固件设定的无法更改。4.2 三级控制模式详解EZ-Key的串口协议提供了三种不同层级的控制方式从简单到复杂满足不同需求。模式一直接发送ASCII字符最简单这是最直观的模式。你想让电脑输入什么字符就直接通过串口发送该字符的ASCII码。例如发送字符A(0x41)电脑就会输入大写字母A发送字符串Hello\n电脑就会依次打出H,e,l,l,o,然后换行。适用范围自动输入预设文本、密码或者由传感器触发输入特定字符。限制只能发送可打印字符ASCII 0x20-0x7E和少数几个控制字符如换行\n即0x0A。无法直接发送像Ctrl、Shift这样的修饰键。模式二发送单字节功能键码对于非打印字符EZ-Key定义了一套单字节的键码映射。你发送一个特定的字节0x00-0xFF模块会将其解释为对应的按键动作。例如0x01Insert键0x08Backspace键0x0B左箭头0x0E上箭头0x0F-0x1AF1 - F12 功能键0x1BESC键0xE0-0xE7左右Ctrl, Shift, Alt, Win/GUI键这里有个巨大陷阱当你发送0xE1左Shift时它模拟的是“按下Shift键”这个动作但并没有自动组合一个字母。如果你想让电脑输入大写‘A’你需要先发送0xE1按下Shift再发送a(0x61)然后发送0xE1释放Shift。如果只发送不释放Shift键就会一直处于按下状态导致后续所有字母都变大写。这种模式适合模拟单个功能键但对于组合键操作比较繁琐。模式三发送原始HID报告最强大这是EZ-Key的终极武器它允许你通过一个结构化的8字节数据包一次性发送包含修饰键Ctrl, Shift等和多达6个普通按键的完整组合状态。数据包格式固定为0xFD [修饰键字节] 0x00 [键码1] [键码2] [键码3] [键码4] [键码5] [键码6]起始字节固定为0xFD告诉模块这是一个原始HID报告。修饰键字节这是一个位掩码bitmask每一位代表一个修饰键是否按下。例如同时按下左Ctrl和左Shift修饰键字节就是(10) | (11) 0x01 | 0x02 0x03。键码使用标准的USB HID键码与ASCII码不同。例如字母‘A’的HID键码是0x04字母‘S’是0x16回车键是0x28。假设我们要通过串口让电脑执行“CtrlS”保存这个操作单片机需要发送以下字节序列按下报告FD 01 00 16 00 00 00 00 00FD: 报告头。01: 修饰键字节表示左Ctrl按下MODIFIER_CONTROL_LEFT 0x01。00: 保留字节。16: 键码1是‘S’USB HID键码。后面5个00键码2-6为空。释放报告FD 00 00 00 00 00 00 00 00发送全零的报告表示所有按键释放。如果只发送按下报告而不发送释放报告电脑会认为Ctrl和S一直被按着。这种“按下-释放”的配对操作是必须的。4.3 鼠标与多媒体控制报告从v1.1固件开始EZ-Key支持通过串口发送原始HID鼠标报告。格式为0xFD 0x00 0x03 [按钮状态] [X位移] [Y位移] 0x00 0x00 0x000xFD 0x00 0x03鼠标报告标识头。按钮状态位掩码。0x01左键0x02右键0x04中键。X位移/Y位移相对移动量范围是-127到127的有符号数。例如发送X50, Y0鼠标向右移动50个单位X-10, Y20鼠标向左移动10个单位向下移动20个单位。从v1.2固件开始还支持消费者控制报告即多媒体按键格式为0xFD 0x00 0x02 [掩码低字节] [掩码高字节] 0x00 0x00 0x00 0x00通过不同的位掩码可以控制音量加减0x01 0x00/0x02 0x00、播放/暂停0x40 0x00、下一曲/上一曲等。这在制作媒体遥控器时非常有用。4.4 Arduino实战代码解析理解了协议用代码实现就很简单了。下面是一个Arduino示例演示如何通过软件串口控制EZ-Key。假设EZ-Key的RX接在Arduino的D2引脚。#include SoftwareSerial.h // 定义软件串口RX接D3未用TX接D2连接EZ-Key的RX SoftwareSerial BTSerial(3, 2); // RX, TX void setup() { Serial.begin(9600); // 用于电脑端调试 BTSerial.begin(9600); // 与EZ-Key通信 delay(1000); // 等待模块启动 Serial.println(Bluefruit EZ-Key Controller Ready); } void keyCommand(uint8_t modifiers, uint8_t k1, uint8_t k20, uint8_t k30, uint8_t k40, uint8_t k50, uint8_t k60) { BTSerial.write(0xFD); BTSerial.write(modifiers); BTSerial.write((byte)0x00); BTSerial.write(k1); BTSerial.write(k2); BTSerial.write(k3); BTSerial.write(k4); BTSerial.write(k5); BTSerial.write(k6); } void loop() { // 示例1每隔5秒自动输入Hello World并回车 Serial.println(Sending: Hello World); BTSerial.println(Hello World); // 直接发送ASCII字符串 delay(5000); // 示例2模拟按下CtrlAltDelete需谨慎会触发系统菜单 Serial.println(Sending: CtrlAltDel (Hold)); // 左Ctrl(0x01) 左Alt(0x04) 0x05, Delete键的HID码是0x4C keyCommand(0x01 | 0x04, 0x4C); // 按下 delay(100); keyCommand(0, 0); // 释放 delay(5000); // 示例3模拟鼠标向右下角移动并点击左键 Serial.println(Moving mouse and clicking); // 鼠标报告按下左键(0x01)同时向右移动100向下移动50 BTSerial.write(0xFD); BTSerial.write(0x00); BTSerial.write(0x03); BTSerial.write(0x01); // 按钮左键按下 BTSerial.write(100); // X位移 BTSerial.write(50); // Y位移 BTSerial.write((byte)0x00); BTSerial.write((byte)0x00); BTSerial.write((byte)0x00); delay(500); // 发送释放报告按钮为0 BTSerial.write(0xFD); BTSerial.write(0x00); BTSerial.write(0x03); BTSerial.write(0x00); BTSerial.write(0); BTSerial.write(0); BTSerial.write((byte)0x00); BTSerial.write((byte)0x00); BTSerial.write((byte)0x00); delay(5000); }这段代码展示了三种控制方式。重要提示像CtrlAltDel这样的系统级快捷键在真实测试时要格外小心最好先在一个虚拟机或无关紧要的测试环境中进行。5. 按键重映射与高级应用技巧默认的12个GPIO映射可能不符合你的项目需求。EZ-Key提供了两种重映射方式有线串口重映射和无线重映射。5.1 有线串口重映射使用Processing这是早期版本唯一的方法需要用到电脑上的Processing IDE和一个特定的重映射脚本。你需要用一根FTDI串口线或任何USB转TTL模块将电脑的USB口连接到EZ-Key的RX/TX/GND。运行Adafruit提供的Processing脚本它会提供一个图形界面让你点击下拉菜单为每个GPIO引脚分配新的键值包括普通键、功能键、鼠标动作、多媒体键。设置完成后通过串口将新配置烧录到模块的EEPROM中。这个过程一旦完成新的映射就会永久生效直到你再次修改。5.2 无线重映射OTA - Over The Air这是v1.1固件之后加入的、方便得多的功能。你不需要连接任何串口线只需要让模块和电脑已经成功配对连接。然后在电脑上打开一个文本编辑器如记事本、TextEdit将模块切换到“文本风格重映射模式”。具体操作是在5秒内快速按下配对按钮4次。此时模块的红色LED会快速闪烁几下表示进入重映射模式。进入该模式后你在文本编辑器里输入特定的文本命令就可以实时修改按键映射。命令格式类似#0,KEY_A将GPIO 0映射为字母A。所有命令的列表可以在Adafruit的指南中找到。输入完所有映射命令后再长按配对按钮5秒模块会保存设置并重启。这个方法的优点是无需额外接线特别适合已经封装到项目里的模块进行后期调整。5.3 项目构思与避坑指南基于EZ-Key你可以发挥无穷的创意无障碍辅助设备用大号的按钮或压力传感器连接GPIO为行动不便者制作定制的输入设备。智能家居遥控器将模块与红外发射管结合用串口控制学习并模拟红外遥控信号同时用GPIO按钮作为常用情景模式开关。相机快门遥控器很多相机支持USB键盘触发拍照。将EZ-Key配对到一台小型电脑如树莓派Zero用GPIO连接一个快门按钮再通过USB控制相机。直播快捷键盒用串口模式让Arduino读取多个旋钮和按钮的状态通过EZ-Key发送复杂的OBS快捷键组合如场景切换、静音等。实战避坑指南电源噪声如果使用开关电源特别是廉价的手机充电器为模块供电有时会导致蓝牙连接不稳定或按键响应迟钝。在Vin和GND之间并联一个100μF的电解电容和一个0.1μF的陶瓷电容可以极大改善这种情况。按键抖动机械开关在闭合和断开的瞬间会产生快速的通断抖动可能导致一次按下被识别为多次。如果遇到“连击”问题需要在软件如果使用单片机或硬件上消抖。硬件上可以在GPIO和地之间接一个0.1μF的电容软件上可以在检测到按下后延时10-50毫秒再读取状态。串口数据丢失确保单片机发送数据的波特率严格是9600。一些Arduino库如SoftwareSerial在较高主频下可能产生波特率误差。如果发现串口命令时灵时不灵尝试降低单片机主频或者换用硬件串口如Arduino Uno的Serial。配对失败确保设备在配对时距离足够近1米内且周围没有强烈的2.4GHz干扰源如无绳电话、拥挤的WiFi环境。长按5秒清除旧配对信息的步骤至关重要。多设备干扰虽然一个电脑可以配对多个EZ-Key但同时只能有一个处于“已连接”状态。其他的会处于“已配对未连接”状态。你需要手动在系统蓝牙设置里切换连接或者编写脚本控制连接。