翻译内容仅供参考,原文链接:

https://github.com/espressif/esp-idf/blob/dd8db6621/examples/bluetooth/bluedroid/ble/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md

#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "nvs.h"
#include "nvs_flash.h"
#include "controller.h"#include "bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gattc_api.h"
#include "esp_gatt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"

void app_main()
{// Initialize NVS.esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK( ret );esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();ret = esp_bt_controller_init(&bt_cfg);if (ret) {ESP_LOGE(GATTC_TAG, "%s initialize controller failed, error code = %x\n", __func__, ret);return;}ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);if (ret) {ESP_LOGE(GATTC_TAG, "%s enable controller failed, error code = %x\n", __func__, ret);return;}ret = esp_bluedroid_init();if (ret) {ESP_LOGE(GATTC_TAG, "%s init bluetooth failed, error code = %x\n", __func__, ret);return;}ret = esp_bluedroid_enable();if (ret) {ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed, error code = %x\n", __func__, ret);return;}//register the  callback function to the gap moduleret = esp_ble_gap_register_callback(esp_gap_cb);if (ret){ESP_LOGE(GATTC_TAG, "%s gap register failed, error code = %x\n", __func__, ret);return;}//register the callback function to the gattc moduleret = esp_ble_gattc_register_callback(esp_gattc_cb);if(ret){ESP_LOGE(GATTC_TAG, "%s gattc register failed, error code = %x\n", __func__, ret);return;}ret = esp_ble_gattc_app_register(PROFILE_A_APP_ID);if (ret){ESP_LOGE(GATTC_TAG, "%s gattc app register failed, error code = %x\n", __func__, ret);}esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);if (local_mtu_ret){ESP_LOGE(GATTC_TAG, "set local  MTU failed, error code = %x", local_mtu_ret);}}

esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );

esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);

ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);

ret = esp_bluedroid_init();
ret = esp_bluedroid_enable();

    //register the  callback function to the gap moduleret = esp_ble_gap_register_callback(esp_gap_cb);//register the callback function to the gattc moduleret = esp_ble_gattc_register_callback(esp_gattc_cb);ret = esp_ble_gattc_app_register(PROFILE_A_APP_ID);esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);if (local_mtu_ret){ESP_LOGE(GATTC_TAG, "set local  MTU failed, error code = %x", local_mtu_ret);}

esp_ble_gap_register_callback();
esp_ble_gattc_register_callback();

struct gattc_profile_inst {esp_gattc_cb_t gattc_cb;uint16_t gattc_if;uint16_t app_id;uint16_t conn_id;uint16_t service_start_handle;uint16_t service_end_handle;uint16_t char_handle;esp_bd_addr_t remote_bda;
};

#define PROFILE_NUM 1
#define PROFILE_A_APP_ID 0

/* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */
static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = {[PROFILE_A_APP_ID] = {.gattc_cb = gattc_profile_event_handler,.gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */},
};

static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
{ESP_LOGI(GATTC_TAG, "EVT %d, gattc if %d", event, gattc_if);/* If event is register event, store the gattc_if for each profile */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;}}
…

…
/* If the gattc_if equal to profile A, call profile A cb handler,* so here call each profile's callback */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);
}

/// Ble scan parameters
typedef struct {esp_ble_scan_type_t     scan_type;              /*!< Scan type */esp_ble_addr_type_t     own_addr_type;          /*!< Owner address type */esp_ble_scan_filter_t   scan_filter_policy;     /*!< Scan filter policy */uint16_t                scan_interval;          /*!< Scan interval. This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan.*/ //Range: 0x0004 to 0x4000 //Default: 0x0010 (10 ms)//Time = N * 0.625 msec//Time Range: 2.5 msec to 10.24    secondsuint16_t                scan_window;            /*!< Scan window. The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval*///Range: 0x0004 to 0x4000                                                       //Default: 0x0010 (10 ms)//Time = N * 0.625 msec//Time Range: 2.5 msec to 10240 msec
} esp_ble_scan_params_t;

static esp_ble_scan_params_t ble_scan_params = {.scan_type              = BLE_SCAN_TYPE_ACTIVE,.own_addr_type          = BLE_ADDR_TYPE_PUBLIC,.scan_filter_policy     = BLE_SCAN_FILTER_ALLOW_ALL,.scan_interval          = 0x50,.scan_window            = 0x30
};

case ESP_GATTC_REG_EVT:ESP_LOGI(GATTC_TAG, "REG_EVT");esp_err_t scan_ret = esp_ble_gap_set_scan_params(&ble_scan_params);if (scan_ret){ESP_LOGE(GATTC_TAG, "set scan params error, error code = %x", scan_ret);}break;

    case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {//the unit of the duration is seconduint32_t duration = 30;esp_ble_gap_start_scanning(duration);break;}

 /*** @brief ESP_GAP_BLE_SCAN_RESULT_EVT*/struct ble_scan_result_evt_param {esp_gap_search_evt_t search_evt;            /*!< Search event type */esp_bd_addr_t bda;                          /*!< Bluetooth device address which has been searched */esp_bt_dev_type_t dev_type;                 /*!< Device type */esp_ble_addr_type_t ble_addr_type;          /*!< Ble device address type */esp_ble_evt_type_t ble_evt_type;            /*!< Ble scan result event type */int rssi;                                   /*!< Searched device's RSSI */uint8_t  ble_adv[ESP_BLE_ADV_DATA_LEN_MAX + ESP_BLE_SCAN_RSP_DATA_LEN_MAX]; /*!< Received EIR */int flag;                                   /*!< Advertising data flag bit */int num_resps;                              /*!< Scan result number */uint8_t adv_data_len;                       /*!< Adv data length */uint8_t scan_rsp_len;                       /*!< Scan response length */} scan_rst;                                     /*!< Event parameter of ESP_GAP_BLE_SCAN_RESULT_EVT */

/// Sub Event of ESP_GAP_BLE_SCAN_RESULT_EVT
typedef enum {ESP_GAP_SEARCH_INQ_RES_EVT             = 0,      /*!< Inquiry result for a peer device. */ESP_GAP_SEARCH_INQ_CMPL_EVT            = 1,      /*!< Inquiry complete. */ESP_GAP_SEARCH_DISC_RES_EVT            = 2,      /*!< Discovery result for a peer device. */ESP_GAP_SEARCH_DISC_BLE_RES_EVT        = 3,      /*!< Discovery result for BLE GATT based service on a peer device. */ESP_GAP_SEARCH_DISC_CMPL_EVT           = 4,      /*!< Discovery complete. */ESP_GAP_SEARCH_DI_DISC_CMPL_EVT        = 5,      /*!< Discovery complete. */ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT  = 6,      /*!< Search cancelled */
} esp_gap_search_evt_t;

      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 (adv_name != NULL) {if (strlen(remote_device_name) == adv_name_len && strncmp((char *)adv_name, remote_device_name, adv_name_len) == 0) {ESP_LOGI(GATTC_TAG, "searched device %s\n", remote_device_name);if (connect == false) {connect = true;ESP_LOGI(GATTC_TAG, "connect to the remote device.");esp_ble_gap_stop_scanning();esp_ble_gattc_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, scan_result->scan_rst.bda, scan_result->scan_rst.ble_addr_type, true);}}}break;

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);

     case ESP_GATTC_CONNECT_EVT://p_data->connect.status always be ESP_GATT_OKESP_LOGI(GATTC_TAG, "ESP_GATTC_CONNECT_EVT conn_id %d, if %d, status %d", conn_id, gattc_if, p_data->connect.status);conn_id = p_data->connect.conn_id;gl_profile_tab[PROFILE_A_APP_ID].conn_id = p_data->connect.conn_id;memcpy(gl_profile_tab[PROFILE_A_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));ESP_LOGI(GATTC_TAG, "REMOTE BDA:");esp_log_buffer_hex(GATTC_TAG, gl_profile_tab[PROFILE_A_APP_ID].remote_bda, sizeof(esp_bd_addr_t));esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req (gattc_if, conn_id);if (mtu_ret){ESP_LOGE(GATTC_TAG, "config MTU error, error code = %x", mtu_ret);}break;

conn_id = p_data->connect.conn_id;
gl_profile_tab[PROFILE_A_APP_ID].conn_id = p_data->connect.conn_id;
memcpy(gl_profile_tab[PROFILE_A_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
ESP_LOGI(GATTC_TAG, "REMOTE BDA:");
esp_log_buffer_hex(GATTC_TAG, gl_profile_tab[PROFILE_A_APP_ID].remote_bda, sizeof(esp_bd_addr_t));

esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req (gattc_if, conn_id);
if (mtu_ret){ESP_LOGE(GATTC_TAG, "config MTU error, error code = %x", mtu_ret);
}
break;

case ESP_GATTC_OPEN_EVT:if (param->open.status != ESP_GATT_OK){ESP_LOGE(GATTC_TAG, "open failed, status %d", p_data->open.status);break;}
ESP_LOGI(GATTC_TAG, "open success");

case ESP_GATTC_CFG_MTU_EVT:if (param->cfg_mtu.status != ESP_GATT_OK){ESP_LOGE(GATTC_TAG,"config mtu failed, error status = %x", param->cfg_mtu.status);}ESP_LOGI(GATTC_TAG, "ESP_GATTC_CFG_MTU_EVT, Status %d, MTU %d, conn_id %d", param->cfg_mtu.status, param->cfg_mtu.mtu, param->cfg_mtu.conn_id);
…

static esp_bt_uuid_t remote_filter_service_uuid = {.len = ESP_UUID_LEN_16,.uuid = {.uuid16 = REMOTE_SERVICE_UUID,},
};

#define REMOTE_SERVICE_UUID        0x00FF

esp_ble_gattc_search_service(gattc_if, param->cfg_mtu.conn_id, &remote_filter_service_uuid);break;

 case ESP_GATTC_SEARCH_RES_EVT: {esp_gatt_srvc_id_t *srvc_id = &p_data->search_res.srvc_id;conn_id = p_data->search_res.conn_id;if (srvc_id->id.uuid.len == ESP_UUID_LEN_16 && srvc_id->id.uuid.uuid.uuid16 ==
REMOTE_SERVICE_UUID) {get_server = true;gl_profile_tab[PROFILE_A_APP_ID].service_start_handle = p_data->search_res.start_handle;gl_profile_tab[PROFILE_A_APP_ID].service_end_handle = p_data->search_res.end_handle;ESP_LOGI(GATTC_TAG, "UUID16: %x", srvc_id->id.uuid.uuid.uuid16);}break;

#define REMOTE_NOTIFY_CHAR_UUID    0xFF01

/*** @brief Gatt id, include uuid and instance id*/
typedef struct {esp_bt_uuid_t   uuid;                   /*!< UUID */uint8_t         inst_id;                /*!< Instance id */
} __attribute__((packed)) esp_gatt_id_t;

static esp_gatt_srvc_id_t remote_service_id = {.id = {.uuid = {.len = ESP_UUID_LEN_16,.uuid = {.uuid16 = REMOTE_SERVICE_UUID,},},.inst_id = 0,},.is_primary = true,
};

case ESP_GATTC_SEARCH_CMPL_EVT:if (p_data->search_cmpl.status != ESP_GATT_OK){ESP_LOGE(GATTC_TAG, "search service failed, error status = %x", p_data->search_cmpl.status);break;}conn_id = p_data->search_cmpl.conn_id;if (get_server){uint16_t count = 0;esp_gatt_status_t status = esp_ble_gattc_get_attr_count( gattc_if,p_data->search_cmpl.conn_id,ESP_GATT_DB_CHARACTERISTIC,                                                                                                                                           gl_profile_tab[PROFILE_A_APP_ID].service_start_handle,                                                                                              gl_profile_tab[PROFILE_A_APP_ID].service_end_handle,        INVALID_HANDLE,                           &count);if (status != ESP_GATT_OK){ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_attr_count error");}if (count > 0){char_elem_result = (esp_gattc_char_elem_t*)malloc(sizeof(esp_gattc_char_elem_t) * count);if (!char_elem_result){ESP_LOGE(GATTC_TAG, "gattc no mem");}else{status = esp_ble_gattc_get_char_by_uuid( gattc_if,p_data->search_cmpl.conn_id,                                                                      gl_profile_tab[PROFILE_A_APP_ID].service_start_handle,                                                            gl_profile_tab[PROFILE_A_APP_ID].service_end_handle,remote_filter_char_uuid,char_elem_result,&count);if (status != ESP_GATT_OK){ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_char_by_uuid error");}/*  Every service have only one char in our 'ESP_GATTS_DEMO' demo,     so we used first 'char_elem_result' */if (count > 0 && (char_elem_result[0].properties                       &ESP_GATT_CHAR_PROP_BIT_NOTIFY)){gl_profile_tab[PROFILE_A_APP_ID].char_handle =  char_elem_result[0].char_handle;esp_ble_gattc_register_for_notify (gattc_if,   gl_profile_tab[PROFILE_A_APP_ID].remote_bda, char_elem_result[0].char_handle);}}/* free char_elem_result */free(char_elem_result);}else{ESP_LOGE(GATTC_TAG, "no char found");}        }break;

…
/*  Every service have only one char in our 'ESP_GATTS_DEMO' demo, so we used first 'char_elem_result' */if(count > 0 && (char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY)){gl_profile_tab[PROFILE_A_APP_ID].char_handle = char_elem_result[0].char_handle;esp_ble_gattc_register_for_notify (gattc_if, gl_profile_tab[PROFILE_A_APP_ID].remote_bda,char_elem_result[0].char_handle);}
…

    case ESP_GATTC_REG_FOR_NOTIFY_EVT: {ESP_LOGI(GATTC_TAG, "ESP_GATTC_REG_FOR_NOTIFY_EVT");if (p_data->reg_for_notify.status != ESP_GATT_OK){ESP_LOGE(GATTC_TAG, "REG FOR NOTIFY failed: error status = %d", p_data->reg_for_notify.status);}else{uint16_t count = 0;uint16_t notify_en = 1;esp_gatt_status_t ret_status = esp_ble_gattc_get_attr_count( gattc_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id,ESP_GATT_DB_DESCRIPTOR,gl_profile_tab[PROFILE_A_APP_ID].service_start_handle,gl_profile_tab[PROFILE_A_APP_ID].service_end_handle,gl_profile_tab[PROFILE_A_APP_ID].char_handle, &count);if (ret_status != ESP_GATT_OK){ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_attr_count error");}if (count > 0){descr_elem_result = malloc(sizeof(esp_gattc_descr_elem_t) * count);if (!descr_elem_result){ESP_LOGE(GATTC_TAG, "malloc error, gattc no mem");}else{ret_status = esp_ble_gattc_get_descr_by_char_handle( gattc_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id, p_data->reg_for_notify.handle, notify_descr_uuid, descr_elem_result,&count);if (ret_status != ESP_GATT_OK){ESP_LOGE(GATTC_TAG, "esp_ble_gattc_get_descr_by_char_handle   error");}/* Every char has only one descriptor in our 'ESP_GATTS_DEMO' demo, so we used first 'descr_elem_result' */if (count > 0 && descr_elem_result[0].uuid.len == ESP_UUID_LEN_16 && descr_elem_result[0].uuid.uuid.uuid16 == ESP_GATT_UUID_CHAR_CLIENT_CONFIG){ret_status = esp_ble_gattc_write_char_descr( gattc_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id,descr_elem_result[0].handle,sizeof(notify_en),(Uint8 *)&notify_en,ESP_GATT_WRITE_TYPE_RSP,ESP_GATT_AUTH_REQ_NONE);}if (ret_status != ESP_GATT_OK){ESP_LOGE(GATTC_TAG, "esp_ble_gattc_write_char_descr error");}/* free descr_elem_result */free(descr_elem_result);}}else{ESP_LOGE(GATTC_TAG, "decsr not found");}}break;}

static esp_gatt_id_t notify_descr_id = {.uuid = {.len = ESP_UUID_LEN_16,.uuid = {.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG,},},.inst_id = 0,
};

#define ESP_GATT_UUID_CHAR_CLIENT_CONFIG            0x2902          /*  Client Characteristic Configuration */

ESP32蓝牙的Gatt Client的例子演练相关推荐

  1. 【ESP32蓝牙通信】gatt_client 和 gatt_server 调试

    ESP32蓝牙通信 蓝牙协议基本概念 ESP32 蓝牙客户端和服务端 ESP32 作为服务器调试 ESP32 作为客户端调试 项目中需要用到ESP32的蓝牙通信,查资料知道.当esp32作为客户端 c ...

  2. ESP32:蓝牙BLE控制M3508电机

    ESP32:蓝牙BLE控制M3508电机 先给各位朋友拜个年,祝大家新春快乐,事事顺利,身体健康啊! 还是熟悉的3508,内容概述: ESP32主控 蓝牙BLE通信 使用实时系统(FreeRTOS) ...

  3. esp32系列(5):esp32 蓝牙架构学习

    目录 1 ESP32 蓝牙架构学习 1.1 蓝牙 1.1.1 HCI 接口选择 1.1.2 蓝牙运行环境 1.1.3 框架 1.1.3.1 控制器 1.1.3.2 BLUEDROID 1.2 经典蓝牙 ...

  4. esp32与android蓝牙,ESP32蓝牙架构(官方)_esp32蓝牙,esp32如何连接手机蓝牙

    ESP32 蓝牙开发资料,用于了解ESP32内部的蓝牙实现. 本⼿册为 ESP32 的蓝⽛架构简介,主要分三个章节介绍了蓝⽛.经典蓝⽛和蓝⽛低功耗 ⽅⾯的整体架构.注意,本⼿册仅针对 ESP-IDF ...

  5. esp32系列(6):esp32 蓝牙HID设备demo学习

    目录 1 USB 相关知识 2 HID 基础知识 2.1 HID 描述符的概念 2.2 功能特性 2.2.1 HID Class 2.2.2 Subclass 2.2.3 Protocols 2.2. ...

  6. APP Invertor 制作BLE蓝牙APP 控制esp32蓝牙小车

    APP Invertor蓝牙小车制作 1.插件下载 1.1.导入插件 2.APP界面展示 2.1 .可视化编程 3.esp32 蓝牙代码 4.实测效果 4.1 APP控制端 4.2 蓝牙接收端   经 ...

  7. esp32 camera_利用Phyphox和ESP32蓝牙制作欧姆表测电阻

    近日,微主在利用Phyphox和ESP32蓝牙研究热敏电阻的阻值与温度的关系时,需要绘制热敏电阻阻值与时间的关系图像,通过用手捏住或者放开热敏电阻,观察电阻与时间关系图像的变化情况,进而了解温度对热敏 ...

  8. Java实现的简单的WebService服务发布和Client调用例子

    做大作业,要求用到WS,在网上看了看,自己写了一个,很简单的服务发布和Client调用例子. WebService有很多实现的方式,但是原理基本都是一样的,都是基于SOA的三角模型,所以重点在于理解了 ...

  9. 关于esp32蓝牙模块的使用——esp32学习笔记

    关于esp32蓝牙模块的使用--esp32学习笔记 关于esp32蓝牙模块的使用--esp32学习笔记 关于esp32蓝牙模块的使用--esp32学习笔记 零.前言 一.经典蓝牙BT 二.低功耗蓝牙B ...

最新文章

  1. 一点历史--Python
  2. (005)RN开发 js jsx ts tsx的区别
  3. 余额宝 vs. P2P网贷,谁更有生命力?
  4. 【跃迁之路】【451天】程序员高效学习方法论探索系列(实验阶段208-2018.05.02)...
  5. Vh和Vw的简介和使用
  6. AliOS Things图形界面开发指南
  7. vue 生成发布包_Vue 3.0 终于正正正正正式发布了!
  8. java基础大概_Java基础知识(一)
  9. VB 按指定编码格式写入文本文件
  10. 原来竟然还有这种局部变量!
  11. Hive压缩存储性能测试
  12. react替换元素节点_React万字长文面试题梳理
  13. 排序算法专题-基数排序
  14. hdu 1712 ACboy needs your help (DP)
  15. Mysql第一天笔记02——安装Navicat
  16. Google Play要求app从2019年8月1日起支持64位CPU
  17. 跟开涛学SpringMVC
  18. Web前端和后端之区分
  19. WordPress主题分享:Flatsome主题v3.15.7免费下载 2022年最新版
  20. 【最新】Firefox Manifest V3:进展及下一步计划

热门文章

  1. Sender的意义及使用举例
  2. 华创资本“细+慢活儿”的企业服务SaaS
  3. 邻居交换——冒泡排序
  4. 基于51单片机的教室车辆计数器报警proteus仿真原理图PCB
  5. linux 用记事本打开文件,Ubuntu 10.04下Gedit打开Windows记事本.txt文件乱码解决
  6. mysql查询 31到40_sql语句,取出表A中的第31条到40条记录
  7. 31条指令单周期cpu设计(Verilog)-(十)上代码→顶层模块设计总结
  8. 接口神器:Apifox,究竟有多香!
  9. 街拍视频和街拍第一站的爬虫
  10. 中国商业印刷行业市场深度调研及投资价值评估研究报告