2.4.4. 三模鼠标应用
2.4.4.1. 概述
支持标准的蓝牙BLE鼠标模式,蓝牙鼠标支持 windows 系统,mac 系统、安卓系统、ios 系统连接。
支持2.4g + dongle鼠标133回报率模式(高回报率暂未支持)
支持USB有线直连1k回报率模式
2.4.4.2. 工程配置
使用快捷键Alt + g 打开app_config.h,配置’CONFIG_APP_MOUSE_DUAL’使能
//app case 选择,只选1,要配置对应的board_config.h
#define CONFIG_APP_KEYBOARD 0//hid按键 ,default case
#define CONFIG_APP_KEYFOB 0//自拍器,
#define CONFIG_APP_MOUSE_DUAL 1//三模鼠标(ble&2.4g&usb) 需搭配CONFIG_BOARD_AW3XX_MOUSE板级,可配置单模ble
#define CONFIG_APP_MOUSE_LOW_LATENCY 0//AW33N暂不支持, 待迭代. 低延时从机,高回报率测试,需搭配CONFIG_BOARD_AW313A_MOUSE板级
#define CONFIG_APP_KEYPAGE 0//翻页器
#define CONFIG_APP_REMOTE_CONTROL 0//AW33N暂不支持, 待迭代. 遥控器,需搭配CONFIG_BOARD_AW31A_RC板级
使用快捷键Alt + g 打开board_config.h,板级选择CONFIG_BOARD_AW33N_MOUSE
#ifndef BOARD_CONFIG_H
#define BOARD_CONFIG_H
//#define CONFIG_BOARD_AW33N_DEMO
#define CONFIG_BOARD_AW33N_MOUSE
// #define CONFIG_BOARD_AW33N_MOUSE_M143
// #define CONFIG_BOARD_AW33N_RC
#include "board_aw33n_demo_cfg.h"
#include "board_aw33n_mouse_cfg.h"
#include "board_aw33n_mouse_m143_cfg.h"
#include "board_aw33n_rc_cfg.h"
#endif
apps/demo/hid/board/bd57/board_aw33n_mouse_cfg.h
key IO配置,根据鼠标的硬件原理图来配置按键
//*********************************************************************************//
// adkey 配置 //
//*********************************************************************************//
#define KEY_AD_EN ENABLE //<AD按键使能
#define AD_KEY_IO IO_PORTA_09 // 可用的IO见adc_ch_io_table
#define EXTERN_R_UP 0 // 220 -> 22k,外挂上拉电阻,0使用内部上拉,内部上拉为10k
#if EXTERN_R_UP
#define R_UP EXTERN_R_UP
#else
#define R_UP 100 // 内部上拉为10K,有20%误差
#endif
#define ADC10_33 (0x3ffL)
// 根据具体电路配置
#define ADC10_30 (ADC10_33 * 1000 / (1000 + R_UP)) //100K
#define ADC10_27 (ADC10_33 * 50 / (50 + R_UP)) //5K
#define ADC10_23 (ADC10_33 * 0 / (0 + R_UP)) //0
#define ADC10_20 (0)
#define ADC10_17 (0)
#define ADC10_13 (0) //NULL
#define ADC10_10 (0) //NULL
#define ADC10_07 (0) //NULL
#define ADC10_04 (0) //NULL
#define ADC10_00 (0) //NULL
#define AD_NOKEY ((ADC10_33 + ADC10_30) / 2)
#define ADKEY1_0 ((ADC10_30 + ADC10_27) / 2)
#define ADKEY1_1 ((ADC10_04 + ADC10_00) / 2)
#define ADKEY1_2 ((ADC10_23 + ADC10_20) / 2)
#define ADKEY1_3 ((ADC10_20 + ADC10_17) / 2)
#define ADKEY1_4 ((ADC10_17 + ADC10_13) / 2)
#define ADKEY1_5 ((ADC10_13 + ADC10_10) / 2)
#define ADKEY1_6 ((ADC10_10 + ADC10_07) / 2)
#define ADKEY1_7 ((ADC10_07 + ADC10_04) / 2)
#define ADKEY1_8 ((ADC10_27 + ADC10_23) / 2)
#define TCFG_ADKEY_VALUE0 0
#define TCFG_ADKEY_VALUE1 1
#define TCFG_ADKEY_VALUE2 2
#define TCFG_ADKEY_VALUE3 3
#define TCFG_ADKEY_VALUE4 4
#define TCFG_ADKEY_VALUE5 5
#define TCFG_ADKEY_VALUE6 6
#define TCFG_ADKEY_VALUE7 7
#define TCFG_ADKEY_VALUE8 8
#define TCFG_ADKEY_VALUE9 9
#define KEY_CPI_VAL 0
#define TCFG_ADC_VTEMP_CH_EN ENABLE //温度采集功能
//*********************************************************************************//
// iokey 配置 //
//*********************************************************************************//
#if LOW_CONNECT_INTERVAL_TEST
#define KEY_IO_EN DISABLE //<IO按键使能
#else
#define KEY_IO_EN ENABLE //<IO按键使能
#endif
#define MOUSE_KEY_SCAN_MODE ENABLE_THIS_MOUDLE
#define KEY_LK_VAL BIT(0) //1
#define KEY_RK_VAL BIT(1) //2
#define KEY_HK_VAL BIT(2) //4
// #define KEY_FB_VAL BIT(3) //8
// #define KEY_BB_VAL BIT(4) //16
// #define KEY_CPI_VAL BIT(5) //32
#define KEY_LK_RK_VAL (KEY_LK_VAL | KEY_RK_VAL) //3
#define KEY_LK_HK_VAL (KEY_LK_VAL | KEY_HK_VAL) //5
#define KEY_RK_HK_VAL (KEY_RK_VAL | KEY_HK_VAL) //6
#define KEY_LK_RK_HK_VAL (KEY_LK_VAL | KEY_RK_VAL | KEY_HK_VAL)//7
#define TCFG_IOKEY_MOUSE_LK_PORT IO_PORTA_04
#define TCFG_IOKEY_MOUSE_RK_PORT IO_PORTA_06
#define TCFG_IOKEY_MOUSE_HK_PORT IO_PORTA_05
// #define TCFG_IOKEY_MOUSE_CPI_PORT IO_PORTA_11
#if (LOW_CONNECT_INTERVAL_TEST == 0)
#define TCFG_POWER_CHECK_MODE_ENABLE 0//ENABLE
// #define TCFG_IOKEY_MOUSE_SWITCH_PORT IO_PORTA_00
#define TCFG_MOUSE_DET_S1_SWITCH_PORT IO_PORTB_01
#define TCFG_MOUSE_DET_S2_SWITCH_PORT IO_PORTA_13
#endif
传感器 io配置
//*********************************************************************************//
// optical mouse sensor配置 //
//*********************************************************************************//
#if (LOW_CONNECT_INTERVAL_TEST == 0)
#define TCFG_OMSENSOR_ENABLE
#endif
#define TCFG_S202_EN DISABLE
#define TCFG_HAL3205_EN DISABLE
#define TCFG_HAL3212_EN ENABLE
#define TCFG_OPTICAL_SENSOR_SCLK_PORT IO_PORTA_15
#define TCFG_OPTICAL_SENSOR_DATA_PORT IO_PORTA_14
#define TCFG_OPTICAL_SENSOR_INT_PORT IO_PORTB_01
鼠标滚轮器配置
//*********************************************************************************//
// code switch配置 //
//*********************************************************************************//
#if LOW_CONNECT_INTERVAL_TEST
#define TCFG_CODE_SWITCH_ENABLE DISABLE_THIS_MOUDLE
#else
#define TCFG_CODE_SWITCH_ENABLE ENABLE_THIS_MOUDLE
#endif
#define TCFG_CODE_SWITCH_A_PHASE_PORT IO_PORTA_03
#define TCFG_CODE_SWITCH_B_PHASE_PORT IO_PORTA_02
apps/demo/hid/board/bd57/board_aw33n_mouse_global_build_cfg.h
默认打开USB模式,可以通过开关这个宏的方式来控制USB模式
#define HAS_USB_EN 1
2.4.4.3. 模式选择
Note
三模鼠标默认有ble、2.4g和usb三种模式可以选择,通过拨码开关选择,具体逻辑代码如下:
/*************************************************************************************************/
/*!
* \brief mouse软件上电检测,ble&2.4g模式切换
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
static void mouse_power_mode_check(void)
{
#ifdef TCFG_IOKEY_MOUSE_SWITCH_PORT
uint8_t delay_10ms_cnt = 0;
uint32_t port_max_value = 1023;
// 根据具体电路分压
uint32_t port_side1_value = 1023 / 2;
uint32_t port_size2_value = 1023 * 3 / 4;
uint32_t vol_sum = 0; // 用于累加电压值
while (1) {
wdt_clear();
delay_10ms(1);
uint32_t vol_value = adc_get_value_blocking(adc_io2ch(TCFG_IOKEY_MOUSE_SWITCH_PORT));
log_info("vol_value is %d", vol_value);
// filter error value
if (vol_value == port_max_value) {
continue;
}
log_info("+");
vol_sum += vol_value; // 累加电压值
delay_10ms_cnt++;
if (delay_10ms_cnt >= 10) {
uint32_t vol_avg = vol_sum / 10; // 计算平均值
log_info("Average vol_value is %d", vol_avg);
if (vol_avg > port_side1_value) {
if (vol_avg < port_size2_value) {
mouse_switch_start_mode = HID_MODE_BLE;
} else {
mouse_switch_start_mode = HID_MODE_24G;
}
return;
} else {
log_info("-");
log_info("switch enter softpoweroff\n");
p33_io_wakeup_edge(TCFG_IOKEY_MOUSE_SWITCH_PORT, RISING_EDGE);
app_power_set_soft_poweroff(NULL);
}
}
}
#endif
#if TCFG_POWER_CHECK_MODE_ENABLE
gpio_set_mode(IO_PORT_SPILT(TCFG_MOUSE_DET_S1_SWITCH_PORT), PORT_INPUT_PULLUP_200K);
gpio_set_mode(IO_PORT_SPILT(TCFG_MOUSE_DET_S2_SWITCH_PORT), PORT_INPUT_PULLUP_200K);
if (!gpio_read(TCFG_MOUSE_DET_S1_SWITCH_PORT)) {
mouse_switch_start_mode = HID_MODE_BLE;
} else if (!gpio_read(TCFG_MOUSE_DET_S2_SWITCH_PORT)) {
mouse_switch_start_mode = HID_MODE_24G;
} else {
mouse_switch_start_mode = HID_MODE_USB;
}
log_info("mode = %d", mouse_switch_start_mode);
#endif
}
Note
初始化时检测拨码io高低电平从而判断选择哪种模式(ble或2.4g),通过软件检测的方式来实现,用户在做切换模式设计时也可以设计其他电路来实现模式的切换
2.4.4.4. BLE模式运行逻辑

配对与连接
启动配对模式:左键+中键+右键长按3s进入配对模式。选择ble模式后,上电默认会开启广播,广播30s没有连接进入软关机
apps/demo/hid/examples/mouse_dual/app_mouse_dual.c
void mouse_select_btmode(uint8_t mode)
{
if (mode == HID_MODE_USB) {
mouse_info.mouse_hid_mode = mode;
if (pair_timer_id) {
sys_timeout_del(pair_timer_id);
pair_timer_id = 0;
}
return;
}
if (mode != HID_MODE_INIT) {
if (mouse_info.mouse_hid_mode == mode) {
return;
}
mouse_info.mouse_hid_mode = mode;
}
log_info("###### %s: %d,%d\n", __FUNCTION__, mode, mouse_info.mouse_hid_mode);
if (mouse_info.mouse_hid_mode == HID_MODE_BLE || mouse_info.mouse_hid_mode == HID_MODE_24G) {
if (mouse_info.mouse_hid_mode == HID_MODE_BLE) {
log_info("---------app select ble--------\n");
rf_set_24g_hackable_coded(0);
} else {
log_info("---------app select 24g--------\n");
log_info("set_24g_code: %04x", CFG_RF_24G_CODE_ID);
rf_set_24g_hackable_coded(CFG_RF_24G_CODE_ID);
}
if (!STACK_MODULES_IS_SUPPORT(BT_BTSTACK_LE) || !BT_MODULES_IS_SUPPORT(BT_MODULE_LE)) {
log_info("not surpport ble,make sure config !!!\n");
ASSERT(0);
}
// 非测试模式并且没有绑定设备时关闭广播
#if (TEST_MOUSE_SIMULATION_ENABLE == 0)
if (!le_hogp_get_is_paired()) {
ble_module_enable(0);
}
#endif
ble_module_enable(1);
}
mouse_vm_deal(1);
}
左中右键长按3s打开广播,这个操作会将配对信息清除,电脑或手机如果还存在配对信息,将无法根据mac地址自动回连
apps/demo/hid/examples/mouse_dual/app_mouse_dual.c
// 中键+左键+右键, 长按数秒开广播
#if (DOUBLE_KEY_HOLD_PAIR)
if (KEY_LK_RK_HK_VAL == event->u.key.value && event_type == KEY_EVENT_LONG) {
log_info("adv start:key3 hold:%d", mouse_double_key_long_cnt);
if (++mouse_double_key_long_cnt >= DOUBLE_KEY_HOLD_CNT) {
ble_module_enable(0);
sys_timeout_add(NULL, mouse_bt_pair_mode_handle, WAIT_DISCONN_TIME_MS); //确保断开连接
mouse_double_key_long_cnt = 0;
}
return;
} else {
mouse_double_key_long_cnt = 0;
}
#endif
搜索设备:计算机搜索附近的BLE设备,并找到鼠标。
配对与连接:计算机与鼠标交换密钥,建立安全连接。配对成功后,鼠标与计算机之间可以传输HID报文。
BLE HID协议
BLE HID协议是专门为低功耗设备设计的,允许鼠标、键盘等设备通过BLE与计算机进行通信。BLE HID设备使用标准的HID描述符来定义其功能和报告格式。
apps/demo/hid/examples/mouse_dual/app_mouse_dual.h
static const uint8_t mouse_report_map[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 定义了后续字段的用途范畴,这里是通用桌面控制。
0x09, 0x02, // Usage (Mouse) - 指定当前设备为鼠标。
0xA1, 0x01, // Collection (Application) - 开始应用层集合,标志着一个应用集合的开始。
0x85, MOUSE_SEND_DATA_REPORT_ID, // Report ID (1) - 报告ID为1。
0x09, 0x01, // Usage (Pointer) - 指明是一个指针设备(在这里,是个鼠标)。
0xA1, 0x00, // Collection (Physical) - 开始物理集合,表示这是个物理设备。
// Buttons (5 buttons)
0x95, 0x05, // Report Count (5) - 报告包含5项数据。
0x75, 0x01, // Report Size (1) - 每项数据大小为1位。
0x05, 0x09, // Usage Page (Button) - 用途页面为按钮。
0x19, 0x01, // Usage Minimum (0x01) - 按钮的最小值为1(第一个按钮)。
0x29, 0x05, // Usage Maximum (0x05) - 按钮的最大值为5(第五个按钮)。
0x15, 0x00, // Logical Minimum (0) - 数据的逻辑最小值为0。
0x25, 0x01, // Logical Maximum (1) - 数据的逻辑最大值为1。
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 输入类型,代表了按钮的状态。
// Padding for the buttons - 3 bits
0x95, 0x01, // Report Count (1) - 一项填充数据。
0x75, 0x03, // Report Size (3) - 填充大小为3位,用于对齐字节。
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 输入类型为常量,用于占位不使用。
// Wheel (8 bits)
0x75, 0x08, // Report Size (8) - 滚轮数据的大小为8位。
0x95, 0x01, // Report Count (1) - 一项数据。
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 同上。
0x09, 0x38, // Usage (Wheel) - 滚轮。
0x15, 0x81, // Logical Minimum (-127) - 滚轮数据的逻辑最小值为-127。
0x25, 0x7F, // Logical Maximum (127) - 滚轮数据的逻辑最大值为127。
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 输入类型,代表了滚轮的滚动。
// X and Y Axis (12 bits each)
0x75, 0x10, // Report Size (16) - 每项数据的大小为16位。
0x95, 0x02, // Report Count (2) - 两项数据(X轴和Y轴)。
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 同上,指定用途页面为通用桌面控制。
0x09, 0x30, // Usage (X) - X轴。
0x09, 0x31, // Usage (Y) - Y轴。
0x16, 0x00, 0x80, // Logical Minimum (-32768) - X和Y轴数据的逻辑最小值为-32768。
0x26, 0xFF, 0x7F, // Logical Maximum (32767) - X和Y轴数据的逻辑最大值为32767。
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 输入类型,代表了轴的移动。
0xC0, // End Collection - 结束当前集合。
0xC0, // End Collection - 结束最外层的集合。
// Volume and media control report
0x05, 0x0C, // Usage Page (Consumer Devices)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, CUSTOM_SEND_DATA_REPORT_ID, // Report ID (2)
0x09, 0xE9, // Usage (Volume Up)
0x09, 0xEA, // Usage (Volume Down)
0x09, 0xCD, // Usage (Play/Pause)
0x09, 0xE2, // Usage (Mute)
0x09, 0xB6, // Usage (Scan Next Track)
0x09, 0xB5, // Usage (Scan Previous Track)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x06, // Report Count (6)
0x81, 0x02, // Input (Data,Var,Abs)
// Padding for alignment
0x95, 0x01, // Report Count (1)
0x75, 0x02, // Report Size (2)
0x81, 0x01, // Input (Const,Array,Abs)
0xC0 // End Collection
};
这个HID报文定义了一个BLE鼠标的描述符,它包括了鼠标的主要功能,如按键、滚轮、X轴和Y轴的移动。该描述符还定义了音量和媒体控制功能。以下是每一部分的详细解释:
顶层集合
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 定义了后续字段的用途范畴,这里是通用桌面控制。
0x09, 0x02, // Usage (Mouse) - 指定当前设备为鼠标。
0xA1, 0x01, // Collection (Application) - 开始应用层集合,标志着一个应用集合的开始。
0x85, MOUSE_SEND_DATA_REPORT_ID, // Report ID (1) - 报告ID为1。
这部分代码定义了一个使用页面为“通用桌面控制”的鼠标设备,并且开始一个应用层集合,报告ID为1。
指针设备(物理集合)
0x09, 0x01, // Usage (Pointer) - 指明是一个指针设备(在这里,是个鼠标)。
0xA1, 0x00, // Collection (Physical) - 开始物理集合,表示这是个物理设备。
这一部分定义了一个指针设备,并开始一个物理集合。
按钮
0x95, 0x05, // Report Count (5) - 报告包含5项数据。
0x75, 0x01, // Report Size (1) - 每项数据大小为1位。
0x05, 0x09, // Usage Page (Button) - 用途页面为按钮。
0x19, 0x01, // Usage Minimum (0x01) - 按钮的最小值为1(第一个按钮)。
0x29, 0x05, // Usage Maximum (0x05) - 按钮的最大值为5(第五个按钮)。
0x15, 0x00, // Logical Minimum (0) - 数据的逻辑最小值为0。
0x25, 0x01, // Logical Maximum (1) - 数据的逻辑最大值为1。
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 输入类型,代表了按钮的状态。
这里定义了5个按钮,每个按钮的数据大小为1位。它们的逻辑值范围为0到1,表示按钮按下和释放状态。
填充位
0x95, 0x01, // Report Count (1) - 一项填充数据。
0x75, 0x03, // Report Size (3) - 填充大小为3位,用于对齐字节。
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 输入类型为常量,用于占位不使用。
这里添加了3位填充位,以对齐字节。
滚轮
0x75, 0x08, // Report Size (8) - 滚轮数据的大小为8位。
0x95, 0x01, // Report Count (1) - 一项数据。
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 同上。
0x09, 0x38, // Usage (Wheel) - 滚轮。
0x15, 0x81, // Logical Minimum (-127) - 滚轮数据的逻辑最小值为-127。
0x25, 0x7F, // Logical Maximum (127) - 滚轮数据的逻辑最大值为127。
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 输入类型,代表了滚轮的滚动。
这里定义了滚轮数据,数据大小为8位,范围从-127到127,表示滚轮的滚动量。
X轴和Y轴
0x75, 0x10, // Report Size (16) - 每项数据的大小为16位。
0x95, 0x02, // Report Count (2) - 两项数据(X轴和Y轴)。
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 同上,指定用途页面为通用桌面控制。
0x09, 0x30, // Usage (X) - X轴。
0x09, 0x31, // Usage (Y) - Y轴。
0x16, 0x00, 0x80, // Logical Minimum (-32768) - X和Y轴数据的逻辑最小值为-32768。
0x26, 0xFF, 0x7F, // Logical Maximum (32767) - X和Y轴数据的逻辑最大值为32767。
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 输入类型,代表了轴的移动。
这里定义了X轴和Y轴的数据,每个轴的数据大小为16位,范围从-32768到32767,表示鼠标的移动量。
结束集合
0xC0, // End Collection - 结束当前集合。
0xC0, // End Collection - 结束最外层的集合。
结束物理集合和应用集合。
音量和媒体控制报文
顶层集合
0x05, 0x0C, // Usage Page (Consumer Devices)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, CUSTOM_SEND_DATA_REPORT_ID, // Report ID (2)
定义了一个使用页面为“消费者设备”的集合,报告ID为2。
控制按钮
0x09, 0xE9, // Usage (Volume Up)
0x09, 0xEA, // Usage (Volume Down)
0x09, 0xCD, // Usage (Play/Pause)
0x09, 0xE2, // Usage (Mute)
0x09, 0xB6, // Usage (Scan Next Track)
0x09, 0xB5, // Usage (Scan Previous Track)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x06, // Report Count (6)
0x81, 0x02, // Input (Data,Var,Abs)
定义了6个控制按钮,数据大小为1位,逻辑值范围为0到1,表示按钮的状态。
填充位
0x95, 0x01, // Report Count (1)
0x75, 0x02, // Report Size (2)
0x81, 0x01, // Input (Const,Array,Abs)
添加了2位填充位,以对齐字节。
结束集合
0xC0 // End Collection
结束应用集合。
这整个HID报文描述符定义了鼠标的基本功能(按键、滚轮、X轴和Y轴)以及音量和媒体控制功能,通过这些报文,鼠标可以向计算机报告其状态和用户的操作。
数据采集与处理
鼠标内部的传感器检测到用户的操作,如移动和点击。传感器将这些操作转换为数字信号。微处理器读取传感器数据,确定光标的移动量和按键状态。
Note
ble模式通过蓝牙事件中断发数
//蓝牙EVT中断回调,注意代码执行时间要断
LP_RUNCODE_AT(.lp_running.app.text)
void conn_evt_probe_handle_hook(u16 conn_handle, u16 event_cnt)
{
//保证每次连接事件推送一次发包操作
if (!mouse_info.mouse_is_paired) {
return;
}
if (!mouse_sleep_exit_send_flag) {
if (!mouse_conn_send_flag) {
bt_event_update_to_user(NULL, SYS_BT_EVENT_TYPE_CON_STATUS, BT_STATUS_CONN_EVTT_PROBE, 0);
}
} else {
if (!(mouse_flag.sensor_send_flag && mouse_flag.wheel_send_flag && mouse_flag.button_send_flag)) {
bt_event_update_to_user(NULL, SYS_BT_EVENT_TYPE_CON_STATUS, BT_STATUS_CONN_SEND_DATA, 0);
}
mouse_sleep_exit_send_flag = 0;
}
}
生成HID报文
微处理器将传感器数据转换为HID报文。HID报文包含以下信息:
光标移动:表示光标在X和Y轴上的移动量。
按键状态:表示鼠标按键的按下或释放状态。
滚轮滚动:表示鼠标滚轮的滚动量。
发送HID报文来实现对电脑或者手机的控制
/*************************************************************************************************/
/*!
* \brief 鼠标发数函数,定时器调用
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
static void mouse_data_send(void *priv_hw, uint8_t hw_state)
{
/* mouse_reset_cnt++; */
/* uint32_t mouse_reset_cnt_max; */
/* if (mouse_info.mouse_hid_mode == HID_MODE_BLE) { */
/* mouse_reset_cnt_max = MOUSE_7MS_CLEAR_WDT_CNT_MAX; */
/* } else { */
/* mouse_reset_cnt_max = MOUSE_1MS_CLEAR_WDT_CNT_MAX; */
/* } */
/* if (mouse_reset_cnt > mouse_reset_cnt_max) { */
/* #if (TCFG_HID_AUTO_SHUTDOWN_TIME) */
/* sys_timer_modify(mouse_info.mouse_auto_shutdown_timer, TCFG_HID_AUTO_SHUTDOWN_TIME * 1000); */
/* #endif */
/* 避免看门狗超时 */
/* wdt_clear(); */
/* mouse_reset_cnt = 0; */
/* } */
if (mouse_info.mouse_hid_mode == HID_MODE_24G && SWITCH_MODE_24G_ENABLE) {
#if 1
#if CONFIG_BLE_CONNECT_SLOT
hw_send_packet_fast(HID_REPORT_ID_01_SEND_HANDLE, priv_hw, (uint8_t *)&mouse_send_packet, sizeof(mouse_packet_data_t), 27, hw_state);
#else
//直通接口
ble_hid_data_send_hw_fast(MOUSE_SEND_DATA_REPORT_ID, (uint8_t *)&mouse_send_packet, sizeof(mouse_send_packet));
putchar('@');
/* ble_hid_data_send(MOUSE_SEND_DATA_REPORT_ID, (uint8_t *)&mouse_send_packet, sizeof(mouse_send_packet)); */
#endif
#else //如需进行长包短包间隔测试,可以运行下面发包逻辑
static u32 cnt = 0;
cnt++;
if (cnt % 1000 == 0) {
/* log_info("hw_send_packet_fast[cnt:%d len:%d]", cnt, sizeof(mouse_packet_data_t)); */
/* put_buf((uint8_t *)&mouse_send_packet, sizeof(mouse_packet_data_t)); */
static u8 data[64] = {0};
memset(data, ++data[0], sizeof(data));
//测试发BLE长包
hw_send_packet_fast(HID_REPORT_ID_01_SEND_HANDLE, priv_hw, data, sizeof(data), PACKET_DATE_LEN, hw_state);
} else {
hw_send_packet_fast(HID_REPORT_ID_01_SEND_HANDLE, priv_hw, (uint8_t *)&mouse_send_packet, sizeof(mouse_packet_data_t), 27, hw_state);
}
#endif
} else if (mouse_info.mouse_hid_mode == HID_MODE_BLE && SWITCH_MODE_BLE_ENABLE) {
//直通接口
ble_hid_data_send_hw_fast(MOUSE_SEND_DATA_REPORT_ID, (uint8_t *)&mouse_send_packet, sizeof(mouse_send_packet));
putchar('@');
/* ble_hid_data_send(MOUSE_SEND_DATA_REPORT_ID, (uint8_t *)&mouse_send_packet, sizeof(mouse_send_packet)); */
} else if (mouse_info.mouse_hid_mode == HID_MODE_USB && SWITCH_MODE_USB_ENABLE) {
mouse_usb_data_send(MOUSE_SEND_DATA_REPORT_ID, (uint8_t *)&mouse_send_packet, sizeof(mouse_send_packet));
}
// 清除鼠标信息
if (mouse_flag.button_send_flag == 0) {
mouse_flag.button_send_flag = 1;
}
if (mouse_flag.wheel_send_flag == 0) {
mouse_flag.wheel_send_flag = 1;
mouse_send_packet.wheel = 0;
}
if (mouse_flag.sensor_send_flag == 0) {
mouse_flag.sensor_send_flag = 1;
memset((void *)&mouse_send_packet.xymovement, 0, sizeof(mouse_send_packet.xymovement));
}
mouse_conn_send_flag = 0;
}
2.4.4.5. 2.4G模式运行逻辑

上图展示了一个BLE无线鼠标系统的详细架构。以下是对图中各部分的详细解释:
MOUSE SENSOR(鼠标传感器)
功能:检测鼠标的移动和按键操作,将这些物理操作转换为数字信号。
通信接口:使用SPI(串行外设接口)与鼠标主控芯片通信。
鼠标(BLE从机)
功能:接收来自鼠标传感器的数据,通过BLE(2.4GHz频段)发送HID(Human Interface Device)报文。
通信接口
SPI:与鼠标传感器通信,接收传感器数据。
BLE(2.4GHz):无线发送HID报文到BLE主机。
BLE主机(USB接收器)
功能:作为BLE主机设备,接收来自BLE从机(鼠标)的HID报文,并通过USB接口将这些报文传输到计算机。
通信接口
BLE(2.4GHz):无线接收来自鼠标的HID报文。
USB:有线传输数据到计算机。
带USB接口设备(计算机)
功能:接收来自BLE主机(USB接收器)的HID报文,并通过操作系统的HID驱动程序处理这些报文,将其转换为用户的操作(如光标移动、点击等)。
通信接口:通过USB接口与BLE主机通信。
工作流程
用户操作:用户移动鼠标或点击按钮。
传感器检测:鼠标传感器检测到用户的操作,并通过SPI接口将数据传输到鼠标主控芯片。
BLE从机发送数据:鼠标主控芯片将接收到的数据转换为HID报文,通过BLE(2.4GHz频段)发送到BLE主机(USB接收器)。
BLE主机接收数据:USB接收器接收到来自鼠标的HID报文,并通过USB接口将这些数据传输到计算机。
计算机处理数据:计算机通过USB接口接收HID报文,并由操作系统的HID驱动程序处理这些数据,实现用户的操作。
Note
2.4g模式和ble模式一样在蓝牙事件中断实现发数,2.4g暂未实现高回报率
2.4.4.6. USB模式运行逻辑

上图展示了一个通过USB直接连接的有线鼠标系统。以下是对图中各部分的详细解释:
有线鼠标
功能:这是一个有线鼠标,通过USB接口与计算机连接,负责检测用户的操作(移动、点击等),并通过HID(Human Interface Device)协议将这些操作转换为数据报文。
通信:鼠标通过USB电缆直接与计算机进行通信。
带USB接口设备(计算机)
功能:这是计算机或任何带有USB接口的设备,接收来自有线鼠标的HID报文,并通过操作系统的HID驱动程序处理这些报文,将其转换为用户的操作(如光标移动、点击等)。
工作流程
用户操作:用户移动鼠标或点击按钮。
有线鼠标发送数据:鼠标的传感器检测到用户的操作,并将数据转换为HID报文,通过USB电缆发送到计算机。
计算机处理数据:计算机通过USB接口接收HID报文,并由操作系统的HID驱动程序处理这些数据,实现用户的操作。
Note
USB模式的工作原理比较简单,直接使用一个1ms的硬件定时器去采集发数
/*************************************************************************************************/
/*!
* \brief usb in 回调函数
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
void mouse_usb_in_hook()
{
#if SWITCH_MODE_BLE_ENABLE || SWITCH_MODE_24G_ENABLE
// 关闭蓝牙模块
ble_module_enable(0);
#endif
mouse_info_t *mouse_info = mouse_get_status_info();
mouse_select_btmode(HID_MODE_USB);
/* mouse_info->mouse_hid_mode = HID_MODE_USB; */
#if TCFG_LED_ENABLE
mouse_led_operate(MOUSE_LED_USB);
#endif
// 开启usb定时器发数
if (mouse_info->mouse_check_mode_timer) {
sys_s_hi_timer_modify(mouse_info->mouse_check_mode_timer, 20);
}
if (mouse_info->mouse_gtimer_tid) {
gptimer_set_timer_period(mouse_info->mouse_gtimer_tid, MOUSE_USB_GTIMER_INIT_TIME);
} else {
mouse_send_data_timer_init(MOUSE_USB_GTIMER_INIT_TIME);
}
}
2.4.4.7. 休眠逻辑
Note
睡眠可设置无操作定时软关机时间
apps/demo/hid/include/app config.h
#define CONFIG_BLE_CONNECT_SLOT 0 //BLE高回报率设置, 支持私有协议,AW33三模鼠标暂不支持高回报率
#define TCFG_HID_AUTO_SHUTDOWN_TIME (0 * 60) //HID无操作自动关机(单位:秒)
Note
有按键和滚轮操作或者蓝牙事件都会重置定时器
apps/demo/hid/examples/mouse_dual/app_mouse_dual.c
#if (TCFG_HID_AUTO_SHUTDOWN_TIME)
//重置无操作定时计数
if (event->type != SYS_DEVICE_EVENT || DEVICE_EVENT_FROM_POWER != (int)event->arg) { //过滤电源消息
sys_timer_modify(mouse_info.mouse_auto_shutdown_timer, TCFG_HID_AUTO_SHUTDOWN_TIME * 1000);
}
#endif
2.4.4.8. 测试发数逻辑
Note
鼠标应用中添加了模拟sensor发数的逻辑,当滑动鼠标回报率未能成功到达预期时,可以用来测试是传感器数据获取流程出现问题,还是BLE主从通信是否存在问题,会默认控制鼠标画正方形
apps/demo/hid/examples/mouse_dual/app_mouse_dual.h
// 模拟sensor发数使能
#define TEST_MOUSE_SIMULATION_ENABLE 0
apps/demo/hid/examples/mouse_dual/app_mouse_dual.c
#if TEST_MOUSE_SIMULATION_ENABLE
mouse_send_data_test();
#else
....
//=====================================MOUSE TEST==================================================//
#if TEST_MOUSE_SIMULATION_ENABLE
/*************************************************************************************************/
/*!
* \brief mouse测试函数
*
* \param
*
* \return
*
* \note 持续控制鼠标画一个矩形
*/
/*************************************************************************************************/
static void mouse_send_data_test(void)
{
static int16_t deltaX, deltaY;
static uint8_t dcount = 100;
dcount++;
if (dcount >= 100) {
dcount = 0;
if ((deltaX == 0) && (deltaY == 4)) {
deltaX = 4;
deltaY = 0;
} else if ((deltaX == 4) && (deltaY == 0)) {
deltaX = 0;
deltaY = -4;
} else if ((deltaX == 0) && (deltaY == -4)) {
deltaX = -4;
deltaY = 0;
} else if ((deltaX == -4) && (deltaY == 0)) {
deltaX = 0;
deltaY = 4;
} else {
deltaX = 4;
deltaY = 0;
}
}
mouse_optical_sensor_event(0, deltaX, deltaY);
}
//=====================================MOUSE TEST==================================================//
#endif
2.4.4.9. case默认应用资源
Note
demo默认占用外设资源如下,具体可以查看 apps/demo/hid/board/bd57/board_aw33n_mouse_cfg.h
I/O口占用情况
PA口 I/O |
默认占用情况 |
|---|---|
PA11 |
默认打印UART0引脚 |
PA4 |
鼠标左键 |
PA6 |
鼠标右键 |
PA5 |
鼠标中键 |
PA9 |
ADKEY |
硬件定时器占用情况
定时器 |
默认占用情况 |
|---|---|
TIMER0 |
暂无使用 |
TIMER1 |
USB模式定时采集数据发数 |
TIMER2 |
暂无使用 |
TIMER3 |
暂无使用 |
串口占用情况
串口 |
默认占用情况 |
|---|---|
UART0 |
SDK打印 |
UART1 |
暂无使用 |
UART2 |
暂无使用 |
USB暂用情况
USB |
默认占用情况 |
|---|---|
USB0 |
默认使用USB模式发数 |
2.4.4.10. case默认应用功能现象
操作行为 |
现象 |
|---|---|
进入配对模式后,使用bd57 dongle(2.4g)/电脑(ble)连接进行绑定操作,name为AW3XN_DUAL_MOUSE(BLE) |
能够成功绑定连接 |
左键+中键+右键长按3s进入配对模式 |
能够成功绑定连接 |
拨码切换模式 1. 上档为ble模式 2. 下档为24g模式 3. 中间档为关机或UBS模式 |
操作正常 |
拨码开关在中间档同时插上usb,关闭蓝牙,(ble或2.4g)转为USB模式 |
操作正常 |
左,中、右键 |
操作正常 |
DPI切换键 |
操作正常 |
滑轮 |
操作正常 |
侧键1 |
操作正常 |
侧键2 |
操作正常 |
所有模式1min无鼠标操作进入睡眠,按键唤醒 |
行为正常 |
2.4g模式下dongle进入suspend,主机主动断开,进入睡眠 |
行为正常 |
移动顺滑 |
行为正常 |
鼠标移动回包率(usb最高稳定在900+,ble和2.4g最高133) |
行为正常 |