数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 80|回复: 2

[Arduino] esp32c2(也即esp8684)大夏龙雀DX-WF25吃灰板子做蓝牙手柄

[复制链接]
发表于 昨天 13:51 | 显示全部楼层 |阅读模式
本帖最后由 hackhack 于 2026-6-29 17:41 编辑

完整的12按键游戏手柄好了。有两个版本,看你们需要哪个。

main.c内容如下
  1. #include <stdio.h>
  2. #include <string.h>
  3. // #include "esp_log.h"
  4. #include <stdbool.h>
  5. #include "nvs_flash.h"
  6. #include "freertos/FreeRTOS.h"
  7. #include "freertos/task.h"
  8. #include "driver/gpio.h"
  9. /* NimBLE 核心头文件 */
  10. #include "nimble/nimble_port.h"
  11. #include "nimble/nimble_port_freertos.h"
  12. #include "host/ble_hs.h"
  13. #include "host/util/util.h"
  14. #include "services/gap/ble_svc_gap.h"
  15. #include "services/gatt/ble_svc_gatt.h"
  16. #include "store/config/ble_store_config.h"

  17. #define TAG "BLE_GAMEPAD"

  18. /* --- 13个 GPIO 引脚分配 --- */
  19. // 方向键 (帽子开关)
  20. #define GPIO_DPAD_UP      GPIO_NUM_0
  21. #define GPIO_DPAD_DOWN    GPIO_NUM_1
  22. #define GPIO_DPAD_LEFT    GPIO_NUM_2
  23. #define GPIO_DPAD_RIGHT   GPIO_NUM_4
  24. // 功能键 (HID 按钮 1-4)
  25. #define GPIO_BTN_A        GPIO_NUM_5
  26. #define GPIO_BTN_B        GPIO_NUM_6
  27. #define GPIO_BTN_X        GPIO_NUM_18
  28. #define GPIO_BTN_Y        GPIO_NUM_7
  29. // 肩键 (HID 按钮 5-6)
  30. #define GPIO_BTN_L        GPIO_NUM_19
  31. #define GPIO_BTN_R        GPIO_NUM_20
  32. // 菜单键 (HID 按钮 7-8)
  33. #define GPIO_BTN_MINUS    GPIO_NUM_10
  34. #define GPIO_BTN_PLUS     GPIO_NUM_3
  35. // LED 指示灯
  36. #define GPIO_LED_STATUS   GPIO_NUM_8

  37. /* 全局连接句柄 */
  38. static uint16_t current_conn_handle = BLE_HS_CONN_HANDLE_NONE;
  39. /* GATT 特征值句柄(用于发送通知) */
  40. static uint16_t hid_input_report_handle;

  41. static uint8_t protocol_mode = 0x01; // 0x01 = Report Mode

  42. /* * 1. 标准 HID 游戏手柄报告描述符
  43. * 报告结构:
  44. * Byte 0: 8个常规按钮 (A, B, X, Y, L, R, -, +)
  45. * Byte 1: 低4位为帽子开关 (0-7表示方向,0x0F释放), 高4位填零对齐
  46. * Byte 2: X 轴模拟量固定置中 (0)
  47. * Byte 3: Y 轴模拟量固定置中 (0)
  48. */
  49. static const uint8_t hid_report_map[] = {
  50.     0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
  51.     0x09, 0x05,        // Usage (Game Pad)
  52.     0xa1, 0x01,        // Collection (Application)
  53.     0x85, 0x01,        //   Report ID (1)
  54.    
  55.     // 8个标准功能按键 (Bit 0~7)
  56.     0x05, 0x09,        //   Usage Page (Button)
  57.     0x19, 0x01,        //   Usage Minimum (0x01)
  58.     0x29, 0x08,        //   Usage Maximum (0x08)
  59.     0x15, 0x00,        //   Logical Minimum (0)
  60.     0x25, 0x01,        //   Logical Maximum (1)
  61.     0x75, 0x01,        //   Report Size (1)
  62.     0x95, 0x08,        //   Report Count (8)
  63.     0x81, 0x02,        //   Input (Data,Var,Abs)
  64.    
  65.     // 帽子开关 (D-Pad 方向键)
  66.     0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
  67.     0x09, 0x39,        //   Usage (Hat switch)
  68.     0x15, 0x00,        //   Logical Minimum (0) - 对应正上(Up)
  69.     0x25, 0x07,        //   Logical Maximum (7) - 对应左上(Up-Left)
  70.     0x35, 0x00,        //   Physical Minimum (0)
  71.     0x46, 0x3B, 0x01,  //   Physical Maximum (315)
  72.     0x65, 0x14,        //   Unit (System: English Rotary, Direction: Angular Position)
  73.     0x75, 0x04,        //   Report Size (4 bits)
  74.     0x95, 0x01,        //   Report Count (1)
  75.     0x81, 0x42,        //   Input (Data,Var,Abs,Null State) - 0x0F 代表无触发
  76.    
  77.     // 4位常数填充(对齐到字节边界)
  78.     0x75, 0x04,        //   Report Size (4)
  79.     0x95, 0x01,        //   Report Count (1)
  80.     0x81, 0x03,        //   Input (Const,Var,Abs)
  81.    
  82.     // 虚拟 X/Y 轴(固定为0维持系统兼容)
  83.     0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
  84.     0x09, 0x30,        //   Usage (X)
  85.     0x09, 0x31,        //   Usage (Y)
  86.     0x15, 0x81,        //   Logical Minimum (-127)
  87.     0x25, 0x7f,        //   Logical Maximum (127)
  88.     0x75, 0x08,        //   Report Size (8)
  89.     0x95, 0x02,        //   Report Count (2)
  90.     0x81, 0x02,        //   Input (Data,Var,Abs)
  91.    
  92.     0xc0               // End Collection
  93. };

  94. /* HID 基础信息 */
  95. static const uint8_t hid_info[4] = {
  96.     0x11, 0x01, // bcdHID (v1.11)
  97.     0x00,       // bCountryCode
  98.     0x03        // Flags: RemoteWake | NormallyConnectable
  99. };

  100. /* 报告引用描述符 (指向 Report ID 1, Type: Input) */
  101. static const uint8_t hid_report_reference[2] = {0x01, 0x01};

  102. /* PnP ID 信息 (伪装成 Xbox 360 控制器架构,提高 Windows 识别率) */
  103. static const uint8_t pnp_id[7] = {
  104.     0x02,       // Source: USB IF
  105.     0x5e, 0x04, // VID: 0x045E (Microsoft)
  106.     0x8e, 0x02, // PID: 0x028E (Xbox 360 Controller)
  107.     0x00, 0x01  // Version: 1.0.0
  108. };

  109. /* GATT 回调声明 */
  110. static int gatt_svr_chr_access_dis(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
  111. static int gatt_svr_chr_access_hid(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
  112. static int ble_app_gap_event(struct ble_gap_event *event, void *arg);
  113. static void ble_app_advertise(uint8_t addr_type);

  114. /* GATT 服务及特征值定义 */
  115. static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
  116.     {
  117.         /* 设备信息服务 (DIS) */
  118.         .type = BLE_GATT_SVC_TYPE_PRIMARY,
  119.         .uuid = BLE_UUID16_DECLARE(0x180A),
  120.         .characteristics = (struct ble_gatt_chr_def[]) { {
  121.             .uuid = BLE_UUID16_DECLARE(0x2A50), // PnP ID
  122.             .access_cb = gatt_svr_chr_access_dis,
  123.             .flags = BLE_GATT_CHR_F_READ,
  124.         }, {
  125.             0,
  126.         } }
  127.     },
  128.     {
  129.         /* 人机接口设备服务 (HID) */
  130.         .type = BLE_GATT_SVC_TYPE_PRIMARY,
  131.         .uuid = BLE_UUID16_DECLARE(0x1812),
  132.         .characteristics = (struct ble_gatt_chr_def[]) { {
  133.             .uuid = BLE_UUID16_DECLARE(0x2A4A), // HID Information
  134.             .access_cb = gatt_svr_chr_access_hid,
  135.             .flags = BLE_GATT_CHR_F_READ,
  136.         }, {
  137.             .uuid = BLE_UUID16_DECLARE(0x2A4B), // Report Map
  138.             .access_cb = gatt_svr_chr_access_hid,
  139.             .flags = BLE_GATT_CHR_F_READ,
  140.         }, {
  141.             .uuid = BLE_UUID16_DECLARE(0x2A4C), // HID Control Point
  142.             .access_cb = gatt_svr_chr_access_hid,
  143.             .flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
  144.         }, {
  145.             .uuid = BLE_UUID16_DECLARE(0x2A4D), // Report (Input)
  146.             .access_cb = gatt_svr_chr_access_hid,
  147.             .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
  148.             .val_handle = &hid_input_report_handle,
  149.             .descriptors = (struct ble_gatt_dsc_def[]) { {
  150.                 .uuid = BLE_UUID16_DECLARE(0x2908), // Report Reference
  151.                 .access_cb = gatt_svr_chr_access_hid,
  152.                 .att_flags = BLE_ATT_F_READ,
  153.             }, {
  154.                 0,
  155.             } }
  156.         }, {
  157.             .uuid = BLE_UUID16_DECLARE(0x2A4E), // Protocol Mode
  158.             .access_cb = gatt_svr_chr_access_hid,
  159.             .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP,
  160.         }, {
  161.             0,
  162.         } }
  163.     },
  164.     { 0 }
  165. };

  166. static int gatt_svr_chr_access_dis(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
  167.     if (ble_uuid_u16(ctxt->chr->uuid) == 0x2A50) {
  168.         return os_mbuf_append(ctxt->om, pnp_id, sizeof(pnp_id)) == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
  169.     }
  170.     return BLE_ATT_ERR_UNLIKELY;
  171. }

  172. static int gatt_svr_chr_access_hid(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
  173.     uint16_t uuid = ble_uuid_u16(ctxt->chr->uuid);
  174.     if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR || ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) {
  175.         if (uuid == 0x2A4A) return os_mbuf_append(ctxt->om, hid_info, sizeof(hid_info)) == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
  176.         if (uuid == 0x2A4B) return os_mbuf_append(ctxt->om, hid_report_map, sizeof(hid_report_map)) == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
  177.         if (uuid == 0x2908) return os_mbuf_append(ctxt->om, hid_report_reference, sizeof(hid_report_reference)) == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
  178.         if (uuid == 0x2A4E) return os_mbuf_append(ctxt->om, &protocol_mode, sizeof(protocol_mode)) == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
  179.         if (uuid == 0x2A4D) {
  180.             uint8_t empty_report[4] = {0, 0x0F, 0, 0}; // 帽子开关默认释放值为0x0F
  181.             return os_mbuf_append(ctxt->om, empty_report, sizeof(empty_report)) == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
  182.         }
  183.     } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
  184.         if (uuid == 0x2A4C) return 0;
  185.         if (uuid == 0x2A4E && ctxt->om->om_len == 1) {
  186.             protocol_mode = ctxt->om->om_data[0];
  187.             return 0;
  188.         }
  189.     }
  190.     return BLE_ATT_ERR_UNLIKELY;
  191. }

  192. /* 蓝牙 GAP 状态机广播控制 */
  193. static void ble_app_advertise(uint8_t addr_type) {
  194.     struct ble_gap_adv_params adv_params;
  195.     struct ble_hs_adv_fields fields;
  196.     int rc;

  197.     memset(&fields, 0, sizeof(fields));
  198.     fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
  199.    
  200.     fields.appearance = 0x03C4; // Gamepad 外观代码
  201.     fields.appearance_is_present = 1;

  202.     const char *name = "ESP8684-Gamepad";
  203.     fields.name = (uint8_t *)name;
  204.     fields.name_len = strlen(name);
  205.     fields.name_is_complete = 1;

  206.     ble_uuid16_t hid_uuid = BLE_UUID16_INIT(0x1812);
  207.     fields.uuids16 = &hid_uuid;
  208.     fields.num_uuids16 = 1;
  209.     fields.uuids16_is_complete = 1;

  210.     rc = ble_gap_adv_set_fields(&fields);
  211.     if (rc != 0) {
  212.         //ESP_LOGE(TAG, "设置广播数据失败: %d", rc);
  213.         return;
  214.     }

  215.     memset(&adv_params, 0, sizeof(adv_params));
  216.     adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
  217.     adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;

  218.     rc = ble_gap_adv_start(addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_app_gap_event, NULL);
  219.     //if (rc != 0) {
  220.     //    ESP_LOGE(TAG, "开启广播失败: %d", rc);
  221.     //} else {
  222.     //    ESP_LOGI(TAG, "手柄蓝牙广播已开启...");
  223.     //}
  224. }

  225. static int ble_app_gap_event(struct ble_gap_event *event, void *arg) {
  226.     struct ble_gap_conn_desc desc;
  227.     switch (event->type) {
  228.         case BLE_GAP_EVENT_CONNECT:
  229.             //ESP_LOGI(TAG, "设备已连接, 状态=%d", event->connect.status);
  230.             if (event->connect.status == 0) {
  231.                 current_conn_handle = event->connect.conn_handle;
  232.                 ble_gap_security_initiate(current_conn_handle);
  233.             } else {
  234.                 uint8_t addr_type;
  235.                 ble_hs_id_infer_auto(0, &addr_type);
  236.                 ble_app_advertise(addr_type);
  237.             }
  238.             return 0;

  239.         case BLE_GAP_EVENT_DISCONNECT:
  240.             //ESP_LOGI(TAG, "断开连接,原因=%d", event->disconnect.reason);
  241.             current_conn_handle = BLE_HS_CONN_HANDLE_NONE;
  242.             uint8_t addr_type;
  243.             ble_hs_id_infer_auto(0, &addr_type);
  244.             ble_app_advertise(addr_type);
  245.             return 0;

  246.         case BLE_GAP_EVENT_REPEAT_PAIRING:
  247.             if (ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc) == 0) {
  248.                 ble_store_util_delete_peer(&desc.peer_id_addr);
  249.             }
  250.             return BLE_GAP_REPEAT_PAIRING_RETRY;

  251.         case BLE_GAP_EVENT_ENC_CHANGE:
  252.             //ESP_LOGI(TAG, "加密状态改变: %d", event->enc_change.status);
  253.             return 0;
  254.     }
  255.     return 0;
  256. }

  257. static void ble_app_on_sync(void) {
  258.     uint8_t addr_type;
  259.     ble_hs_id_infer_auto(0, &addr_type);
  260.     ble_app_advertise(addr_type);
  261. }

  262. /* 4. 手柄 HID 完整 4 字节报告发送函数 */
  263. void send_gamepad_report(uint8_t buttons, uint8_t hat) {
  264.     if (current_conn_handle == BLE_HS_CONN_HANDLE_NONE) {
  265.         return;
  266.     }

  267.     // 结构:[按键字节, 帽子开关字节, X轴字节(0), Y轴字节(0)]
  268.     uint8_t report_data[4] = { buttons, hat, 0x00, 0x00 };
  269.     struct os_mbuf *om = ble_hs_mbuf_from_flat(report_data, sizeof(report_data));
  270.    
  271.     if (om != NULL) {
  272.         int rc = ble_gattc_notify_custom(current_conn_handle, hid_input_report_handle, om);
  273.         if (rc != 0) {
  274.             //ESP_LOGE(TAG, "HID 报告发送失败, 错误码=%d", rc);
  275.         }
  276.     }
  277. }

  278. /* 5. 12个按键扫描及 LED 控制任务 */
  279. void button_scan_task(void *pvParameters) {
  280.     // 汇聚并配置全量 12 个输入引脚掩码
  281.     uint64_t pin_mask = (1ULL << GPIO_DPAD_UP)   | (1ULL << GPIO_DPAD_DOWN) |
  282.                         (1ULL << GPIO_DPAD_LEFT) | (1ULL << GPIO_DPAD_RIGHT) |
  283.                         (1ULL << GPIO_BTN_A)     | (1ULL << GPIO_BTN_B) |
  284.                         (1ULL << GPIO_BTN_X)     | (1ULL << GPIO_BTN_Y) |
  285.                         (1ULL << GPIO_BTN_L)     | (1ULL << GPIO_BTN_R) |
  286.                         (1ULL << GPIO_BTN_MINUS) | (1ULL << GPIO_BTN_PLUS);

  287.     gpio_config_t io_conf = {
  288.         .pin_bit_mask = pin_mask,
  289.         .mode = GPIO_MODE_INPUT,
  290.         .pull_up_en = GPIO_PULLUP_ENABLE,
  291.         .pull_down_en = GPIO_PULLDOWN_DISABLE,
  292.         .intr_type = GPIO_INTR_DISABLE
  293.     };
  294.     gpio_config(&io_conf);

  295.     // 配置 LED 状态灯引脚
  296.     gpio_config_t led_conf = {
  297.         .pin_bit_mask = (1ULL << GPIO_LED_STATUS),
  298.         .mode = GPIO_MODE_OUTPUT,
  299.         .pull_up_en = GPIO_PULLUP_DISABLE,
  300.         .pull_down_en = GPIO_PULLDOWN_DISABLE,
  301.         .intr_type = GPIO_INTR_DISABLE
  302.     };
  303.     gpio_config(&led_conf);
  304.     gpio_set_level(GPIO_LED_STATUS, 0); // 默认初始熄灭

  305.     uint8_t last_buttons = 0;
  306.     uint8_t last_hat = 0x0F;

  307.     while (1) {
  308.         // 读取原始低电平状态 (0 为按下,取反转为 true 为按下)
  309.         bool up    = !gpio_get_level(GPIO_DPAD_UP);
  310.         bool down  = !gpio_get_level(GPIO_DPAD_DOWN);
  311.         bool left  = !gpio_get_level(GPIO_DPAD_LEFT);
  312.         bool right = !gpio_get_level(GPIO_DPAD_RIGHT);

  313.         bool btn_a = !gpio_get_level(GPIO_BTN_A);
  314.         bool btn_b = !gpio_get_level(GPIO_BTN_B);
  315.         bool btn_x = !gpio_get_level(GPIO_BTN_X);
  316.         bool btn_y = !gpio_get_level(GPIO_BTN_Y);

  317.         bool btn_l = !gpio_get_level(GPIO_BTN_L);
  318.         bool btn_r = !gpio_get_level(GPIO_BTN_R);

  319.         bool minus = !gpio_get_level(GPIO_BTN_MINUS);
  320.         bool plus  = !gpio_get_level(GPIO_BTN_PLUS);

  321.         // LED 触发判断:12个按键有任意一个按下就拉高,无按键拉低
  322.         bool any_pressed = up || down || left || right || btn_a || btn_b ||
  323.                            btn_x || btn_y || btn_l || btn_r || minus || plus;
  324.         gpio_set_level(GPIO_LED_STATUS, any_pressed ? 1 : 0);

  325.         /* * 帽子开关(8方向 D-Pad)解算逻辑:
  326.          * 0=正上, 1=右上, 2=正右, 3=右下, 4=正下, 5=左下, 6=正左, 7=左上, 0x0F=释放
  327.          */
  328.         uint8_t current_hat = 0x0F;
  329.         if (up && !down && !left && !right)        current_hat = 0; // 上
  330.         else if (up && !down && !left && right)    current_hat = 1; // 右上
  331.         else if (!up && !down && !left && right)   current_hat = 2; // 右
  332.         else if (!up && down && !left && right)    current_hat = 3; // 右下
  333.         else if (!up && down && !left && !right)   current_hat = 4; // 下
  334.         else if (!up && down && left && !right)    current_hat = 5; // 左下
  335.         else if (!up && !down && left && !right)   current_hat = 6; // 左
  336.         else if (up && !down && left && !right)    current_hat = 7; // 左上

  337.         // 组装常规按键数据(字节0)
  338.         uint8_t current_buttons = 0;
  339.         if (btn_a) current_buttons |= (1 << 0); // 1号键 - A
  340.         if (btn_b) current_buttons |= (1 << 1); // 2号键 - B
  341.         if (btn_x) current_buttons |= (1 << 2); // 3号键 - X
  342.         if (btn_y) current_buttons |= (1 << 3); // 4号键 - Y
  343.         if (btn_l) current_buttons |= (1 << 4); // 5号键 - L肩键
  344.         if (btn_r) current_buttons |= (1 << 5); // 6号键 - R肩键
  345.         if (minus) current_buttons |= (1 << 6); // 7号键 - 减号键
  346.         if (plus)  current_buttons |= (1 << 7); // 8号键 - 加号键

  347.         // 发现手柄输入有状态改变,立即上报
  348.         if (current_buttons != last_buttons || current_hat != last_hat) {
  349.             last_buttons = current_buttons;
  350.             last_hat = current_hat;
  351.             send_gamepad_report(current_buttons, current_hat);
  352.             //ESP_LOGI(TAG, "状态更新 - Btns: 0x%02X, Hat: %02X", current_buttons, current_hat);
  353.         }

  354.         vTaskDelay(pdMS_TO_TICKS(15)); // 15ms 周期轮询,自带消抖滤毛刺效果
  355.     }
  356. }

  357. void nimble_host_task(void *param) {
  358.     //ESP_LOGI(TAG, "NimBLE 主任务已启动");
  359.     nimble_port_run();
  360.     nimble_port_freertos_deinit();
  361. }

  362. /* 程序主入口 */
  363. void app_main(void) {
  364.     esp_err_t ret = nvs_flash_init();
  365.     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  366.         ESP_ERROR_CHECK(nvs_flash_erase());
  367.         ret = nvs_flash_init();
  368.     }
  369.     ESP_ERROR_CHECK(ret);

  370.     ESP_ERROR_CHECK(nimble_port_init());
  371.    
  372.     ble_svc_gap_init();
  373.     ble_svc_gatt_init();
  374.    
  375.     int rc = ble_gatts_count_cfg(gatt_svr_svcs);
  376.     if (rc != 0) return;
  377.     rc = ble_gatts_add_svcs(gatt_svr_svcs);
  378.     if (rc != 0) return;

  379.     ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO;
  380.     ble_hs_cfg.sm_bonding = 1;
  381.     ble_hs_cfg.sm_mitm = 0;
  382.     ble_hs_cfg.sm_sc = 1;
  383.     ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
  384.     ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;

  385.     ble_hs_cfg.store_read_cb = ble_store_config_read;
  386.     ble_hs_cfg.store_write_cb = ble_store_config_write;

  387.     ble_svc_gap_device_name_set("ESP8684-Gamepad");
  388.     ble_hs_cfg.sync_cb = ble_app_on_sync;

  389.     nimble_port_freertos_init(nimble_host_task);

  390.     // 启动12按键和1LED的处理任务
  391.     xTaskCreate(button_scan_task, "button_scan_task", 2048, NULL, 5, NULL);
  392. }
复制代码



sdkconfig.defaults内容如下
  1. # 芯片目标
  2. CONFIG_IDF_TARGET="esp32c2"

  3. # 26MHz 外置晶振关键配置
  4. CONFIG_XTAL_FREQ_26=y
  5. CONFIG_XTAL_FREQ=26
  6. CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_120=y

  7. # 闪存大小配置 (2MB)
  8. CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
  9. CONFIG_PARTITION_TABLE_CUSTOM=y
  10. CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"

  11. # 编译器优化:优化大小 (-Os) 极致省闪存
  12. CONFIG_COMPILER_OPTIMIZATION_SIZE=y

  13. # 彻底关闭 Wi-Fi,根除共存丢包,极大释放内存空间
  14. CONFIG_ESP_WIFI_ENABLED=n

  15. # 蓝牙底层配置:启用 NimBLE,禁用臃肿的 Bluedroid
  16. CONFIG_BT_ENABLED=y
  17. CONFIG_BT_BLUEDROID_ENABLED=n
  18. CONFIG_BT_NIMBLE_ENABLED=y
  19. # 绑定信息持久化(第二版增加,不开会导致无法自动连接已连接过的蓝牙)
  20. CONFIG_BT_NIMBLE_NVS_PERSIST=y

  21. # NimBLE 内存极致裁剪
  22. CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
  23. CONFIG_BT_NIMBLE_MAX_BONDS=3
  24. CONFIG_BT_NIMBLE_MAX_CCCDS=8
  25. CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT=12

  26. # 关闭UART0,因为要用19、20两个引脚
  27. # 彻底禁用标准控制台输出(适用于 ESP-IDF v5.x / v6.x)
  28. CONFIG_ESP_CONSOLE_NONE=y
  29. # 如果是较老版本的 ESP-IDF,请使用这行:
  30. # CONFIG_ESP_CONSOLE_UART_NONE=y

复制代码





初步测试正常。把编译的固件也放出来吧。没有家元的留下邮箱。

版本1:不会绑定蓝牙,每次断电重启需要重新连接。


版本2:开启了绑定蓝牙,连接过的设备会自动连接。






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

打赏

参与人数 1家元 +30 收起 理由
家睦 + 30

查看全部打赏

发表于 4 小时前 | 显示全部楼层
游客请登录后查看回复内容
回复 支持 反对

使用道具 举报

发表于 4 小时前 | 显示全部楼层
游客请登录后查看回复内容
回复 支持 1 反对 0

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|数码之家-技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2026-6-30 13:12 , Processed in 0.093600 second(s), 11 queries , Gzip On, Redis On.

Powered by Discuz!

© MyDigit.Net Since 2006

快速回复 返回顶部 返回列表