分享

ESP

 iamlijin 2019-05-20

        本次项目是用ESP_32S做一个低功耗蓝牙BLE的透传模块,模块将扫描到的蓝牙名称以及设备地址通过USB口(串口)传出,上位机通过串口输入要连接的蓝牙名称后,模块进行连接配对,配对成功后就将USB口收到的数据通过蓝牙发送到配对端。

       硬件:ESP-32S模块,以及必要的外围电路。

      软件系统:FreeRTOS,接口代码采用乐鑫提供的ESP32模块BSP包

1、串口初始化

  1. static void Uart_init(void)
  2. {
  3. uart_config_t uart_config = {
  4. .baud_rate = 115200,
  5. .data_bits = UART_DATA_8_BITS,
  6. .parity = UART_PARITY_DISABLE,
  7. .stop_bits = UART_STOP_BITS_1,
  8. .flow_ctrl = UART_HW_FLOWCTRL_RTS,
  9. .rx_flow_ctrl_thresh = 122,
  10. };
  11. //Set UART parameters
  12. uart_param_config(UART_NUM_0, &uart_config);
  13. //Set UART pins
  14. uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
  15. //Install UART driver, and get the queue.
  16. uart_driver_install(UART_NUM_0, 4096, 8192, 10,&spp_uart_queue,0);
  17. xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_0, 8, NULL);
  18. }

2、蓝牙功能初始化

  1. void ble_client_appRegister(void)
  2. {
  3. esp_err_t status;
  4. char err_msg[20];
  5. ESP_LOGI(GATTC_TAG, "register callback");
  6. //register the scan callback function to the gap module
  7. if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) {
  8. ESP_LOGE(GATTC_TAG, "gap register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg)));
  9. return;
  10. }
  11. //register the callback function to the gattc module
  12. if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK) {
  13. ESP_LOGE(GATTC_TAG, "gattc register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg)));
  14. return;
  15. }
  16. esp_ble_gattc_app_register(PROFILE_APP_ID);
  17. esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(200); //设置MTU最大为200
  18. if (local_mtu_ret){
  19. ESP_LOGE(GATTC_TAG, "set local MTU failed: %s", esp_err_to_name_r(local_mtu_ret, err_msg, sizeof(err_msg)));
  20. }
  21. cmd_reg_queue = xQueueCreate(10, sizeof(uint32_t));
  22. xTaskCreate(spp_client_reg_task, "spp_client_reg_task", 2048, NULL, 10, NULL);
  23. }
  24. void BLE_init()
  25. {
  26. esp_err_t ret;
  27. ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
  28. esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
  29. memcpy(g_BLE_name, "TestBluetooth", 13);
  30. nvs_flash_init();
  31. ret = esp_bt_controller_init(&bt_cfg);
  32. if (ret) {
  33. ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
  34. return;
  35. }
  36. ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
  37. if (ret) {
  38. ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
  39. return;
  40. }
  41. ESP_LOGI(GATTC_TAG, "%s init bluetooth\n", __func__);
  42. ret = esp_bluedroid_init();
  43. if (ret) {
  44. ESP_LOGE(GATTC_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
  45. return;
  46. }
  47. ret = esp_bluedroid_enable();
  48. if (ret) {
  49. ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
  50. return;
  51. }
  52. ble_client_appRegister();
  53. }

3、启动扫描

 调用ESP接口 esp_ble_gap_start_scanning(0xff);

 扫描到蓝牙设备后会触发事件 ESP_GAP_BLE_SCAN_RESULT_EVT,在事件触发时,回去扫描到的设备名称以及地址信息,通过串口将设备信息输出,

  1. adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
  2. if(adv_name==NULL)
  3. adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_SHORT, &adv_name_len);
  4. Uart_Send_ScanDevInfo(scan_result->scan_rst.bda,adv_name,adv_name_len);

4、收到上位机通过串口输入连接设备名称后,将扫描到的设备名称与目标名称进行对比,如果相符就停止扫描

  1. if (adv_name != NULL)
  2. {
  3. if(g_device_nameFlag && (strncmp((char *)adv_name, g_BLE_name, adv_name_len) == 0))
  4. {
  5. memcpy(&(scan_rst), scan_result, sizeof(esp_ble_gap_cb_param_t));
  6. esp_ble_gap_stop_scanning();
  7. }
  8. }

停止扫描后会触发 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事件。

连接事件处理:设置数据长度

  1. is_connect = true;
  2. gl_profile_tab[PROFILE_APP_ID].conn_id = p_data->connect.conn_id;
  3. memcpy(gl_profile_tab[PROFILE_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
  4. esp_log_buffer_hex(GATTC_TAG, gl_profile_tab[PROFILE_APP_ID].remote_bda, sizeof(esp_bd_addr_t));
  5. esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req(gattc_if, spp_conn_id);
  6. if (mtu_ret){
  7. ESP_LOGE(GATTC_TAG, "config MTU error, error code = %x", mtu_ret);
  8. }

6、设置成功后触发ESP_GATTC_CFG_MTU_EVT事件。在此事件中获取设备信息

  1. if(p_data->cfg_mtu.status != ESP_OK){
  2. break;
  3. }
  4. ESP_LOGI(GATTC_TAG,"+MTU:%d\n", p_data->cfg_mtu.mtu);
  5. spp_mtu_size = p_data->cfg_mtu.mtu;
  6. spp_conn_id = p_data->connect.conn_id;
  7. spp_gattc_if = gattc_if;
  8. esp_ble_gattc_search_service(spp_gattc_if, spp_conn_id, &spp_service_uuid);

7、获取成功后触发ESP_GATTC_SEARCH_RES_EVT事件,然后设置通讯需要的队列、数据通道等,就可以进行通讯了,

 

8、当串口收到数据后,调用

  1. esp_ble_gattc_write_char( spp_gattc_if,spp_conn_id,
  2. (db+SPP_IDX_SPP_DATA_RECV_VAL)->attribute_handle,
  3. event.size,
  4. pBuf,
  5. ESP_GATT_WRITE_TYPE_RSP,
  6. ESP_GATT_AUTH_REQ_NONE);

将数据传输给BLE服务端。

9、当模块收到BLE服务端的数据,会触发通知事件:ESP_GATTC_NOTIFY_EVT,在该事件出发时,调用

 notify_event_handler(p_data);将数据通过串口发送出去

  1. static void notify_event_handler(esp_ble_gattc_cb_param_t * p_data)
  2. {
  3. uint8_t handle = 0;
  4. if(p_data->notify.is_notify == true){
  5. ESP_LOGI(GATTC_TAG,"+NOTIFY:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len);
  6. }else{
  7. ESP_LOGI(GATTC_TAG,"+INDICATE:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len);
  8. }
  9. handle = p_data->notify.handle;
  10. if(handle == db[SPP_IDX_SPP_DATA_NTY_VAL].attribute_handle){
  11. if((p_data->notify.value[0] == '#')&&(p_data->notify.value[1] == '#')){ //配置数据
  12. if((++notify_value_count) != p_data->notify.value[3]){
  13. if(notify_value_p != NULL){
  14. free(notify_value_p);
  15. }
  16. notify_value_count = 0;
  17. notify_value_p = NULL;
  18. notify_value_offset = 0;
  19. ESP_LOGE(GATTC_TAG,"notify value count is not continuous,%s\n",__func__);
  20. return;
  21. }
  22. if(p_data->notify.value[3] == 1){
  23. notify_value_p = (char *)malloc(((spp_mtu_size-7)*(p_data->notify.value[2]))*sizeof(char));
  24. if(notify_value_p == NULL){
  25. ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
  26. notify_value_count = 0;
  27. return;
  28. }
  29. memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4));
  30. if(p_data->notify.value[2] == p_data->notify.value[3]){
  31. uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
  32. free(notify_value_p);
  33. notify_value_p = NULL;
  34. notify_value_offset = 0;
  35. return;
  36. }
  37. notify_value_offset += (p_data->notify.value_len - 4);
  38. }else if(p_data->notify.value[3] <= p_data->notify.value[2]){
  39. memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4));
  40. if(p_data->notify.value[3] == p_data->notify.value[2]){
  41. uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
  42. free(notify_value_p);
  43. notify_value_count = 0;
  44. notify_value_p = NULL;
  45. notify_value_offset = 0;
  46. return;
  47. }
  48. notify_value_offset += (p_data->notify.value_len - 4);
  49. }
  50. }else{
  51. uart_write_bytes(UART_NUM_0, (char *)(p_data->notify.value), p_data->notify.value_len);
  52. }
  53. }else if(handle == ((db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle)){
  54. }else{
  55. }
  56. }

大体流程就是这样的,具体数据细节处理业务就不细述了。

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多