内容介绍
内容介绍
项目描述:
- 项目介绍:Funpack2-6 nRF7002-DK 蓝牙复合设备项目,基于VScode和nRF Connect SDK平台完成任务一,实现蓝牙鼠标键盘功能。按键1作为鼠标右键点击,按键2作为键盘输入按下时输入“eetree”字符,电脑开启大写锁定时,板卡的LED亮起。
- 设计思路:板载的nRF5340 Soc作为主控,利用其内置的蓝牙支持,开发蓝牙HIDS设备。利用板卡外置的按钮和LED进行交互操作,完成蓝牙配对和按键模拟。
- 硬件介绍:nRF7002-DK是用于nRF7002 Wi-Fi 6 协同IC的开发套件,该开发套件采用nRF5340多协议片上系统 (SoC) 作为nRF7002的主处理器,在单一的电路板上包含了开发工作所需的一切,可让开发人员轻松开启基于 nRF7002 的物联网项目。 其支持低功耗 Wi-Fi 应用开发,并实现了多项 Wi-Fi 6 功能,比如 OFDMA、波束成型和 TWT。该 DK 包括 Arduino 连接器、两个可编程按钮、一个 Wi-Fi 双频段天线和一个低功耗蓝牙天线,以及电流测量引脚。 nRF7002 Wi-Fi 6配套IC为另一个主机添加了低功耗Wi-Fi 6功能,具有无缝连接和基于Wi-Fi的定位(本地Wi-Fi集线器的SSID嗅探)功能。该IC设计用于搭配Nordic现有的nRF52®和nRF53®系列多协议片上系统 (SoC) 和nRF91®系列蜂窝物联网系统级封装 (SiP) 使用。nRF7002 IC还可与非nordic主机器件搭配使用。通过SPI或QSPI与主机通信,并带有额外的共存功能,可与其他协议如蓝牙、Thread或Zigbee无缝共存。nRF7002在Nordic的nRF Connect SDK中提供集成和支持。
板卡特性:
- 用于nRF7002双频带Wi-Fi 6配套IC的开发套件
- nRF5340 SoC主机器件
- Wi-Fi 6 (IEEE 802.11 a/b/g/n/ac/ax)、蓝牙低功耗 (LE)、蓝牙网状网络、802.15.4、Thread、Zigbee®、ANT、2.4GHz专有和NFC无线协议支持
- 2.4GHz、5GHz芯片和NFC天线 SWF射频连接器
- SEGGER J-Link板载编程器/调试器
- 用户可编程LED (2x) 和按钮 (2x)
- 用于测量功耗的引脚
- 来自USB、外部或锂聚合物电池的2.9V至5.0V电源
- Arduino连接器
芯片应用场景:
- 电池供电Wi-Fi产品
- 智慧城市和智能农业
- 智能家居
- 工业传感器
- 可穿戴设备和医疗设备
软件流程图:
主要代码片段及说明:
头文件引入
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <soc.h>
#include <assert.h>
#include <zephyr/spinlock.h>
#include <zephyr/settings/settings.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/services/bas.h>
#include <bluetooth/services/hids.h>
#include <zephyr/bluetooth/services/dis.h>
#include <dk_buttons_and_leds.h>
定义hid报告,初始化
static void hid_init(void)
{
int err;
struct bt_hids_init_param hids_init_obj = { 0 };
struct bt_hids_inp_rep *hids_inp_rep;
struct bt_hids_outp_feat_rep *hids_outp_rep;
static const uint8_t report_map[] = {
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x06, /* Usage (Keyboard) */
0xA1, 0x01, /* Collection (Application) */
/* Keys */
#if INPUT_REP_KEYS_REF_ID
0x85, INPUT_REP_KEYS_REF_ID,
#endif
0x05, 0x07, /* Usage Page (Key Codes) */
0x19, 0xe0, /* Usage Minimum (224) */
0x29, 0xe7, /* Usage Maximum (231) */
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) reserved byte(1) */
0x95, 0x06, /* Report Count (6) */
0x75, 0x08, /* Report Size (8) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x65, /* Logical Maximum (101) */
0x05, 0x07, /* Usage Page (Key codes) */
0x19, 0x00, /* Usage Minimum (0) */
0x29, 0x65, /* Usage Maximum (101) */
0x81, 0x00, /* Input (Data, Array) Key array(6 bytes) */
/* LED */
#if OUTPUT_REP_KEYS_REF_ID
0x85, OUTPUT_REP_KEYS_REF_ID,
#endif
0x95, 0x05, /* Report Count (5) */
0x75, 0x01, /* Report Size (1) */
0x05, 0x08, /* Usage Page (Page# for LEDs) */
0x19, 0x01, /* Usage Minimum (1) */
0x29, 0x05, /* Usage Maximum (5) */
0x91, 0x02, /* Output (Data, Variable, Absolute), */
/* Led report */
0x95, 0x01, /* Report Count (1) */
0x75, 0x03, /* Report Size (3) */
0x91, 0x01, /* Output (Data, Variable, Absolute), */
/* Led report padding */
0xC0, /* End Collection (Application) */
0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
0x09, 0x02, /* Usage (Mouse) */
0xA1, 0x01, /* Collection (Application) */
0x85, 0x02, /* Report Id (2) */
0x09, 0x01, /* Usage (Pointer) */
0xA1, 0x00, /* Collection (Physical) */
0x05, 0x09, /* Usage Page (Button) */
0x19, 0x01, /* Usage Minimum (0x01) */
0x29, 0x03, /* Usage Maximum (0x03) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x95, 0x03, /* Report Count (3) */
0x75, 0x01, /* Report Size (1) */
0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,...) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x05, /* Report Size (5) */
0x81, 0x03, /* Input (Const,Var,Abs,No Wrap,Linear,...) */
0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
0x09, 0x30, /* Usage (X) */
0x09, 0x31, /* Usage (Y) */
0x15, 0x81, /* Logical Minimum (129) */
0x25, 0x7F, /* Logical Maximum (127) */
0x75, 0x08, /* Report Size (8) */
0x95, 0x02, /* Report Count (2) */
0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */
0xC0, /* End Collection */
0xC0, /* End Collection */
};
hids_init_obj.rep_map.data = report_map;
hids_init_obj.rep_map.size = sizeof(report_map);
hids_init_obj.info.bcd_hid = BASE_USB_HID_SPEC_VERSION;
hids_init_obj.info.b_country_code = 0x00;
hids_init_obj.info.flags = (BT_HIDS_REMOTE_WAKE |
BT_HIDS_NORMALLY_CONNECTABLE);
hids_inp_rep =
&hids_init_obj.inp_rep_group_init.reports[INPUT_REP_KEYS_IDX];
hids_inp_rep->size = INPUT_REPORT_KEYS_MAX_LEN;
hids_inp_rep->id = INPUT_REP_KEYS_REF_ID;
hids_init_obj.inp_rep_group_init.cnt++;
hids_outp_rep =
&hids_init_obj.outp_rep_group_init.reports[OUTPUT_REP_KEYS_IDX];
hids_outp_rep->size = OUTPUT_REPORT_MAX_LEN;
hids_outp_rep->id = OUTPUT_REP_KEYS_REF_ID;
hids_outp_rep->handler = hids_outp_rep_handler;
hids_init_obj.outp_rep_group_init.cnt++;
hids_inp_rep = &hids_init_obj.inp_rep_group_init.reports[INPUT_REP_BUTTONS_IDX];
hids_inp_rep->size = INPUT_REPORT_BUTTONS_MAX_LEN;
hids_inp_rep->id = OUTPUT_REP_BUTTONS_REF_ID;
hids_init_obj.inp_rep_group_init.cnt++;
hids_init_obj.is_kb = true;
hids_init_obj.is_mouse = true;
hids_init_obj.boot_kb_outp_rep_handler = hids_boot_kb_outp_rep_handler;
hids_init_obj.pm_evt_handler = hids_pm_evt_handler;
err = bt_hids_init(&hids_obj, &hids_init_obj);
__ASSERT(err == 0, "HIDS initialization failed\n");
}
初始化蓝牙对象:
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE,
(CONFIG_BT_DEVICE_APPEARANCE >> 0) & 0xff,
(CONFIG_BT_DEVICE_APPEARANCE >> 8) & 0xff),
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_HIDS_VAL),
BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)),
};
static const struct bt_data sd[] = {
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};
static struct conn_mode {
struct bt_conn *conn;
bool in_boot_mode;
} conn_mode[CONFIG_BT_HIDS_MAX_CLIENT_COUNT];
开始蓝牙广播
static void advertising_start(void)
{
int err;
struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(
BT_LE_ADV_OPT_CONNECTABLE |
BT_LE_ADV_OPT_ONE_TIME,
BT_GAP_ADV_FAST_INT_MIN_2,
BT_GAP_ADV_FAST_INT_MAX_2,
NULL);
err = bt_le_adv_start(adv_param, ad, ARRAY_SIZE(ad), sd,
ARRAY_SIZE(sd));
if (err) {
if (err == -EALREADY) {
printk("Advertising continued\n");
} else {
printk("Advertising failed to start (err %d)\n", err);
}
return;
}
is_adv = true;
printk("Advertising successfully started\n");
}
按钮按下以及信号发送
static void button_shift_changed(bool down)
{
for (size_t i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
if (conn_mode[i].conn) {
int err;
uint8_t buffer[INPUT_REPORT_BUTTONS_MAX_LEN];
memset(buffer, 0, INPUT_REPORT_BUTTONS_MAX_LEN);
/*if (down) {
buffer[0] = 1;
} else {
buffer[0] = 0;
}*/
if (down) {
//buffer[0] |= (1 << 1); // 设置 buffer[0] 的第二位为 1 即为鼠标右键按下
buffer[0] = 0b000010;
} else {
//buffer[0] &= ~(1 << 1); // 设置 buffer[0] 的第二位为 0
buffer[0] = 0b000000;
}
bt_hids_inp_rep_send(&hids_obj, conn_mode[i].conn,
INPUT_REP_BUTTONS_IDX,
buffer, sizeof(buffer), NULL);
if (err) {
printk("Key report send error: %d\n", err);
return err;
}
}
}
}
if (pairing_button_pressed &&
(has_changed & (KEY_PAIRING_ACCEPT | KEY_PAIRING_REJECT))) {
pairing_button_pressed = false;
return;
}
if (has_changed & KEY_TEXT_MASK) {
button_text_changed((button_state & KEY_TEXT_MASK) != 0);
}
if (has_changed & KEY_SHIFT_MASK) {
button_shift_changed((button_state & KEY_SHIFT_MASK) != 0);
}
#if CONFIG_NFC_OOB_PAIRING
if (has_changed & KEY_ADV_MASK) {
size_t i;
for (i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
if (!conn_mode[i].conn) {
advertising_start();
return;
}
}
printk("Cannot start advertising, all connections slots are"
" taken\n");
}
#endif
}
功能展示及说明:
蓝牙配对:
打字功能
大写指示灯:
右键菜单:
项目心得:我学会了基本的nrf SDK开发,也是第一次了解蓝牙协议,第一次接触hid标准,这次活动增加了我对hid和蓝牙的理解认识,也熟悉了VScode的开发流程。
该项目已经成功实现了简易蓝牙鼠标键盘二合一设备的功能,并达到了预期指标。然而通过更换硬件,还有许多可以提升与扩展的地方。例如接上屏幕,利用丰富的io接口进行图文展示。或者学习利用IMCU进行动态调试开发等等。
软硬件
附件下载
my_hids_keymouse.zip
代码文件
团队介绍
个人项目,个人报名
团队成员
Quarix
评论
0 / 100
查看更多