esp32-S3专题三:外设2之蓝牙使用

一、介绍

物联网设备中,蓝牙功能的经常搭配wifi使用。在设备首次使用阶段中,给无网络连接状态下的设备,传输wifi的连接信息和相关证书等。而s3模块就搭配了蓝牙模块,并且内置了蓝牙协议栈。

二、BluFi 简介

官网有详细的蓝牙协议的讲解,这里就不做铺开讲解。可以看看

https://docs.espressif.com/projects/esp-idf/zh_CN/release-v4.4/esp32s3/api-guides/blufi.html

本次教程参考例程的是 gatt_server,结合此例程做快速的配置和解析。蓝牙协议交互流程如下(图片引用esp官网)
在这图片里插入图片描述

三、例程解析

(一)蓝牙名称和UUID初始化

1.注销默认值service uuiddevice name

static uint8_t raw_adv_data[] = {
        /* flags */
        0x02, 0x01, 0x06,
        /* tx power*/
        0x02, 0x0a, 0xeb,
        /* service uuid */
//        0x03, 0x03, 0xFF, 0x00,
        /* device name */
		//0x0f, 0x09, 'E', 'S', 'P', '_', 'G', 'A', 'T', 'T', 'S', '_', 'D','E', 'M', 'O'
//		0x15, 0x09, 'X','W','_','H','_','X', '_', '2','2','0','4','2','0','_','0','0','0','0','0','2'
};
static uint8_t raw_scan_rsp_data[] = {
        /* flags */
        0x02, 0x01, 0x06,
        /* tx power */
        0x02, 0x0a, 0xeb,
        /* service uuid */
//        0x03, 0x03, 0xFF,0x00
};

1.UUID设置(例程实现)

//默认值
static esp_bt_uuid_t service_uuid_main = {
    .len = ESP_UUID_LEN_128,
    .uuid = {.uuid128 ={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0xBB, 0x23, 0xB1, 0x00, 0x63, 0x01, 0x00, 0x40, 0x6E},},
};
static esp_bt_uuid_t service_uuid_rx = {
    .len = ESP_UUID_LEN_128,
    .uuid = {.uuid128 ={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0xBB, 0x23, 0xB1, 0x00, 0x63, 0x02, 0x00, 0x40, 0x6E},},
};
static esp_bt_uuid_t service_uuid_tx = {
    .len = ESP_UUID_LEN_128,
    .uuid = {.uuid128 ={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0xBB, 0x23, 0xB1, 0x00, 0x63, 0x03, 0x00, 0x40, 0x6E},},
};

2.设置UUID的函数


void set_ble_udid(){
	uint8_t baseMac[6]={0};
	esp_read_mac(baseMac, ESP_MAC_WIFI_STA);//将wifi的mac设置给蓝牙,也可以自行构造
	for(int i=0;i<6;i++){
		service_uuid_main.uuid.uuid128[i]=mmac[i];
		service_uuid_rx.uuid.uuid128[i]=mmac[i];
		service_uuid_tx.uuid.uuid128[i]=mmac[i];
	}
}	

3.uuid和特征值生效代码(例程实现)

//
//特征值使用默认设置
static const uint16_t primary_service_uuid         = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid   = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
//static const uint8_t char_prop_read                =  ESP_GATT_CHAR_PROP_BIT_READ;
static const uint8_t char_prop_write               = ESP_GATT_CHAR_PROP_BIT_WRITE ;
//static const uint8_t char_prop_read_write_notify   = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE;
static const uint8_t char_prop_notify   = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t heart_measurement_ccc[2]      = {0x00, 0x00};
static const uint8_t char_value[4]                 = {0x11, 0x22, 0x33, 0x44};

static const esp_gatts_attr_db_t gatt_db[HRS_IDX_NB] =
{
    // Service Declaration
    [IDX_SVC]        =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
    		ESP_UUID_LEN_128, ESP_UUID_LEN_128, (uint8_t *)service_uuid_main.uuid.uuid128}},

	/* Characteristic Declaration */
	[IDX_CHAR_B]      =
	{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
	  CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},

	/* Characteristic Value */
	[IDX_CHAR_VAL_B]  =
	{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)service_uuid_rx.uuid.uuid128, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
	  GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},


    /* Characteristic Declaration */
    [IDX_CHAR_A]     =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},

    /* Characteristic Value */
    [IDX_CHAR_VAL_A] =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)&service_uuid_tx.uuid.uuid128, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},

    /* Client Characteristic Configuration Descriptor */
    [IDX_CHAR_CFG_A]  =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      sizeof(uint16_t), sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},

};

4.设置蓝牙名称后传入gatts_profile_event_handler

static char ble_name[16] = {0};
void set_ble_name(){
	char  ble_name[16] = "test_ble";
	memcpy(ble_name,ble_name,strlen(ble_name));
}	

//此次代码不全,具体参考例程
static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
    switch (event) {
        case ESP_GATTS_REG_EVT:{
			 ..........................
			esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(ble_name, strlen(ble_name)+1);
            if (raw_adv_ret){
                ESP_LOGE(GATTS_TABLE_TAG, "config raw adv data failed, error code = %x ", raw_adv_ret);
            }
            adv_config_done |= ADV_CONFIG_FLAG;

            ..........................
}

(二)蓝牙功能初始化

直接参考例程,设置相关模式,并打开蓝牙

void ble_init(){

ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));

    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    ret = esp_bt_controller_init(&bt_cfg);
    if (ret) {
        ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
    if (ret) {
        ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bluedroid_init();
    if (ret) {
        ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bluedroid_enable();
    if (ret) {
        ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_ble_gatts_register_callback(gatts_event_handler);
    if (ret){
        ESP_LOGE(GATTS_TABLE_TAG, "gatts register error, error code = %x", ret);
        return;
    }

    ret = esp_ble_gap_register_callback(gap_event_handler);
    if (ret){
        ESP_LOGE(GATTS_TABLE_TAG, "gap register error, error code = %x", ret);
        return;
    }

    ret = esp_ble_gatts_app_register(ESP_APP_ID);
    if (ret){
        ESP_LOGE(GATTS_TABLE_TAG, "gatts app register error, error code = %x", ret);
        return;
    }
    esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);
    if (local_mtu_ret){
        ESP_LOGE(GATTS_TABLE_TAG, "set local  MTU failed, error code = %x", local_mtu_ret);
    }


    /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/
    esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND;     //bonding with peer device after authentication
    esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;           //set the IO capability to No output No input
    uint8_t key_size = 16;      //the key size should be 7~16 bytes
    uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
    uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
    uint8_t oob_support = ESP_BLE_OOB_DISABLE;
    esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
    /* If your BLE device act as a Slave, the init_key means you hope which types of key of the master should distribute to you,
    and the response key means which key you can distribute to the Master;
    If your BLE device act as a master, the response key means you hope which types of key of the slave should distribute to you,
    and the init key means which key you can distribute to the slave. */
    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));

}

(三)蓝牙消息发送函数

//参数在蓝牙连接成功后,在gatts_event_handler回调函数里更新
static esp_gatt_if_t ble_gatts_if = 0;
static uint16_t ble_conn_id=0xFF;//本次代码只采用notify方式发送消息
static uint16_t ble_attr_handle;

nt ble_send_msg(char *send_buf){
	esp_ble_gatts_send_indicate(ble_gatts_if, ble_conn_id, ble_attr_handle,strlen(send_buf)+1, send_buf, false);
}

(四)蓝牙消息接收函数

static char ble_rec_buf[256] = {0};

static void ble_data_rec(uint8_t* data,int len){
	ESP_LOGI(GATTS_TABLE_TAG,"ble_data_cb %s",data);
	memcpy(ble_rec_buf,data,len);
}


static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param){
		..............................
		..............................
		..............................
        case ESP_GATTS_WRITE_EVT:
            if (!param->write.is_prep){
				..........
				if (heart_rate_handle_table[IDX_CHAR_CFG_A] == param->write.handle && param->write.len == 2){
				     uint16_t descr_value = param->write.value[1]<<8 | param->write.value[0];
                    if (descr_value == 0x0001){ // notify 建立连接,并更新连接值
                        ESP_LOGI(GATTS_TABLE_TAG, "notify enable");
                    	ble_gatts_if = gatts_if;
                    	ble_conn_id = param->write.conn_id;
                    	ble_attr_handle = heart_rate_handle_table[IDX_CHAR_VAL_A];
                    }
                    ........
                }else{
                	ble_data_rec(param->write.value,param->write.len); //接收回调
                }
                /* send response when param->write.need_rsp is true*/
                if (param->write.need_rsp){
                    esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
                }
            }
            .........................
            .........................
            .........................
}

(五)关闭蓝牙使用

void bledeInit()
{
	esp_ble_gatts_app_unregister(ESP_APP_ID);
	esp_bluedroid_disable();
	esp_bluedroid_deinit();
	esp_bt_controller_disable();
	esp_bt_controller_deinit();
}

四、总结

以上是esp32的ble简单使用,如果是传输证书等机密信息,esp32官方还提高ble信息加密传输,有兴趣可以去官方了解一下,纯项目技术分享,更新不易,如有帮助,点赞一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

水厂小白@

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

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

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

打赏作者

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

抵扣说明:

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

余额充值