IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 从零开始的nrf52832蓝牙开发(8)--连接 -> 正文阅读

[系统运维]从零开始的nrf52832蓝牙开发(8)--连接

因为笔者周围蓝牙设备过多,所以就不做直接连接实验了,但是仍就会先从直接连接讲。

1.过滤连接

1.1主机端

想要连接设备,我们的主机要发起连接,但是发起之后,怎么进行连接,这个是由连接参数决定,这就又回到了设置扫描初始化那个结构体:

连接参数结构体定义:

typedef struct
{
  uint16_t min_conn_interval;         /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
  uint16_t max_conn_interval;         /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
  uint16_t slave_latency;             /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/
  uint16_t conn_sup_timeout;          /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/
} ble_gap_conn_params_t;

参数意义可以参考以下文档的3.4节:

蓝牙技术详解

这里我们定义:

然后它被放在和扫描参数一起初始化:

?

然后只需要在扫描回调事件中连接:

            ret_code_t          err_code;
            
            // 配置准备连接的设备MAC
            ble_gap_addr_t m_addr;
            m_addr.addr_id_peer = 1;
            m_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC;
            memcpy(m_addr.addr,p_scan_evt->params.p_not_found->peer_addr.addr,BLE_GAP_ADDR_LEN);
            
            // 停止扫描
            nrf_ble_scan_stop();
            // 发起连接
            err_code = sd_ble_gap_connect(&m_addr,&m_scan_params,&m_conn_params,APP_BLE_CONN_CFG_TAG);
            APP_ERROR_CHECK(err_code);

在直接连接的例子中,我们使用的是判断信号强度,然后直接把扫描到的设备的MAC地址复制到我们想要连接设备的地址里:

?

但是前文说过,笔者周围蓝牙设备太多,所以不做直接连接了,直接做过滤连接:

?

我把连接处理放在了,过滤匹配后的事件回调内,但没有删掉对信号强度的判断,也就是除了过滤要符合,信号还要够强。

注意,我们把扫描关闭后,就不再会有扫描事件被触发回调了,而到了BLE事件中:

//******************************************************************
// fn : ble_evt_handler
//
// brief : BLE事件回调
// details : 包含以下几种事件类型:COMMON、GAP、GATT Client、GATT Server、L2CAP
//
// param : ble_evt_t  事件类型
//         p_context  未使用
//
// return : none
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    ble_gap_evt_connected_t const * p_connected_evt = &p_gap_evt->params.connected;
    switch (p_ble_evt->header.evt_id)
    {
        // 连接
        case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO("Connected. conn_DevAddr: %s\nConnected. conn_handle: 0x%04x\nConnected. conn_Param: %d,%d,%d,%d",
                         Util_convertBdAddr2Str((uint8_t*)p_connected_evt->peer_addr.addr),
                         p_gap_evt->conn_handle,
                         p_connected_evt->conn_params.min_conn_interval,
                         p_connected_evt->conn_params.max_conn_interval,
                         p_connected_evt->conn_params.slave_latency,
                         p_connected_evt->conn_params.conn_sup_timeout
                         );
            break;
        // 断开连接
        case BLE_GAP_EVT_DISCONNECTED:
            NRF_LOG_INFO("Disconnected. conn_handle: 0x%x, reason: 0x%04x",
                         p_gap_evt->conn_handle,
                         p_gap_evt->params.disconnected.reason);
            // 如果需要异常断开重连,可以打开下面的注释
            // scan_start();  // 重新开始扫描
            break;

        default:
            break;
    }
}

当设备连接和断开后,分别会触发:

BLE_GAP_EVT_CONNECTED?和?BLE_GAP_EVT_DISCONNECTED这两个事件,其他事件还有:

?

总的扫描回调函数:


//******************************************************************
// fn : scan_start
//
// brief : 开始扫描
//
// param : none
//
// return : none
static void scan_start(void)
{
    ret_code_t ret;

    ret = nrf_ble_scan_start(&m_scan);
    APP_ERROR_CHECK(ret);
}

//******************************************************************
// fn : scan_evt_handler
//
// brief : 处理扫描回调事件
//
// param : scan_evt_t  扫描事件结构体
//
// return : none
static void scan_evt_handler(scan_evt_t const * p_scan_evt)
{
    uint32_t err_code;
    ble_gap_addr_t peer_addr;
    ble_gap_addr_t const * p_peer_addr;
    switch(p_scan_evt->scan_evt_id)
    {
        // 白名单设置请求
        case NRF_BLE_SCAN_EVT_WHITELIST_REQUEST:
        {
          memset(&peer_addr, 0x00, sizeof(peer_addr));
          peer_addr.addr_id_peer = 1;
          peer_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC;
          peer_addr.addr[5] = 0xD0;
          peer_addr.addr[4] = 0xD3;
          peer_addr.addr[3] = 0x07;
          peer_addr.addr[2] = 0xCE;
          peer_addr.addr[1] = 0xDF;
          peer_addr.addr[0] = 0xF5;
          p_peer_addr = &peer_addr; 
          
          // 设置白名单
          err_code = sd_ble_gap_whitelist_set(&p_peer_addr, 0x01);
          if (err_code == NRF_SUCCESS)
          {
            NRF_LOG_INFO("Successfully set whitelist!");
          }
          APP_ERROR_CHECK(err_code);
        }break;
        
        // 扫描到的白名单设备数据
        case NRF_BLE_SCAN_EVT_WHITELIST_ADV_REPORT:
        {
          // 判断是否为扫描回调数据
          if(p_scan_evt->params.p_whitelist_adv_report->type.scan_response)
          {
            if(p_scan_evt->params.p_whitelist_adv_report->data.len)    // 存在扫描回调数据
            {
              NRF_LOG_INFO("scan data:  %s",
                            Util_convertHex2Str(
                            p_scan_evt->params.p_whitelist_adv_report->data.p_data,
                            p_scan_evt->params.p_whitelist_adv_report->data.len));
            }
            else
            {
              NRF_LOG_INFO("scan data:  %s","NONE");
            }
            NRF_LOG_INFO("rssi:  %ddBm",p_scan_evt->params.p_whitelist_adv_report->rssi);
          }
          else  // 否则为广播数据
          {
            // 打印扫描的设备MAC
            NRF_LOG_INFO("Device MAC:  %s",
                         Util_convertBdAddr2Str((uint8_t*)p_scan_evt->params.p_whitelist_adv_report->peer_addr.addr));
            
            if(p_scan_evt->params.p_whitelist_adv_report->data.len)    // 存在广播数据
            {
              NRF_LOG_INFO("adv data:  %s",
                            Util_convertHex2Str(
                            p_scan_evt->params.p_whitelist_adv_report->data.p_data,
                            p_scan_evt->params.p_whitelist_adv_report->data.len));
            }
            else
            {
              NRF_LOG_INFO("adv data:  %s","NONE");
            }
          }
        } break;
        case NRF_BLE_SCAN_EVT_NOT_FOUND:
        {
          NRF_LOG_INFO("@@@@@@@@@@@@-------------------------- EVENT ------------------------------");
          // 判断是否为扫描回调数据
          if(p_scan_evt->params.p_not_found->type.scan_response)
          {
            if(p_scan_evt->params.p_not_found->data.len)    // 存在扫描回调数据
            {
              NRF_LOG_INFO("@@@@@@@@@@@@ScanRsp Data:%s",
                            Util_convertHex2Str(
                            p_scan_evt->params.p_not_found->data.p_data,
                            p_scan_evt->params.p_not_found->data.len));
            }
            else
            {
              NRF_LOG_INFO("@@@@@@@@@@@@ScanRsp Data:%s","NONE");
            }
            
          }
          else  // 否则为广播数据
          {
            //打印设备RSSI信号
            NRF_LOG_INFO("@@@@@@@@@@@@Device RSSI: %ddBm",p_scan_evt->params.p_not_found->rssi);
            // 打印扫描的设备MAC
            NRF_LOG_INFO("@@@@@@@@@@@@Device MAC:  %s",
                         Util_convertBdAddr2Str((uint8_t*)p_scan_evt->params.p_not_found->peer_addr.addr));
            
            if(p_scan_evt->params.p_not_found->data.len)    // 存在广播数据
            {
              NRF_LOG_INFO("@@@@@@@@@@@@Adv Data:    %s",
                            Util_convertHex2Str(
                            p_scan_evt->params.p_not_found->data.p_data,
                            p_scan_evt->params.p_not_found->data.len));
            }
            else
            {
              NRF_LOG_INFO("@@@@@@@@@@@@Adv Data:  %s","NONE");
            }
          }
           如果扫描到的设备信号强度大于-30dBm
          //if(p_scan_evt->params.p_not_found->rssi > (-30))
          //{
          //  ret_code_t          err_code;
            
          //  // 配置准备连接的设备MAC
          //  ble_gap_addr_t m_addr;
          //  m_addr.addr_id_peer = 1;
          //  m_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC;
          //  memcpy(m_addr.addr,p_scan_evt->params.p_not_found->peer_addr.addr,BLE_GAP_ADDR_LEN);
            
          //  // 停止扫描
          //  nrf_ble_scan_stop();
          //  // 发起连接
          //  err_code = sd_ble_gap_connect(&m_addr,&m_scan_params,&m_conn_params,APP_BLE_CONN_CFG_TAG);
          //  APP_ERROR_CHECK(err_code);
          //}

        } break;
        case NRF_BLE_SCAN_EVT_FILTER_MATCH:
        {
          // 下面这一段我们只保留了扫描回调数据获取的部分,因为从机筛选广播的UUID在扫描回调数据
          // 判断是否为扫描回调数据
          if(p_scan_evt->params.filter_match.p_adv_report->type.scan_response)
          {
            NRF_LOG_INFO("Device MAC:  %s",
                         Util_convertBdAddr2Str((uint8_t*)p_scan_evt->params.filter_match.p_adv_report->peer_addr.addr));
            
            if(p_scan_evt->params.filter_match.p_adv_report->data.len)    // 存在扫描回调数据
            {
              NRF_LOG_INFO("ScanRsp Data:%s",
                            Util_convertHex2Str(
                            p_scan_evt->params.filter_match.p_adv_report->data.p_data,
                            p_scan_evt->params.filter_match.p_adv_report->data.len));
            }
            else
            {
              NRF_LOG_INFO("ScanRsp Data:%s","NONE");
            }
            NRF_LOG_INFO("Device RSSI: %ddBm",p_scan_evt->params.filter_match.p_adv_report->rssi);
          }
          // 如果扫描到的设备信号强度大于-30dBm
          if(p_scan_evt->params.filter_match.p_adv_report->rssi > (-30))
          {
            ret_code_t          err_code;
            
            // 配置准备连接的设备MAC
            ble_gap_addr_t m_addr;
            m_addr.addr_id_peer = 1;
            m_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC;
            memcpy(m_addr.addr,p_scan_evt->params.filter_match.p_adv_report->peer_addr.addr,BLE_GAP_ADDR_LEN);
            
            // 停止扫描
            nrf_ble_scan_stop();
            // 发起连接
            err_code = sd_ble_gap_connect(&m_addr,&m_scan_params,&m_conn_params,APP_BLE_CONN_CFG_TAG);
            APP_ERROR_CHECK(err_code);
          }
//          else  // 否则为广播数据
//          {
//            // 打印扫描的设备MAC
//            NRF_LOG_INFO("Device MAC:  %s",
//                         Util_convertBdAddr2Str((uint8_t*)p_scan_evt->params.filter_match.p_adv_report->peer_addr.addr));
//            
//            if(p_scan_evt->params.filter_match.p_adv_report->data.len)    // 存在广播数据
//            {
//              NRF_LOG_INFO("adv data:  %s",
//                            Util_convertHex2Str(
//                            p_scan_evt->params.filter_match.p_adv_report->data.p_data,
//                            p_scan_evt->params.filter_match.p_adv_report->data.len));
//            }
//            else
//            {
//              NRF_LOG_INFO("adv data:  %s","NONE");
//            }
//          }
        } break;
        default:
           break;
    }
}

?

1.2从机端

从机主要就在蓝牙事件回调中添加了对连接断开事件的处理,和主机端一样:

//******************************************************************
// fn : ble_evt_handler
//
// brief : BLE事件回调
// details : 包含以下几种事件类型:COMMON、GAP、GATT Client、GATT Server、L2CAP
//
// param : ble_evt_t  事件类型
//         p_context  未使用
//
// return : none
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    ble_gap_evt_connected_t const * p_connected_evt = &p_gap_evt->params.connected;
    switch (p_ble_evt->header.evt_id)
    {
        // 连接
        case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO("Connected. conn_DevAddr: %s\nConnected. conn_handle: 0x%04x\nConnected. conn_Param: %d,%d,%d,%d",
                         Util_convertBdAddr2Str((uint8_t*)p_connected_evt->peer_addr.addr),
                         p_gap_evt->conn_handle,
                         p_connected_evt->conn_params.min_conn_interval,
                         p_connected_evt->conn_params.max_conn_interval,
                         p_connected_evt->conn_params.slave_latency,
                         p_connected_evt->conn_params.conn_sup_timeout
                         );
            break;
        // 断开连接
        case BLE_GAP_EVT_DISCONNECTED:
            NRF_LOG_INFO("Disconnected. conn_handle: 0x%x, reason: 0x%04x",
                         p_gap_evt->conn_handle,
                         p_gap_evt->params.disconnected.reason);
            break;

        default:
            // No implementation needed.
            break;
    }
}

?注意这个回调的参数:

/**@brief Common BLE Event type, wrapping the module specific event reports. */
typedef struct
{
  ble_evt_hdr_t header;           /**< Event header. */
  union
  {
    ble_common_evt_t  common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */
    ble_gap_evt_t     gap_evt;    /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */
    ble_gattc_evt_t   gattc_evt;  /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */
    ble_gatts_evt_t   gatts_evt;  /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */
    ble_l2cap_evt_t   l2cap_evt;  /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */
  } evt;                          /**< Event union. */
} ble_evt_t;

可以看到,ble事件中,有:

普通事件、gap事件、gatt客户端事件、gatt服务端事件、l2cap事件

而gap事件中包含连接和断开:

?

而每个结构体里包含该事件所能获取到的信息,就比如连接事件中:

?

?我们可以获取,对方的地址、角色(中心或外围设备)、连接参数等。

1.3实际现象

主机端打印:

?从机端打印:

2.过滤自动连接

2.1主机端

这里主要更改的是主机端,我们不再需要提供MAC地址去连接对应的设备,而是使用自动连接:

这个参数我们之前就看到过,只不过没有做讲解,也没有设置它:

?

然后我们把之前在?NRF_BLE_SCAN_EVT_FILTER_MATCH?中手动连接的代码注释掉,添加两个事件回调:

?

2.2从机端

和上文相同,略。

2.3实际现象

?

?可以看到,在扫描到符合过滤设置后,设备直接被连接上了。

3.?白名单自动连接

3.1主机端

同样的道理,我们只需要在以前白名单扫描模式的基础上,开启自动连接就可以了:

?

?

这部分代码和之前基本上一模一样,完全可以举一反三。

3.2从机

略。

3.3实验现象

?

完全与预期相符。

4.白名单手动连接

不再赘述,和前面一模一样,只是回调函数里面放个手动连接而已:

?

?

?

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-12 16:43:29  更:2022-05-12 16:44:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:51:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码