【Funpack2-6】基于nRF7002DK的蓝牙鼠标键盘复合设备
本项目是基于nRF7002DK的蓝牙鼠标键盘复合设备,可以分别实现蓝牙鼠标和蓝牙键盘的对应功能,再将两种功能合在一起。
标签
Funpack活动
蓝牙
Zephyr
nRF5340
roc
更新2023-10-13
538

一、项目描述

1.项目介绍

基于nRF7002DK的蓝牙鼠标键盘复合设备

  • 功能一:Button 1模拟鼠标点击
  • 功能二:Button 2模拟键盘按键,按下时输入“eetree”字符
  • 功能三:电脑开启大写锁定时,板卡的LED亮起

2.设计思路

本项目是基于nRF7002DK的蓝牙鼠标键盘复合设备,可以分别实现蓝牙鼠标和蓝牙键盘的对应功能,再将两种功能合在一起。

功能一是模拟鼠标,功能二和功能三是模拟键盘。进一步分析功能二是模拟的键盘向电脑发送信息,而功能三是电脑向模拟的键盘发送信息。由于单独的蓝牙鼠标和单独的蓝牙键盘在nordic官方demo中都有比较好的实现,可以进行借鉴学习;难点是如何将两种功能合在一起,也就是编写一个复合HID设备描述。所以这个复合HID设备描述中,要包含项目所需功能必要的通信信息。

3.简单的硬件介绍

本项目使用的是nRF7002DK板卡。这个板卡可以分为两个部分:一部分是板载jlink区,用于程序下载调试;另一部分是nordic芯片功能评估区,由nRF5340和nRF7002组成。本项目主要使用的nRF5340这款芯片。

二、软件流程图及主要代码片段

1.软件流程图

软件主要分两部分:

  • 开发板硬件初始化
    • 配置按键、LED
    • 设置蓝牙回调函数
    • 设置蓝牙混合设备信息
    • 蓝牙初始化
    • 进行蓝牙配对
  • 蓝牙鼠标键盘混合设备功能实现
    • 模拟鼠标
      • 鼠标左键模拟
    • 模拟键盘
      • 键盘按键模拟
      • CapsLock按键模拟

Fv6NL1zlBHL45U4VVDpWJkWeie0T

2.主要代码片段

  • 设置按键和LED
#define CON_STATUS_LED DK_LED1               /*蓝牙混合设备连接状态灯*/
#define LED_CAPS_LOCK  DK_LED2                /*CapsLock按键灯*/
#define KEY_SHIFT_MASK DK_BTN1_MSK      /*按键1*/
#define KEY_TEXT_MASK  DK_BTN2_MSK      /*按键2*/

当个蓝牙设备连接成功时LED1亮起;LED1实现按键输入功能;当按下按键2时,实现CapsLock功能并亮起LED2

  • 蓝牙配对按键设置
#define KEY_PAIRING_ACCEPT DK_BTN1_MSK /*确认蓝牙连接*/
#define KEY_PAIRING_REJECT DK_BTN2_MSK /*取消蓝牙连接*/
  • Zephyr HID设备生成宏
BT_HIDS_DEF(hids_obj,
	    OUTPUT_REPORT_MAX_LEN,
	    INPUT_REPORT_KEYS_MAX_LEN,
		INPUT_REP_BUTTONS_LEN);

Zephyr OS的生成宏,在编译前生成蓝牙HIDS设备的信息

  • HID设备描述
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) */

//mouse
		0x05, 0x01,     /* Usage Page (Generic Desktop) */
		0x09, 0x02,     /* Usage (Mouse) */

		0xA1, 0x01,     /* Collection (Application) */

		/* Report ID 2: Mouse buttons + scroll/pan */
#if INPUT_REP_REF_BUTTONS_ID
		0x85, INPUT_REP_REF_BUTTONS_ID, /* Report Id 2 */
#endif
		0x09, 0x01,                    //   USAGE (Pointer)
		0xa1, 0x00,                    //   COLLECTION (Physical)
		0x05, 0x09,                    //     USAGE_PAGE (Button)
		0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
		0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
		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)
		0x95, 0x01,                    //     REPORT_COUNT (1)
		0x75, 0x05,                    //     REPORT_SIZE (5)
		0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
		0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
		0x09, 0x30,                    //     USAGE (X)
		0x09, 0x31,                    //     USAGE (Y)
		0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
		0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
		0x75, 0x08,                    //     REPORT_SIZE (8)
		0x95, 0x02,                    //     REPORT_COUNT (2)
		0x81, 0x06,                    //     INPUT (Data,Var,Rel)
		0xc0,                          //   END_COLLECTION
		0xc0                           // END_COLLECTION
};

蓝牙混合HID的设置信息,通过hid_init生成hids_obj结构体,以给Zephyr的BT_HITS_DEF必要的初始化信息

  • 按键输入字符
static const uint8_t hello_world_str[] = {
	0x08,	/* Key e */
	0x08,	/* Key e */
	0x17,	/* Key t */
	0x15,   /* Key r */
	0x08,	/* Key e */
	0x08,	/* Key e */
	0x28,	/* Key Return */
};

当按下按键1时依次输入eetree

  • 模拟鼠标左键功能
static int mouse_click_send(uint8_t click)
{
	int err;
	for (size_t i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
		if (conn_mode[i].conn) {
			int err;

			err = mouse_report_con_send(click,
						  conn_mode[i].in_boot_mode,
						  conn_mode[i].conn);
			if (err) {
				printk("Key report send error: %d\n", err);
				return err;
			}
		}
	}
	return 0;
}

当按下按键1时,模拟鼠标左键功能

  • 键盘功能模拟
static void button_text_changed(bool down)
{
	static const uint8_t *chr = hello_world_str;

	if (down) {
		hid_buttons_press(chr, 1);
	} else {
		hid_buttons_release(chr, 1);
		if (++chr == (hello_world_str + sizeof(hello_world_str))) {
			chr = hello_world_str;
		}
	}
}

当按下按键2时,依次输入eetree

  • main函数主要功能
int main(void)
{
	int err;
	int blink_status = 0;

	printk("Starting Bluetooth Peripheral MIX HIDS example\n");

	configure_gpio();

	err = bt_conn_auth_cb_register(&conn_auth_callbacks);
	if (err) {
		printk("Failed to register authorization callbacks.\n");
		return 0;
	}

	err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
	if (err) {
		printk("Failed to register authorization info callbacks.\n");
		return 0;
	}

	hid_init();

	err = bt_enable(NULL);
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
		return 0;
	}

	printk("Bluetooth initialized\n");

	if (IS_ENABLED(CONFIG_SETTINGS)) {
		settings_load();
	}

#if CONFIG_NFC_OOB_PAIRING
	k_work_init(&adv_work, delayed_advertising_start);
	app_nfc_init();
#else
	advertising_start();
#endif

	k_work_init(&pairing_work, pairing_process);

	for (;;) {
		if (is_adv) {
			dk_set_led(ADV_STATUS_LED, (++blink_status) % 2);
		} else {
			dk_set_led_off(ADV_STATUS_LED);
		}
		k_sleep(K_MSEC(ADV_LED_BLINK_INTERVAL));
	}
}
  1. configure_gpio函数配置按键和LED
  2. bt_conn_auth_cb_register函数和bt_conn_auth_info_cb_register函数设置蓝牙回调函数,即蓝牙键盘鼠标对应功能
  3. hid_init蓝牙设备初始化
  4. k_work_init(&pairing_work, pairing_process),开始蓝牙配对

三、功能展示及说明

  1. 打开nRF7002DK板卡开关
  2. 电脑端开启蓝牙连接板卡,如板卡连接成功则LED 1亮起
  3. Button 1模拟鼠标左键
  4. Button 2模拟键盘按键,连续按键输入“eetree”字符
  5. 在电脑端按下CapsLock按键,板卡上LED 2亮起;再按CapsLock,LED 2灭。LED 2与CapsLock保持相同状态

四、对本活动的心得体会

  1. 本次活动使用了nordic的nRF5340蓝牙芯片,让我体会的这款蓝牙芯片的强大的功能。双核M33的配置可以在蓝牙应用中提供性能和安全的双重保障。当然双核开发也比之前的单核开发要复杂一些
  2. 学习了VSCode上ncs的开发也与之前使用KEIL进行开发有很大的不同
  3. 学习了Zephyr RTOS相关知识,利用Zephyr更好地实现实现nRF5340上的功能。由于时间有限,以后可以更加深入地学习这个非常强大的RTOS
  4. 项目最难的地方,我认为是设置环境,很多人卡在这里,如果能提供方便的开发环境,把更多的精力放在项目功能实现上就更好了

 

附件下载
peripheral_hids_mix.rar
团队介绍
个人
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号