1. 首先杰理的sdk代码封装了好几个模块,我们codeblocks打开需要做蓝牙hid的模块路径如下:
sdk\apps\hid\board\bd19\AC632N_hid.cbp
注意:AC6328A用到的是bd19,其他的bd文件包可以删除精简代码
2. 在hid的board_config.h里面选择你要的板级配置…define 哪个宏就打开下面哪个头文件,不用的注释掉. >>>>>这个文件路径如下:
apps\hid\board\bd19\board_config.h
#define CONFIG_BOARD_AC632N_DEMO
// #define CONFIG_BOARD_AC6321A_DEMO
// #define CONFIG_BOARD_AC6321A_STAND_KEYBOARD//AC6321A+AD15键盘项目,download.bat需要修改添加打包ex_mcu.bin
// #define CONFIG_BOARD_AC6321A_MOUSE
// #define CONFIG_BOARD_AC6323A_DEMO
// #define CONFIG_BOARD_AC6328A_KEYFOB
// #define CONFIG_BOARD_AC6328B_DEMO
// #define CONFIG_BOARD_AC6329B_DEMO
// #define CONFIG_BOARD_AC6329C_DEMO
// #define CONFIG_BOARD_AC6329E_DEMO
// #define CONFIG_BOARD_AC6329F_DEMO
#include "board_ac632n_demo_cfg.h"
// #include "board_ac6321a_demo_cfg.h"
// #include "board_ac6321a_stand_keyboard_cfg.h"
// #include "board_ac6321a_mouse_cfg.h"
// #include "board_ac6323a_demo_cfg.h"
// #include "board_ac6328a_keyfob_cfg.h"
// #include "board_ac6328b_demo_cfg.h"
// #include "board_ac6329b_demo_cfg.h"
// #include "board_ac6329c_demo_cfg.h"
// #include "board_ac6329e_demo_cfg.h"
// #include "board_ac6329f_demo_cfg.h"
3. 然后跳进上面那个没有被注释掉的头文件配置 #include “board_ac632n_demo_cfg.h”
4. 要串口打印日志的自己在 UART配置 里面配置,以下是我的配置,你自己根据你的串口改,我的仅供参考
//*********************************************************************************//
// UART配置 //
//*********************************************************************************//
#define TCFG_UART0_ENABLE ENABLE_THIS_MOUDLE //串口打印模块使能
#define TCFG_UART0_RX_PORT NO_CONFIG_PORT //串口接收脚配置(用于打印可以选择NO_CONFIG_PORT)
#define TCFG_UART0_TX_PORT IO_PORT_DP //串口发送脚配置
#define TCFG_UART0_BAUDRATE 115200 //串口波特率配置
5. 最后配置蓝牙,因为我们要做的是蓝牙自拍杆,其实就是给手机发送一个音量减少的动作,这用到了hid协议,以下就是我蓝牙配置的选项,仅供参考:
//*********************************************************************************//
// 蓝牙配置 //
//*********************************************************************************//
#define TCFG_USER_TWS_ENABLE 0 //tws功能使能
#define TCFG_USER_BLE_ENABLE 0 //BLE功能使能,---使能后,请配置TCFG_BLE_DEMO_SELECT选择DEMO例子
#define TCFG_USER_EDR_ENABLE 1 //EDR功能使能
#if TCFG_USER_EDR_ENABLE
#define USER_SUPPORT_PROFILE_SPP 0
#define USER_SUPPORT_PROFILE_HFP 0
#define USER_SUPPORT_PROFILE_A2DP 0
#define USER_SUPPORT_PROFILE_AVCTP 0
#define USER_SUPPORT_PROFILE_HID 1
#define USER_SUPPORT_PROFILE_PNP 0
#define USER_SUPPORT_PROFILE_PBAP 0
#endif
6. 配置完成后,我们就去设置app的hid模式,因为杰理的开发包封装了很多个hid设备,但是因为我只要发送一个音量减少的动作,所以我就在默认的app配置里面增加hid报告描述符并且改动,以下是我的配置,仅供参考>>>配置路径如下:
apps\hid\include\app_config.h
//app case 选择,只选1,要配置对应的board_config.h
#define CONFIG_APP_KEYBOARD 1//hid按键 ,default case
#define CONFIG_APP_KEYFOB 0//自拍器, board_ac6368a,board_6318,board_6379b
#define CONFIG_APP_MOUSE_SINGLE 0//单模切换
#define CONFIG_APP_MOUSE_DUAL 0//同时开双模
#define CONFIG_APP_STANDARD_KEYBOARD 0//标准HID键盘,board_ac6351d
#define CONFIG_APP_KEYPAGE 0//翻页器
#define CONFIG_APP_GAMEBOX 0//吃鸡王座
#define CONFIG_APP_REMOTE_CONTROL 0//语音遥控
#define CONFIG_APP_IDLE 0//IDLE
7. 以上的配置结束,当烧录进去,单片机就会默认跑下面这个路径的demo
apps\hid\examples\keyboard\app_keyboard.c
下面开始教你们怎么通过hid通道发送一个音量减的数据:
1.先修改static const u8 hidkey_report_map[]里面的报告描述符
因为我上一篇博客用过一个报告描述符,所以我直接把他copy过来,懒得折腾,把他原本的注释掉
代码如下:
static const u8 hidkey_report_map[] = {
// 0x05, 0x0C, // Usage Page (Consumer)
// 0x09, 0x01, // Usage (Consumer Control)
// 0xA1, 0x01, // Collection (Application)
// 0x85, 0x01, // Report ID (1)
// 0x09, 0xE9, // Usage (Volume Increment)
// 0x09, 0xEA, // Usage (Volume Decrement)
// 0x09, 0xCD, // Usage (Play/Pause)
// 0x09, 0xE2, // Usage (Mute)
// 0x09, 0xB6, // Usage (Scan Previous Track)
// 0x09, 0xB5, // Usage (Scan Next Track)
// 0x09, 0xB3, // Usage (Fast Forward)
// 0x09, 0xB4, // Usage (Rewind)
// 0x15, 0x00, // Logical Minimum (0)
// 0x25, 0x01, // Logical Maximum (1)
// 0x75, 0x01, // Report Size (1)
// 0x95, 0x10, // Report Count (16)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0xC0, // End Collection
// // 35 bytes
0x05, 0x01, // USAGE_PAGE (Generic Desktop Controls)
0x09, 0x02, // USAGE (Mouse)
0xA1, 0x01, // COLLECTION (Application) //用Collections和Report ID设成综合性设备
0x85, 0x01, // REPORT_ID (1)
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)
0x75, 0x05, // REPORT_SIZE (5)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop Controls)
0x09, 0x01, // USAGE (Pointer)
0xA1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x16, 0x00, 0xD8, // LOGICAL_MINIMUM (-6000)
0x26, 0x00, 0x28, // LOGICAL_MAXIMUM (6000)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xC0, // END_COLLECTION
0xC0, // END_COLLECTION
0x05, 0x0C, // USAGE_PAGE (Consumer Devices)
0x09, 0x01, // USAGE (Consumer Control)
0xA1, 0x01, // COLLECTION (Application)
0x85, 0x02, // REPORT_ID (2)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x09, 0x34, // USAGE (Stop) 0000 0001 (0x01)
0x09, 0x40, // USAGE (Menu) 0000 0010 (0x02)
0x0A, 0x23, 0x02, // USAGE (Forward) 0000 0100 (0x04)
0x0A, 0x24, 0x02, // USAGE (Backward) 0000 1000 (0x08)
0x09, 0xE9, // USAGE (Volume Up) 0001 0000 (0x10)
0x09, 0xEA, // USAGE (Volume Down) 0010 0000 (0x20)
0x09, 0xB0, // USAGE (Play) 0100 0000 (0x40)
0x09, 0xB1, // USAGE (Pause) 1000 0000 (0x80)
0x09, 0xB3, // USAGE (Fast Forward) 0000 0001 0000 0000 (0x0100)
0x09, 0xB4, // USAGE (Rewind) 0000 0010 0000 0000 (0x0200)
0x09, 0xB5, // USAGE (Scan Next Track) 0000 0100 0000 0000 (0x0400)
0x09, 0xB6, // USAGE (Scan Previous Track) 0000 1000 0000 0000 (0x0800)
0x09, 0xB7, // USAGE (Stop) 0001 0000 0000 0000 (0x010000)
0x09, 0xCD, // USAGE (Play/Pause) 0010 0000 0000 0000 (0x020000)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x0E, // REPORT_COUNT (14) //只用到16个bit的14个bit
0x81, 0x22, // INPUT (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x02, // REPORT_COUNT (2) //要补齐多余2个没用的bit
0x81, 0x02, // INPUT (Data,Var,Abs)
0xC0, // END_COLLECTION
};
因为你修改了这个hid报告描述符,杰理的sdk封装好了就会自动帮你注册好了,然后你只需要发送hid数据就能完成你的需求了.
2.看看原理图,因为只有一个PA9引脚,所以就用PA9引脚连接一个按钮,用按钮控制发送一次hid数据,初始化gpio口
gpio初始化代码如下:
static void gpio_init(){
gpio_set_die(IO_PORTA_09, 1);
gpio_set_dieh(IO_PORTA_09, 1);
gpio_set_direction(IO_PORTA_09, 1);
}
把gpio_init()这个函数放在hidkey_app_start()函数最下面;
根据串口打印的日志,我发现下面这个函数一直在打印日志
static void hidkey_key_event_handler(struct sys_event *event);
猜测一下应该是一个按钮事件,于是我把他原本的代码修改如下:
static void hidkey_key_event_handler(struct sys_event *event)
{
/* u16 cpi = 0; */
// u8 event_type = 0;
// u8 key_value = 0;
if (event->arg == (void *)DEVICE_EVENT_FROM_KEY) {
// event_type = event->u.key.event;
// key_value = event->u.key.value;
// log_info("hidkey app_key_evnet: %d,%d\n", event_type, key_value);
// hidkey_app_key_deal_test(event_type, key_value);
/*上面为原始demo*/
u8 button_status = gpio_read(IO_PORTA_09);
// printf(">>>>>=======>>>>>>%d\n",gpio_read(IO_PORTA_09));
if(button_status == 0){
printf("按钮按下\n");
u8 hid_arr[]={0xA1,0x02,0x20}; //用6951的报告描述符-->音量降低
user_hid_send_data(hid_arr,sizeof(hid_arr));
hid_arr[2]=0x00;
user_hid_send_data(hid_arr,sizeof(hid_arr));
}
}
}
当gpio口检测到按钮按下,会发送2次hid数据给设备…
当手机连接蓝牙并且当按钮按下,手机音量就会降低一次.
至于发送的数据原理,我现在来解释一下
0xA1: 是蓝牙hid通道必须发的(不确定是杰理芯片还是规定,但是杰理的蓝牙hid数据必须要先发0xA1)
0x02: 根据报告描述符好report2的选择,我们要report2的功能第二个必须发送0x02
0x20: 第三个数据请看report2下面每个功能后面我注释掉十六进制数据,第三个功能根据注释掉十六进制就能控制手机的各种功能
至于为什么发送了一次数据,又要修改第三个数据为0再发送一次…因为这样就能模拟一次点击事件,否则就会认为你一直按着音量键,音量会持续下降…发送了就实现点击一次,音量降低一次
已解决兼容IOS通过蓝牙hid控制音量增减
流程大概跟上面一样,但是用的example是下面这个路径的:
apps\hid\examples\keyfob\app_keyfob.c
用这个路径报告描述符不用修改
然后在上面第6点选择第二个宏打开
最后把按键事件句柄换成以下
static void app_keyfob_event_handler(struct sys_event *event)
{
/*
* 下面这段函数指针的作用是因为当使能了ble后,edr发送的hid数据不生效,
* 需要用ble的通道发送hid数据,故加以判断看使用哪个通道发送hid数据
*/
void (*hid_data_send_pt)(u8 report_id, u8 * data, u16 len) = NULL;
#if TCFG_USER_EDR_ENABLE && !TCFG_USER_BLE_ENABLE
hid_data_send_pt = edr_hid_data_send;
#endif
#if TCFG_USER_BLE_ENABLE
hid_data_send_pt = ble_hid_data_send;
#endif
u8 button_status = gpio_read(IO_PORTA_09);
/*谨记: 请不要用IPhone修改蓝牙名称,断开连接后会导致安卓控制失效!!!*/
/*谨记: 请不要用IPhone修改蓝牙名称,断开连接后会导致安卓控制失效!!!*/
/*谨记: 请不要用IPhone修改蓝牙名称,断开连接后会导致安卓控制失效!!!*/
if(button_status == 0){
printf("按钮按下\n");
u8 vol_down[3] = {0x00, 0x01, 0x00};
hid_data_send_pt(3, vol_down, 3);
vol_down[1] = 0;
hid_data_send_pt(3, vol_down, 3);
}
}
以上,对你有帮助点个赞,留个言,还有不懂再有偿私聊