本次项目是用ESP_32S做一个低功耗蓝牙BLE的透传模块,模块将扫描到的蓝牙名称以及设备地址通过USB口(串口)传出,上位机通过串口输入要连接的蓝牙名称后,模块进行连接配对,配对成功后就将USB口收到的数据通过蓝牙发送到配对端。
硬件:ESP-32S模块,以及必要的外围电路。
软件系统:FreeRTOS,接口代码采用乐鑫提供的ESP32模块BSP包
1、串口初始化
static void Uart_init(void)
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_RTS,
.rx_flow_ctrl_thresh = 122,
};
//Set UART parameters
uart_param_config(UART_NUM_0, &uart_config);
//Set UART pins
uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
//Install UART driver, and get the queue.
uart_driver_install(UART_NUM_0, 4096, 8192, 10,&spp_uart_queue,0);
xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_0, 8, NULL);
}
2、蓝牙功能初始化
void ble_client_appRegister(void)
{
esp_err_t status;
char err_msg[20];
ESP_LOGI(GATTC_TAG, "register callback");
//register the scan callback function to the gap module
if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) {
ESP_LOGE(GATTC_TAG, "gap register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg)));
return;
}
//register the callback function to the gattc module
if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK) {
ESP_LOGE(GATTC_TAG, "gattc register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg)));
return;
}
esp_ble_gattc_app_register(PROFILE_APP_ID);
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(200); //设置MTU最大为200
if (local_mtu_ret){
ESP_LOGE(GATTC_TAG, "set local MTU failed: %s", esp_err_to_name_r(local_mtu_ret, err_msg, sizeof(err_msg)));
}
cmd_reg_queue = xQueueCreate(10, sizeof(uint32_t));
xTaskCreate(spp_client_reg_task, "spp_client_reg_task", 2048, NULL, 10, NULL);
}
void BLE_init()
{
esp_err_t ret;
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();
memcpy(g_BLE_name, "TestBluetooth", 13);
nvs_flash_init();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ESP_LOGI(GATTC_TAG, "%s init bluetooth\n", __func__);
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(GATTC_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ble_client_appRegister();
}
3、启动扫描
调用ESP接口 esp_ble_gap_start_scanning(0xff);
扫描到蓝牙设备后会触发事件 ESP_GAP_BLE_SCAN_RESULT_EVT,在事件触发时,回去扫描到的设备名称以及地址信息,通过串口将设备信息输出,
adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
if(adv_name==NULL)
adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_SHORT, &adv_name_len);
Uart_Send_ScanDevInfo(scan_result->scan_rst.bda,adv_name,adv_name_len);
4、收到上位机通过串口输入连接设备名称后,将扫描到的设备名称与目标名称进行对比,如果相符就停止扫描
if (adv_name != NULL)
{
if(g_device_nameFlag && (strncmp((char *)adv_name, g_BLE_name, adv_name_len) == 0))
{
memcpy(&(scan_rst), scan_result, sizeof(esp_ble_gap_cb_param_t));
esp_ble_gap_stop_scanning();
}
}
停止扫描后会触发 ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT事件,在事件触发时启动连接
esp_ble_gattc_open(gl_profile_tab[PROFILE_APP_ID].gattc_if, scan_rst.scan_rst.bda, scan_rst.scan_rst.ble_addr_type, true);
5、连接成功后会触发gattc_profile_event_handler()中的 ESP_GATTC_CONNECT_EVT事件。
连接事件处理:设置数据长度
is_connect = true;
gl_profile_tab[PROFILE_APP_ID].conn_id = p_data->connect.conn_id;
memcpy(gl_profile_tab[PROFILE_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
esp_log_buffer_hex(GATTC_TAG, gl_profile_tab[PROFILE_APP_ID].remote_bda, sizeof(esp_bd_addr_t));
esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req(gattc_if, spp_conn_id);
if (mtu_ret){
ESP_LOGE(GATTC_TAG, "config MTU error, error code = %x", mtu_ret);
}
6、设置成功后触发ESP_GATTC_CFG_MTU_EVT事件。在此事件中获取设备信息
if(p_data->cfg_mtu.status != ESP_OK){
break;
}
ESP_LOGI(GATTC_TAG,"+MTU:%d\n", p_data->cfg_mtu.mtu);
spp_mtu_size = p_data->cfg_mtu.mtu;
spp_conn_id = p_data->connect.conn_id;
spp_gattc_if = gattc_if;
esp_ble_gattc_search_service(spp_gattc_if, spp_conn_id, &spp_service_uuid);
7、获取成功后触发ESP_GATTC_SEARCH_RES_EVT事件,然后设置通讯需要的队列、数据通道等,就可以进行通讯了,
8、当串口收到数据后,调用
esp_ble_gattc_write_char( spp_gattc_if,spp_conn_id,
(db+SPP_IDX_SPP_DATA_RECV_VAL)->attribute_handle,
event.size,
pBuf,
ESP_GATT_WRITE_TYPE_RSP,
ESP_GATT_AUTH_REQ_NONE);
将数据传输给BLE服务端。
9、当模块收到BLE服务端的数据,会触发通知事件:ESP_GATTC_NOTIFY_EVT,在该事件出发时,调用
notify_event_handler(p_data);将数据通过串口发送出去
static void notify_event_handler(esp_ble_gattc_cb_param_t * p_data)
{
uint8_t handle = 0;
if(p_data->notify.is_notify == true){
ESP_LOGI(GATTC_TAG,"+NOTIFY:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len);
}else{
ESP_LOGI(GATTC_TAG,"+INDICATE:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len);
}
handle = p_data->notify.handle;
if(handle == db[SPP_IDX_SPP_DATA_NTY_VAL].attribute_handle){
if((p_data->notify.value[0] == '#')&&(p_data->notify.value[1] == '#')){ //配置数据
if((++notify_value_count) != p_data->notify.value[3]){
if(notify_value_p != NULL){
free(notify_value_p);
}
notify_value_count = 0;
notify_value_p = NULL;
notify_value_offset = 0;
ESP_LOGE(GATTC_TAG,"notify value count is not continuous,%s\n",__func__);
return;
}
if(p_data->notify.value[3] == 1){
notify_value_p = (char *)malloc(((spp_mtu_size-7)*(p_data->notify.value[2]))*sizeof(char));
if(notify_value_p == NULL){
ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
notify_value_count = 0;
return;
}
memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4));
if(p_data->notify.value[2] == p_data->notify.value[3]){
uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
free(notify_value_p);
notify_value_p = NULL;
notify_value_offset = 0;
return;
}
notify_value_offset += (p_data->notify.value_len - 4);
}else if(p_data->notify.value[3] <= p_data->notify.value[2]){
memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4));
if(p_data->notify.value[3] == p_data->notify.value[2]){
uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
free(notify_value_p);
notify_value_count = 0;
notify_value_p = NULL;
notify_value_offset = 0;
return;
}
notify_value_offset += (p_data->notify.value_len - 4);
}
}else{
uart_write_bytes(UART_NUM_0, (char *)(p_data->notify.value), p_data->notify.value_len);
}
}else if(handle == ((db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle)){
}else{
}
}
大体流程就是这样的,具体数据细节处理业务就不细述了。