《ESP32从0到1》之:蓝牙一对多主机(补充篇)


文章内容

基于bluetooth->gattc_multi_connect示例创建工程,读懂程序,配合已有蓝牙从机设备,实现蓝牙主机一对多通信。

补充篇:之前调试只实现了连接一台蓝牙从机设备通信,补充篇实现一对多通信;同时开启多个notfiy


硬件

● 一款 ESP32 开发板(本专辑中均使用ESP32-LyraT-Mini V1.2开发板)
● USB 数据线 (A 转 Micro-B)
● 电脑(Windows)


一个服务下同时开启多个特征notify

用手机蓝牙调试助手app观察蓝牙从机模块服务及特征表
在这里插入图片描述
gattc_multi_connect示例程序中,针对notify的操作如下:

● 指定一个含notify属性的特征UUID(REMOTE_NOTIFY_CHAR_UUID)
● 通过esp_ble_gattc_get_char_by_uuid获取指定UUID的特征。其中count表示获取到特征的数量,char_elem_result_a用于存放获取到的特征元素(char_handle特征句柄、properties属性、UUID)
● 判断特征数量>0,char_elem_result_a[0]的特征其属性是否包含notify,若是包含notify则注册服务通知,对应特征值写入1开启notify

通过实验查找并验证问题,当REMOTE_NOTIFY_CHAR_UUID分别设为上图中的0xffe2和0xffe4时,确认esp_ble_gattc_get_char_by_uuid执行后返回的count值以及char_handle

增加LOGE语句,便于debug观察。在这里插入图片描述

#define REMOTE_NOTIFY_CHAR_UUID  0xffe2

执行结果如下:
在这里插入图片描述

#define REMOTE_NOTIFY_CHAR_UUID  0xffe4

执行结果如下:
在这里插入图片描述
尝试将esp_ble_gattc_get_char_by_uuid参数由char_UUID改成service_UUID,实测会报错。
在这里插入图片描述
基本结论:若是需要实现多个notify只能改动程序,需要指定多个uuid并进行多次esp_ble_gattc_get_char_by_uuid获取。

修改程序如下:
● 指定多个含notify属性的特征UUID,增加一个宏定义,用于后续动态分配空间时使用,同步修改定义多个remote_filter_char_uuid。(本实验中设定为2个notify)

#define REMOTE_SERVICE_UUID      0xffe0   //  0x00FF   //对应蓝牙从机设备(gatt_server)服务UUID
#define REMOTE_NOTIFY_CHAR_UUID1  0xffe2  //  0xFF01   //对应服务UUID为0x00FF下的特征UUID
#define REMOTE_NOTIFY_CHAR_UUID2  0xffe4
#define REMOTE_NOTIFY_CHART_COUNT   2   //需要开启两个特征的notify,增加一个宏定义,后续动态开辟空间时用
//其保存的是需要获取的特征UUID。主要esp_ble_gattc_get_char_by_uuid中使用,传递参数。通过uuid获取指定特征
static esp_bt_uuid_t remote_filter_char_uuid1 = {
    .len = ESP_UUID_LEN_16,
    .uuid = {.uuid16 = REMOTE_NOTIFY_CHAR_UUID1,},
};
static esp_bt_uuid_t remote_filter_char_uuid2 = {
    .len = ESP_UUID_LEN_16,
    .uuid = {.uuid16 = REMOTE_NOTIFY_CHAR_UUID2,},
};

● ESP_GATTC_SEARCH_CMPL_EVT事件处理中,通过调用esp_ble_gattc_get_char_by_uuid两次,获取指定UUID的特征,注册两个服务通知。(调用两次共用同一个count变量,逻辑上没那么严谨,但无伤大雅,后续可自行优化)
在这里插入图片描述
● ESP_GATTC_REG_FOR_NOTIFY_EVT事件处理中,相关操作均执行两次,传递不同的特征句柄,实现使能notify操作。
在这里插入图片描述
● ESP_GATTC_WRITE_DESCR_EVT事件处理中,因采购的蓝牙从机模块未开放相关特征说明,不做多余写入操作,注释掉写特征值部分程序。
在这里插入图片描述
● gattc_profile_b_event_handler和gattc_profile_c_event_handler事件处理程序中导入上述相同的修改。编译运行结果如下:
在这里插入图片描述
至此,一个服务下同时开启多个特征notify功能实现。

实现一对多通信

gattc_multi_connect示例为一主多从程序,实际测试只能连接一个蓝牙从机设备。从程序debug上看,连接了第一台从机设备后就不再进行扫描了。
搜索“esp_ble_gap_stop_scanning",查看程序中哪些条件成立会导致停止扫描。导致停止扫描的条件如下:
● esp_gap_cb回调函数的ESP_GAP_BLE_SCAN_RESULT_EVT事件处理中,已连接3台设备
在这里插入图片描述
● esp_gap_cb回调函数的ESP_GAP_BLE_SCAN_RESULT_EVT事件处理中,每次搜索到指定设备名称(remote_device_name)的设备时会停止扫描。
在这里插入图片描述
尝试修改:只保留条件1,注释掉上述条件2里的“esp_ble_gap_stop_scanning();”

编译运行结果:一台设备都无法连接,内部看门狗溢出导致任务重启。
转换思路,搜索“start_scan”,查看程序中哪些条件成立会启动扫描。启动扫描的条件如下:
● ESP_GATTC_WRITE_CHAR_EVT(GATT特征写入操作完成事件)中不管是否成功写入特征值,均会调用start_scan()启动蓝牙扫描;
● ESP_GATTC_DISCONNECT_EVT(ble物理连接断开事件)中调用start_scan()启动蓝牙扫描;

从程序上看,程序开机后会扫描广播,扫描到指定设备名称的设备后进行连接,连接时暂停扫描,写特征值完成后再重新启动扫描。查看程序基本确定是因为ESP_GATTC_WRITE_DESCR_EVT事件处理中,注释掉了写特征值部分程序,未进行写特征值操作,因此程序未能进入ESP_GATTC_WRITE_CHAR_EVT事件处理程序,也就未能重新开启扫描。

尝试修改:考虑到当前配合测试的是采购的现成蓝牙从机设备,未提供相关特征值操作说明,因此无法确定自行写入特征值是否会影响其正常工作,因此还是决定注释掉ESP_GATTC_WRITE_DESCR_EVT事件处理中的写特征值部分程序,然后将start_scan()从ESP_GATTC_WRITE_CHAR_EVT事件处理中挪到ESP_GATTC_WRITE_DESCR_EVT事件处理中。
在这里插入图片描述

编译运行结果:第一个蓝牙从机设备开机后显示连接成功,第二个蓝牙从机设备无法连接成功,debug信息中出现了多次异常信息“ task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:”,如下图所示:
在这里插入图片描述
发现每次发生的位置基本在两个log附近,查找资料,在两个log之前加入vTaskDelay(1);运行则不再出现task_wdt异常提示。
在这里插入图片描述
在这里插入图片描述
虽然不再出现task_wdt异常提示,但是第二个蓝牙从机设备依旧无法连接。查看debug信息,比对能正常连接和无法正常连接的搜索部分信息,发现区别如下图所示。
在这里插入图片描述
对应到程序部分,发现问题。实验中配合测试的蓝牙从机模块设备名称均相同,因此“static const char remote_device_name[3][20] = {“YX-BLE-Tag”, “YX-BLE-Tag”, “YX-BLE-Tag”};”写入的指定设备名称均相同,导致下方程序在做判断时,第一个条件永远符合,当第一个从机设备连接成功conn_device_==true时,直接跳出了该部分程序。

在这里插入图片描述
调整条件判断逻辑如下:

 if (adv_name != NULL) {
                //当前获取的设备名称及长度与连接并记录的第一个server比对相同
                 if (conn_device_a == false) {   
                  if (strlen(remote_device_name[0]) == adv_name_len && strncmp((char *)adv_name, remote_device_name[0], adv_name_len) == 0) {
                        conn_device_a=true;
                          ESP_LOGI(GATTC_TAG, "Searched device %s", remote_device_name[0]);
                        esp_ble_gap_stop_scanning();//停止扫描广播
                        //打开一个直接连接或添加一个后台自动连接
                        esp_ble_gattc_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, scan_result->scan_rst.bda, scan_result->scan_rst.ble_addr_type, true);
                        Isconnecting = true;
                    }                  
                    break;
                 }
                 else if (conn_device_b == false) {   
                  if (strlen(remote_device_name[1]) == adv_name_len && strncmp((char *)adv_name, remote_device_name[1], adv_name_len) == 0) {
                        conn_device_b=true;
                        ESP_LOGI(GATTC_TAG, "Searched device %s", remote_device_name[1]);
                        esp_ble_gap_stop_scanning();
                        esp_ble_gattc_open(gl_profile_tab[PROFILE_B_APP_ID].gattc_if, scan_result->scan_rst.bda, scan_result->scan_rst.ble_addr_type, true);
                        Isconnecting = true;
                    }
                    break;
                 }
                else if (conn_device_c == false) {   
                  if (strlen(remote_device_name[2]) == adv_name_len && strncmp((char *)adv_name, remote_device_name[2], adv_name_len) == 0) {
                        conn_device_c=true;
                         ESP_LOGI(GATTC_TAG, "Searched device %s", remote_device_name[2]);
                        esp_ble_gap_stop_scanning();
                        esp_ble_gattc_open(gl_profile_tab[PROFILE_C_APP_ID].gattc_if, scan_result->scan_rst.bda, scan_result->scan_rst.ble_addr_type, true);
                        Isconnecting = true;
                    }
                    break;
                 }
            }

ESP_GATTC_NOTIFY_EVT事件中增加一个log打印mac地址,便于debug时观察上报的数据来源。

在这里插入图片描述
测试结果:3台蓝牙从机设备均连接成功。且notify上报成功。
在这里插入图片描述

基本结论:
1)原始的gattc_multi_connect示例只适用于连接3个设备名称不同的蓝牙从机设备。若要连接3个设备名称相同的设备则需要调整gap回调函数中ESP_GAP_BLE_SCAN_RESULT_EVT事件处理程序中的条件判断逻辑;

2)原始的gattc_multi_connect示例在启动扫描部分逻辑上是程序开机后会扫描广播,扫描到指定设备名称的设备后进行连接,连接时暂停扫描,写特征值完成后再重新启动扫描。因配合测试的蓝牙从机设备是现成采购的,未提供特征值相关操作说明,因此不对其进行特征值写入,程序针对这块逻辑上需要略作调整;

3) 原始的gattc_multi_connect示例其扫描广播周期是30s,30s之后就会停止扫描。实际应用中应该是若是没有连满3个从机设备则一直处于扫描状态。此问题暂不做修改。

最后补充:gattc_multi_connect示例程序中最多可连接3个蓝牙从机设备,分别写了3个事件处理程序,gattc_profile_a_event_handler/gattc_profile_b_event_handler/gattc_profile_c_event_handler。所有相关修改都需要3个处理程序同步修改。实际上,当连接的蓝牙从机设备为同一类型设备,且所有处理程序均相同时,可以合并成同一个事件处理程序以实现优化程序及代码的目的。

下一篇《ESP32从0到1》之MQTT与阿里iot通信,记得关注哦!


欢迎关注并留言

文章同步发表于公众号"IT搬砖客",欢迎关注并留言。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT搬砖客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值