ESP32连接BLE设备具体实现的说明

这篇具有很好参考价值的文章主要介绍了ESP32连接BLE设备具体实现的说明。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


本篇文章以ESP32C3平台作为主机连接血糖仪蓝牙设备的过程为例,对代码的实现进行分析与理解。


一、基础概念

在上手撕代码之前,让我们准备好砍柴刀,先使用nRF Connect APP连接血糖仪对Gatt协议概念以及各层次进行理解,APP下载链接自行百度,这里就不贴出来了,废话不多说,打开手机蓝牙连接血糖仪蓝牙设备,左图为血糖仪的所有服务项,分别是Generic Access、Device Information、Unknown Service、Unknown Service四项服务(Service),右图是UUID为0x1000的Unknown Service服务项的内容,该服务有四个特征(Characteristic)Unknown Characteristic ,每个特征下又有许多属性,下面对涉及到的各个概念进行说明。
esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32

  • Profile
    一个profile文件可以包含一个或者多个服务,一个profile文件包含需要的服务的信息或者为对等设备如何交互的配置文件的选项信息。一般一个设备就一个profile
  • UUID
    UUID是“Universally Unique Identifier”的缩写,通用唯一识别码的意思。对于蓝牙设备,每个服务都有一个与它对应的UUID,蓝牙技术联盟SIG定义UUID共用了一个基本的UUID:0x0000xxxx-0000-1000-8000-00805F9B34FB。总共128位,为了进一步简化基本UUID,每一个蓝牙技术联盟定义的属性有一个唯一的16位UUID,以代替上面的基本UUID的‘x’部分。使用16位的UUID便于记忆和操作,技术联盟已定义好较多的标准服务UUID,同时,也允许厂商定义自己的UUID,以满足已定义服务外的功能实现
  • Service
    一个服务包含一个或多个特性,这些特性是逻辑上相关的集合体。
  • Characteristic
    一个特性至少包含2个属性:一个属性用于声明(又叫描述符),一个属性用于存放特性的值。
    存放特性值的属性就是真正传输的数据,声明属性用来确定该特性是否可读写、是否可以发起通知(类似于向主机发起中断)等信息。
    比如,LED状态就是一个特性,该特性可读写。
  • Properties
    特性的操作类型有:写、没有回应的写、读、通知、指示(有回应的通知)
    通过字面意思就可以理解,比如LED特性,需要写和读性质。如果设备有事件需要上报,比如按键等,就需要通知或者指示性质。通知就是上报完就没事了,指示的话还需要主机给个响应。
  • Descriptors
    描述符就是用于声明的属性。 有一个特别的描述符值得特别地提起:客户端特性配置描述符(Client Characteristic Configuration Descriptor,CCCD),其uuid为0x2901,画知识点,后面会考…这个描述符是给任何支持通知或指示功能的特性额外增加的。在CCCD中写入“1”使能通知功能,写入“2”使能指示功能,写入“0”同时禁止通知和指示功能。

其他概念

  • 角色
    GATT中也分为两个角色,GATT服务器和GATT客户端。
    提供属性的设备称为GATT服务器,访问GATT服务器而获得属性的设备称为GATT客户端。
    比如手机通过访问蓝牙设备的属性来控制设备LED,所以蓝牙设备就是GATT服务器,手机就是GATT客户端。
  • 属性
    属性是GATT服务器中最基本的单元。GATT服务器将其所有的属性组成一个属性表。
    1)一个属性包含句柄、UUID、值:
    2)句柄是属性在GATT表中的索引。我们一般用不到
    3)UUID是属性的ID,包含了属性值的类型等信息,可能有多个属性拥有同一个UUID
    关于GATT协议的一些基础知识

二、相关API参数与使用说明

下面是本例中用到的也是比较常用的API接口的说明

  • 注册设备APP Profile接口
    esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32
  • 搜索服务(通过给定的服务UUID来搜索相应的服务,若搜索到服务,会进入回调函数中的搜索完成事件,搜索结果也会被保存下来到对应的数据结构,将Handle值等都记录下来)

esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32

  • 获取属性数量(通过给定的起始Handle值,在起始Handle范围内搜索属性的数量)
    esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32
  • 查找描述符(通过给定的描述符uuid来搜索结果)

esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32

  • 查找特征(通过给定的特征uuid来搜索结果)
    esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32

  • 注册通知(若特征有通知属性,则需要额外注册通知并且写通知的描述符CCCD(描述符UUID:0x2902))
    esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32

  • 写特征描述符(通过这个API写描述符的值)
    esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32

  • 读特征(顾名思义,读取对应handle特征的值)
    esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32

  • 写特征(同上)
    esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32
    具体官方文档的API说明

三、整体连接流程

本例使用了gattc_multi_connect官方示例进行修改,官方示例完成了一个可以连接多个蓝牙设备的主机,主机连接设备的整体流程图如下:
esp32 关闭和开启ble,ESP32,物联网,单片机,iot,stm32
这里流程图已经把GATTC扫描连接的过程描述得很清楚了,现在让我们通过官方提供的接口来完成这些流程:

1) Register Callbacks & Register APP Profile

 	//Register Callbacks: esp_gap_cb && esp_gattc_cb
	esp_ble_gap_register_callback(esp_gap_cb);
    esp_ble_gattc_register_callback(esp_gattc_cb);
    
    //Register APP Profile: PROFILE_Bioland_BGM_APP_ID
    esp_ble_gattc_app_register(PROFILE_Bioland_BGM_APP_ID);

2)Set scan parameters

	//以下是esp_gap_cb回调函数中更新连接参数的事件,在这个事件中设置了扫描参数
 	case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
         ESP_LOGI(GATTC_TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
                  param->update_conn_params.status,
                  param->update_conn_params.min_int,
                  param->update_conn_params.max_int,
                  param->update_conn_params.conn_int,
                  param->update_conn_params.latency,
                  param->update_conn_params.timeout);
     	  break;

3)Start scanning

    //当设置完连接参数进入设置完成事件开启GAP扫描    
    case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
         //the unit of the duration is second
         uint32_t duration = 30;
         esp_ble_gap_start_scanning(duration);
         break;
    }

4)Get scan results

case ESP_GAP_BLE_SCAN_RESULT_EVT: {
        esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
        switch (scan_result->scan_rst.search_evt) {
        case ESP_GAP_SEARCH_INQ_RES_EVT:
            esp_log_buffer_hex(GATTC_TAG, scan_result->scan_rst.bda, 6);
            ESP_LOGI(GATTC_TAG, "Searched Adv Data Len %d, Scan Response Len %d", scan_result->scan_rst.adv_data_len, scan_result->scan_rst.scan_rsp_len);
            adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv,
                                                ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
            ESP_LOGI(GATTC_TAG, "Searched Device Name Len %d", adv_name_len);
            esp_log_buffer_char(GATTC_TAG, adv_name, adv_name_len);
            ESP_LOGI(GATTC_TAG, "\n");
            if (Isconnecting){
                break;
            }
            if (conn_device_a && conn_device_b && !stop_scan_done){
                stop_scan_done = true;
                esp_ble_gap_stop_scanning();
                ESP_LOGI(GATTC_TAG, "all devices are connected");
                break;
            }
            if (adv_name != NULL) {

                if (strlen(remote_device_name[0]) == adv_name_len && strncmp((char *)adv_name, remote_device_name[0], adv_name_len) == 0) {
                    if (conn_device_a == false) {
                        conn_device_a = true;
                        esp_bd_addr_t bda;
                        memcpy(bda, scan_result->scan_rst.bda, sizeof(esp_bd_addr_t));
                        ESP_LOGI(GATTC_TAG, "bd_addr:%08x%04x",(bda[0] << 24) + (bda[1] << 16) + (bda[2] << 8) + bda[3],(bda[4] << 8) + bda[5]);
                        esp_ble_gap_stop_scanning();
                        ESP_LOGI(GATTC_TAG, "%s", remote_device_name[0]);
                        esp_ble_gattc_open(gl_profile_tab[PROFILE_Bioland_IT_APP_ID].gattc_if, scan_result->scan_rst.bda, scan_result->scan_rst.ble_addr_type, true);
                        Isconnecting = true;
                    }
                    break;
                }
            }
            break;
}

以上四个步骤是在esp_gap_cb这个回调函数中完成的,之后的流程就在你注册的APP Profile接口函数中完成


那么接下来了解APP Profile接口函数的注册,在注册APP Profile接口函数之前先注册了esp_gattc_cb回调函数,所以APP Profile接口函数注册在回调函数中完成:

static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
{
    if (event == ESP_GATTC_REG_EVT) {
        if (param->reg.status == ESP_GATT_OK) {
            gl_profile_tab[param->reg.app_id].gattc_if = gattc_if;
        } else {
            ESP_LOGI(GATTC_TAG, "Reg app failed, app_id %04x, status %d",
                    param->reg.app_id,
                    param->reg.status);
            return;
        }
    }

    /* 定义了多少个PROFILE_NUM,这里就会注册多少个APP Profile接口函数 */
    do {
        int idx;
        for (idx = 0; idx < PROFILE_NUM; idx++) {
            if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
                    gattc_if == gl_profile_tab[idx].gattc_if) {
                if (gl_profile_tab[idx].gattc_cb) {
                    gl_profile_tab[idx].gattc_cb(event, gattc_if, param);
                }
            }
        }
    } while (0);
}

其中gl_profile_tab[idx]定义了APP Profile接口函数的入口,即为gattc_profile_event_handler

static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = {
    [PROFILE_Bioland_BGM_APP_ID] = {
        .gattc_cb = gattc_profile_event_handler,
        .gattc_if = ESP_GATT_IF_NONE,      
    },
};

那如何能够从esp_gap_cb函数跳转到APP Profile接口函数,那就用到了esp_gap_cb中得到扫描结果判断出连接设备后使用esp_ble_gattc_open()这个接口;这个接口完成后会触发跳转到对应设备的APP Profile接口函数中的ESP_GATTC_OPEN_EVT事件进行处理:

case ESP_GATTC_OPEN_EVT:
        if (p_data->open.status != ESP_GATT_OK){
            //open failed, ignore the first device, connect the second device
            ESP_LOGE(GATTC_TAG, "connect device failed, status %d", p_data->open.status);
            conn_device_a = false;
            //start_scan();
            break;
        }
        memcpy(gl_profile_tab[PROFILE_Bioland_BGM_APP_ID].remote_bda, p_data->open.remote_bda, 6);
        gl_profile_tab[PROFILE_Bioland_BGM_APP_ID].conn_id = p_data->open.conn_id;
        ESP_LOGI(GATTC_TAG, "ESP_GATTC_OPEN_EVT conn_id %d, if %d, status %d, mtu %d", p_data->open.conn_id, gattc_if, p_data->open.status, p_data->open.mtu);
        ESP_LOGI(GATTC_TAG, "REMOTE BDA:");
        esp_log_buffer_hex(GATTC_TAG, p_data->open.remote_bda, sizeof(esp_bd_addr_t));
        esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req (gattc_if, p_data->open.conn_id);
        if (mtu_ret){
            ESP_LOGE(GATTC_TAG, "config MTU error, error code = %x", mtu_ret);
        }
        break;

此时已经连接上蓝牙设备,之后可以对蓝牙设备进行操作与协议数据的交互…

1)Configure MTU size && Search service

case ESP_GATTC_CFG_MTU_EVT:
        if (param->cfg_mtu.status != ESP_GATT_OK){
            ESP_LOGE(GATTC_TAG,"Config mtu failed");
        }
        ESP_LOGI(GATTC_TAG, "Status %d, MTU %d, conn_id %d", param->cfg_mtu.status, param->cfg_mtu.mtu, param->cfg_mtu.conn_id);
        esp_ble_gattc_search_service(gattc_if, param->cfg_mtu.conn_id, NULL);//第三个参数是你想要搜索的ServiceUUID,若设置为NULL则搜索所有Service
        break;

2)Get characteristic

//通过0x1002uuid查找特征并存储搜索信息 
    ESP_LOGE(GATTC_TAG, "remote_handle.service_start_handle %d",remote_handle.service_start_handle);
    status = esp_ble_gattc_get_char_by_uuid( gattc_if,
                                             p_data->search_cmpl.conn_id,
                                             remote_handle.service_start_handle,
                                             remote_handle.service_end_handle,
                                             remote_filter_char_uuid_TX,
                                             char_elem_result_REMOTE_TX,
                                             &count);
    ESP_LOGE(GATTC_TAG, "Txchar_by_uuid %d",count);
    ESP_LOGE(GATTC_TAG, "status %d",status);
    if (status != ESP_GATT_OK){
       ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_Txchar_by_uuid error");
    } 

3)Register for notifications

if (count > 0 && (char_elem_result_REMOTE_TX[0].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY)){
     ESP_LOGE(GATTC_TAG, "handle:%d",char_elem_result_REMOTE_TX[0].char_handle);
     remote_handle.char_handle = char_elem_result_REMOTE_TX[0].char_handle;
     esp_ble_gattc_register_for_notify (gattc_if, gl_profile_tab[PROFILE_Bioland_IT_APP_ID].remote_bda, char_elem_result_REMOTE_TX[0].char_handle);
} 

总结

以上就是ESP32C3作为主机连接蓝牙设备的基本流程,其实通过esp_gap_cb进行扫描广播与设备连接后,GATT协议的处理流程就是:
1、搜索sevice uuid 得到结果信息存储到相应的数据结构
2、搜索char uuid得到结果信息(handle、propertits、uuid)存储到相应的数据结构
3、通过存储的结果数据结构来进行读写 通知注册 写入描述符值选择使能通知或指示文章来源地址https://www.toymoban.com/news/detail-594729.html

到了这里,关于ESP32连接BLE设备具体实现的说明的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32+ESP8266(AT固件)连接阿里云物联网 保姆级教学(附代码)--1.创建产品和设备

    提示:这里是从实际应用如何使用教学配置,未从原理讲解,适合小白从零开始到成功,比较有成就感 STM32+ESP8266(AT固件)连接阿里云物联网系列保姆级教学 1. 创建产品和设备 2. 设置产品Topic数据和功能定义设备物模型数据显示 3. 硬件连接+代码修改 4. Web数据可视化 5.功能

    2024年04月25日
    浏览(60)
  • ESP32C3 BLE5.0 吞吐速率的分析与测试

    前言: 本篇文章主要探讨下影响 BLE 传输速率的因素,分析和计算 BLE 1M PHY、BLE 2M PHY 的最大传输速率以及使用 ESP32-C3 验证两种 PHY 的传输速率 当前蓝牙核心规范的版本是v5.3, 从 BLE5.0 版本时, BLE已经可以支持多种物理层:LE 1M UNCODED PHY、LE 2M UNCODED PHY 以及 LE CODED PHY, 其中

    2024年02月12日
    浏览(87)
  • 【ESP8266】使用MQTT协议 连接华为云iotDA,实现设备属性上报

    相关资料:https://github.com/CQUPTLei/ESP8266 往期文章:【ESP8266】基础AT指令和常用WIF指令 【MQTT 5.0】协议 ——发布订阅模式、Qos、keepalive、连接认证、消息结构 华为云物联网平台 (IoT 设备接入云服务)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上

    2024年02月09日
    浏览(29)
  • 006.合宙ESP32-C3+蓝牙调试器通过BLE发送接收数据教程

    在平衡小车制作过程中,需要对KP/KD/KSP/KSI等PID系数进行调试,而平衡小车无法通过USB等进行有线调试,而ESP32-C3自带蓝牙+WIFI,使用WIFI比较吃算力,故选择通过蓝牙进行调参,同时能够将Angle/Encoder/PWM等数据回传至手机端进行查看。 前期通过查找资料,发现合宙ESP32-C3自带蓝

    2024年02月03日
    浏览(43)
  • 物联网开发笔记(53)- 使用Micropython开发ESP32开发板之蓝牙BLE通信

    一、目的         这一节我们学习如何使用我们的ESP32开发板通过蓝牙和手机进行通信。 二、环境         ESP32 + 手机(笔者用的小米10) + Thonny IDE 三、蓝牙介绍         这个知识大家自行百度吧,这里不再赘述什么是蓝牙和蓝牙的历史,以及相关的专业知识。 四、

    2024年02月06日
    浏览(43)
  • ESP32连接MQ Sensor实现气味反应

    ESP32+MQTT+MySQL实现发布订阅【气味数据收集】 🔗 https://blog.csdn.net/ws15168689087/article/details/131627595 ESP32连接云服务器【WebSocket】 🔗 https://blog.csdn.net/ws15168689087/article/details/131406163 个人云服务器搭建MQTT服务器 🔗 https://blog.csdn.net/ws15168689087/article/details/131571433 ESP32开发板引脚介绍

    2024年02月16日
    浏览(23)
  • Arduino 合宙 ESP32 S3 + OV2640 实现低成本SD存储卡相机(ESP32连接SD模块引脚)

    合宙ESP32 S3 板载16M flash,8m psram和一个FPC相机接口,价格却不到30元,无疑比价格将近50元的第三方ESP32 S3和将近30的ESP32 Cam更具性价比。 但是虽然板载FPC,由于接口冲突,导致相机与psram不能同时开启,作为ESP32 Cam的替代品来看,还缺少了板载SD卡,而且作为一块发布不久的开发

    2024年02月04日
    浏览(38)
  • STM32+ESP8266(AT固件)连接阿里云物联网 保姆级教学(附代码)--2. 设置产品Topic数据和功能定义设备物模型数据显示

    提示:这里是从实际应用如何使用教学配置,未从原理讲解,适合小白从零开始到成功,比较有成就感 STM32+ESP8266(AT固件)连接阿里云物联网系列保姆级教学 1. 创建产品和设备 2. 设置产品Topic数据和功能定义设备物模型数据显示 3. 硬件连接+代码修改 4. Web数据可视化 5.功能

    2024年02月03日
    浏览(49)
  • ESP32的MQTT AT固件烧录+STM32以ESP32的MQTT AT固件的AT指令连接EMQX下mqtt服务器实现消息订阅和发布

    目录 写在前面 三种方案(利用ESP32连接EMQX下的MQTT) 步骤 ESP32烧录固件并AT指令进行测试。 下载固件  烧录工具下载 烧录固件(选择ESP32)  关于AT 指令与MQTT服务器断开后自动重连MQTT服务器 关于AT指令设置上电自动连接WIFI 关于AT指令设置断开后自动重新连接WIFI STM32对接E

    2023年04月12日
    浏览(30)
  • ESP8266连接阿里云(三)连接上阿里云设备

    网盘链接:链接: https://pan.baidu.com/s/1Xx1Vy5NfFU3XRirivi6iDQ?pwd=8888 提取码: 8888 1)AT+RST   重启设备 2)AT+CWMODE=3   AP+Station模式 3)AT+CIPSNTPCFG=1,8,\\\"ntp1.aliyun.com\\\"   开启SNTP服务器,8时域,SNTP服务器为阿里云域名 4)AT+CWJAP=\\\"wifi名字\\\",\\\"WiFi密码\\\"   连接到WIFI ESP8266回复都ok代表连接上了WIFI或者热

    2024年02月13日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包