板卡介绍
XG24-EK2703A是一款功能强大的开发套件,其核心是EFR32MG24B210F1536IM48无线SoC芯片。该套件设计紧凑、成本效益高,并特别适用于需要低功耗和无线通信功能的应用。除了基本的USB接口、LED指示灯和按钮外,它还支持多种无线协议,如蓝牙LE、蓝牙mesh等,并配备了用于调试和数据跟踪的接口。其强大的处理能力和丰富的内存资源使得它成为物联网和嵌入式AI应用的理想选择。
完成任务
- 短按上键,触发滚轮上滚一行。
- 短按下键,触发滚轮下滚一行。
- 长按按键,触发键盘事件,输出EETREE.CN
- 中按按键,触发音量减事件,类似于自拍杆,触发拍照事件。
蓝牙协议介绍
蓝牙协议是一种无线通讯标准,它使得电子设备之间能够在短距离内进行数据传输。自蓝牙技术问世以来,它已经经历了多个版本的迭代,不断提升性能、降低功耗并扩展应用范围。
蓝牙协议栈分为几个主要层次,包括物理层、链路层、网络层、传输层和应用层。物理层负责在无线信道上传输原始数据比特流。链路层负责设备之间的连接建立和数据传输的可靠性。网络层处理设备之间的通信路由和拓扑结构。传输层提供数据传输的服务,确保数据的完整性和顺序。应用层则定义了各种蓝牙应用程序使用的协议和规范。
在蓝牙协议中,低功耗蓝牙(BLE)是一个重要的分支,它专注于在保持通信功能的同时降低功耗。BLE通过优化连接间隔、降低数据传输速率和使用高效的编码方式来减少功耗。这使得BLE成为物联网(IoT)设备和可穿戴设备等低功耗应用的理想选择。
BLE引入了属性协议(ATT)和通用属性配置文件(GATT)等概念,用于定义设备之间的数据交换格式和服务发现机制。GATT配置文件定义了设备可以提供的服务和特征(Characteristics),以及与之相关的属性和操作。这些配置文件使得BLE设备能够以一种标准化的方式与主机设备进行通信。
在实现蓝牙鼠标+键盘复合设备的过程中,BLE的HID over GATT配置文件起着关键作用。它定义了如何将鼠标的移动、点击和滚轮等事件转换为HID报告格式,并通过BLE连接发送给主机设备。主机设备上的蓝牙驱动程序会识别这些HID报告,并将其转换为操作系统可以理解的输入事件。
HID协议介绍
HID(Human Interface Device)协议是一种用于定义计算机与外部输入设备(如键盘、鼠标、游戏控制器等)之间通信的标准。HID协议规定了设备如何向计算机报告其状态变化,以及计算机如何控制这些设备。通过HID协议,设备制造商可以确保其产品与各种操作系统和硬件平台兼容。
HID协议定义了设备描述符(Device Descriptor)、报告描述符(Report Descriptor)和报告(Report)等关键概念。设备描述符提供了设备的基本信息,如厂商ID、产品ID和用途等。报告描述符描述了设备支持的各种报告格式和用途。报告则是设备向主机发送的数据包,其中包含了设备的状态信息和事件。
在实现蓝牙鼠标+键盘复合设备时,需要编写代码以处理鼠标的移动、点击和滚轮等事件,并将这些事件转换为HID报告格式。HID报告通常包括报告ID、字段和值等信息。报告ID用于标识报告的类型,字段定义了报告中各个数据的含义和格式,值则是实际的数据内容。
为了将HID报告发送给主机设备,需要使用BLE的HID over GATT配置文件。该配置文件定义了如何将HID报告封装在BLE数据包中,并通过BLE连接进行传输。主机设备上的蓝牙驱动程序会识别这些BLE数据包,并将其解析为HID报告,然后将其传递给操作系统进行处理。
需要注意的是,在实现蓝牙鼠标+键盘复合设备时,还需要考虑设备的电源管理和连接稳定性等方面的问题。例如,可以优化设备的休眠和唤醒机制以降低功耗,同时调整BLE连接参数以提高连接的稳定性和可靠性。此外,还需要进行充分的测试和调试,以确保设备在各种场景下都能正常工作。
实现思路
在XG24-EK2703A板卡上实现蓝牙鼠标+键盘复合设备的主要思路是利用其支持的BLE功能,通过编程将板卡配置为一个HID设备。具体步骤包括:
- 配置XG24-EK2703A的BLE协议以支持HID over GATT配置文件。
- 编写代码以处理按键事件,这些事件将触发HID报告。
- 通过BLE连接将HID报告发送到配对的主机设备。
- 在手机上进行配对以识别和处理来自XG24-EK2703A的HID报告。
实现方法
- 配置XG24-EK2703A的BLE协议以支持HID over GATT配置文件。
首先配置 XG24-EK2703A 的设备名称。由于名称无法直接输入中文,需要提前转换为十六进制编码进行填写。如图所示,就是中文“万能遥控”的编码值。
点击“添加”按钮,添加一个 HID 项。
在“Report Map”中按照HID协议要求,填写硬件识别符。这里的硬件识别符包括了键盘+鼠标+自拍杆三个设备。在一个数据包内存放了三个设备的标识符。
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0x65, // Usage Maximum (0x65)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x85, 0x02, // Report ID (2)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x05, // Usage Maximum (0x05)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x05, // Report Count (5)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x03, // Report Size (3)
0x95, 0x01, // Report Count (1)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
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,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x0C, // Usage Page (Consumer)
0x0A, 0x38, 0x02, // Usage (AC Pan)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, 0x03, // Report ID (3)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x01, // Report Count (1)
0x09, 0x94, // Usage (Quit)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x95, // Usage (Help)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0xEA, // Usage (Volume Decrement)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0xE9, // Usage (Volume Increment)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0xCB, // Usage (Tracking Decrement)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0xCA, // Usage (Tracking Increment)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0xB6, // Usage (Scan Previous Track)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0xB5, // Usage (Scan Next Track)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0xB1, // Usage (Pause)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0xB0, // Usage (Play)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01, // Report Size (1)
0x95, 0x06, // Report Count (6)
0x81, 0x07, // Input (Const,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xC0, // End Collection
// 179 bytes
// best guess: USB HID Report Descriptor
此时,应该能在手机中识别到名为“万能遥控”的HID设备了。
- 编写代码以处理按键事件,这些事件将触发HID报告。
首先加入“Button Press”库,用于自动化处理按钮事件。
然后在配置页面中设置按钮时间长度。
在主函数中启用按钮中断。
void app_init() { app_button_press_enable(); }
重写中断回调函数,处理按钮事件。
void app_button_press_cb(uint8_t button, uint8_t duration) {
sl_bt_external_signal((duration > APP_BUTTON_PRESS_DURATION_SHORT) << 1 |
button);
return;
}
- 通过BLE连接将HID报告发送到配对的主机设备。
case sl_bt_evt_system_external_signal_id:
memset(inputReportData, 0, sizeof(inputReportData));
if ((evt->data.evt_system_external_signal.extsignals >> 1 & 0x1) == 1) {
if ((evt->data.evt_system_external_signal.extsignals & 0x1) == 0) {
char c[] = {0x08, 0x08, 0x17, 0x15, 0x08, 0x08, 0x37, 0x06, 0x12, 0x10, 0x28};
for (unsigned int i = 0; i < sizeof(c) / sizeof(c[0]); i++) {
if (i > 0 && c[i - 1] == c[i]) {
sl_bt_gatt_server_notify_all(gattdb_report, 8, emptyData);
}
inputReportData[0] = c[i] > 0x1d ? 0x00 : 0x02;
inputReportData[2] = c[i];
sl_bt_gatt_server_notify_all(gattdb_report, 8, inputReportData);
}
memset(inputReportData, 0, sizeof(inputReportData));
sl_bt_gatt_server_notify_all(gattdb_report, 8, inputReportData);
app_log_info("send keyboard\r\n");
} else {
inputReportData[0] = 0x04;
sl_bt_gatt_server_notify_all(gattdb_report_2, 2, inputReportData);
sl_bt_gatt_server_notify_all(gattdb_report_2, 2, emptyData);
app_log_info("send volume\r\n");
}
} else if ((evt->data.evt_system_external_signal.extsignals >> 2) == 0) {
inputReportData[3] =
evt->data.evt_system_external_signal.extsignals & 0x1 ? 0x1 : 0xFF;
sl_bt_gatt_server_notify_all(gattdb_report_1, 5, inputReportData);
app_log_info("send mouse\r\n");
} else {
app_log_info("unknown routine: %lX\r\n",
evt->data.evt_system_external_signal.extsignals);
}
break;
在BLE协议栈中加入对信号量的判断。如果为长按信号,则调用键盘事件;如果为短按信号,则调用鼠标滚轮事件。最后,统一使用 notify 将数据发送到手机。
实物展示
使用手机配对 XG24-EK2703A。
长按触发蓝牙键盘输入。
短按触发鼠标滚轮事件,上下翻行。
支持抖音视频翻页。
遇到问题
在实现过程中,遇到以下问题:HID报告格式错误或不被主机识别。通过仔细检查HID报告的格式是否符合规范,并确保手机正确配对蓝牙以支持HID over GATT配置文件。此外,可以使用调试工具来跟踪和分析BLE通信中的数据流。通过检查发现是由于仅进行连接,而没有进行第二步配对。
总结感想
首先,我要衷心感谢硬禾学堂举办的这次活动,为我提供了一个宝贵的机会,让我能够深入探索和实践蓝牙技术在HID设备中的应用。这次活动不仅让我收获了丰富的知识和经验,还激发了我对物联网和嵌入式系统开发的浓厚兴趣。
通过这次活动,我深刻体会到了蓝牙技术的强大和灵活性。蓝牙作为一种广泛使用的无线通讯标准,在连接和传输数据方面表现出了出色的性能。特别是低功耗蓝牙(BLE)的引入,使得蓝牙技术在低功耗应用领域中大放异彩。在实现蓝牙鼠标+键盘复合设备的过程中,我亲身感受到了BLE的高效和便捷,它能够快速稳定地传输鼠标事件数据,为用户提供了流畅的操作体验。
同时,我也对HID协议有了更深入的了解。HID协议作为一种标准化的输入设备通信协议,为设备和计算机之间的通信提供了清晰的规范。通过遵循HID协议,我可以轻松地将鼠标事件转换为计算机能够识别的输入信号,实现了设备与手机之间的无缝连接。
最后,我要再次感谢硬禾学堂提供的这次宝贵的学习机会。我相信,在未来的学习和工作中,我会将这次活动的经验和知识运用到实际项目中,不断提升自己的技能和能力,为物联网和嵌入式系统的发展贡献自己的力量。