|
@@ -0,0 +1,231 @@
|
|
|
+#include <stdio.h>
|
|
|
+#include "freertos/FreeRTOS.h"
|
|
|
+#include "freertos/task.h"
|
|
|
+#include "driver/gpio.h"
|
|
|
+#include "driver/pwm.h"
|
|
|
+#include "esp_log.h"
|
|
|
+#include "esp_system.h"
|
|
|
+#include "nvs_flash.h"
|
|
|
+#include "esp_bt.h"
|
|
|
+#include "esp_gap_ble_api.h"
|
|
|
+#include "esp_gattc_api.h"
|
|
|
+#include "esp_gatts_api.h"
|
|
|
+#include "esp_gatt_common_api.h"
|
|
|
+
|
|
|
+#define BUTTON_A_GPIO GPIO_NUM_5
|
|
|
+#define BUTTON_B_GPIO GPIO_NUM_6
|
|
|
+#define BUTTON_C_GPIO GPIO_NUM_7
|
|
|
+#define LED_GPIO GPIO_NUM_16
|
|
|
+
|
|
|
+#define PWM_CHANNEL PWM_CHANNEL_0
|
|
|
+#define PWM_FREQ 1000
|
|
|
+#define PWM_RES 100
|
|
|
+
|
|
|
+#define GATTS_TAG "GATTS_DEMO"
|
|
|
+#define GATTS_SERVICE_UUID 0x00FF
|
|
|
+#define GATTS_CHAR_UUID_LED_ON_OFF 0xFF01
|
|
|
+#define GATTS_CHAR_UUID_LED_BRIGHTNESS 0xFF02
|
|
|
+#define GATTS_CHAR_UUID_LED_CONTROL 0xFF03
|
|
|
+
|
|
|
+static bool led_on = false;
|
|
|
+static int led_brightness = 0;
|
|
|
+
|
|
|
+// 定义蓝牙服务和特征值UUID
|
|
|
+static uint16_t gatts_service_uuid = GATTS_SERVICE_UUID;
|
|
|
+static uint16_t gatts_char_uuid_led_on_off = GATTS_CHAR_UUID_LED_ON_OFF;
|
|
|
+static uint16_t gatts_char_uuid_led_brightness = GATTS_CHAR_UUID_LED_BRIGHTNESS;
|
|
|
+static uint16_t gatts_char_uuid_led_control = GATTS_CHAR_UUID_LED_CONTROL;
|
|
|
+
|
|
|
+// 定义蓝牙特征值句柄
|
|
|
+static uint16_t gatts_handle_table[3];
|
|
|
+
|
|
|
+// 定义解析BLE指令的函数
|
|
|
+static void parse_ble_command(uint8_t *value, size_t len) {
|
|
|
+ switch (value[0]) {
|
|
|
+ case 0x01: // LED开关
|
|
|
+ if (len == 2) {
|
|
|
+ if (value[1] == 0x01) {
|
|
|
+ led_on = true;
|
|
|
+ pwm_set_duty(PWM_CHANNEL, led_brightness);
|
|
|
+ pwm_start();
|
|
|
+ }
|
|
|
+ else if (value[1] == 0x00) {
|
|
|
+ led_on = false;
|
|
|
+ pwm_stop();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 0x02: // 逐级增减LED亮度
|
|
|
+ if (len == 2) {
|
|
|
+ int delta = (value[1] == 0x01 ? 1 : -1);
|
|
|
+ led_brightness += delta;
|
|
|
+ if (led_brightness < 0) {
|
|
|
+ led_brightness = 0;
|
|
|
+ }
|
|
|
+ else if (led_brightness > PWM_RES) {
|
|
|
+ led_brightness = PWM_RES;
|
|
|
+ }
|
|
|
+ if (led_on) {
|
|
|
+ pwm_set_duty(PWM_CHANNEL, led_brightness);
|
|
|
+ pwm_start();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 0x03: // 直接指定LED亮度
|
|
|
+ if (len == 2) {
|
|
|
+ led_brightness = value[1];
|
|
|
+ if (led_brightness < 0) {
|
|
|
+ led_brightness = 0;
|
|
|
+ }
|
|
|
+ else if (led_brightness > PWM_RES) {
|
|
|
+ led_brightness = PWM_RES;
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ led_on) {
|
|
|
+ pwm_set_duty(PWM_CHANNEL, led_brightness);
|
|
|
+ pwm_start();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+}
|
|
|
+}
|
|
|
+
|
|
|
+// 定义BLE GATT Server回调函数
|
|
|
+static esp_gatts_cb_event_t gatts_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:
|
|
|
+// 注册GATT服务
|
|
|
+esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab((esp_gatts_attr_db_t *)param->reg.create.handles, gatts_if, 3, 0);
|
|
|
+if (create_attr_ret != ESP_OK) {
|
|
|
+ESP_LOGE(GATTS_TAG, "create attr table failed, error code = %x", create_attr_ret);
|
|
|
+}
|
|
|
+else {
|
|
|
+// 保存特征值句柄
|
|
|
+memcpy(gatts_handle_table, param->reg.create.handles, sizeof(gatts_handle_table));
|
|
|
+}
|
|
|
+break;
|
|
|
+case ESP_GATTS_READ_EVT:
|
|
|
+break;
|
|
|
+case ESP_GATTS_WRITE_EVT:
|
|
|
+if (param->write.is_prep) {
|
|
|
+break;
|
|
|
+}
|
|
|
+if (param->write.need_rsp) {
|
|
|
+esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
|
|
|
+}
|
|
|
+parse_ble_command(param->write.value, param->write.len);
|
|
|
+break;
|
|
|
+default:
|
|
|
+break;
|
|
|
+}
|
|
|
+return ESP_GATT_OK;
|
|
|
+}
|
|
|
+
|
|
|
+// 定义按钮A的中断处理函数
|
|
|
+static void IRAM_ATTR button_a_isr_handler(void *arg) {
|
|
|
+static uint64_t button_a_pressed_time = 0;
|
|
|
+uint64_t button_a_current_time = esp_timer_get_time();
|
|
|
+if (gpio_get_level(BUTTON_A_GPIO) == 0) {
|
|
|
+button_a_pressed_time = button_a_current_time;
|
|
|
+}
|
|
|
+else {
|
|
|
+if (button_a_current_time - button_a_pressed_time > 500000) { // 长按
|
|
|
+led_brightness--;
|
|
|
+if (led_brightness < 0) {
|
|
|
+led_brightness = 0;
|
|
|
+}
|
|
|
+pwm_set_duty(PWM_CHANNEL, led_brightness);
|
|
|
+pwm_start();
|
|
|
+}
|
|
|
+else { // 短按
|
|
|
+led_brightness++;
|
|
|
+if (led_brightness > PWM_RES) {
|
|
|
+led_brightness = PWM_RES;
|
|
|
+}
|
|
|
+pwm_set_duty(PWM_CHANNEL, led_brightness);
|
|
|
+pwm_start();
|
|
|
+}
|
|
|
+}
|
|
|
+}
|
|
|
+
|
|
|
+// 定义按钮B的中断处理函数
|
|
|
+static void IRAM_ATTR button_b_isr_handler(void *arg) {
|
|
|
+static uint64_t button_b_pressed_time = 0;
|
|
|
+uint64_t button_b_current_time = esp_timer_get_time();
|
|
|
+if (gpio_get_level(BUTTON_B_GPIO) == 0) {
|
|
|
+button_b_pressed_time = button_b_current_time;
|
|
|
+}
|
|
|
+else {
|
|
|
+if (button_b_current_time - button_b_pressed_time > 500000) { // 长按
|
|
|
+led_brightness++;
|
|
|
+if (led_brightness > PWM_RES) {
|
|
|
+led_brightness = PWM_RES;
|
|
|
+}
|
|
|
+pwm_set_duty(PWM_CHANNEL, led_brightness);
|
|
|
+pwm_start();
|
|
|
+}
|
|
|
+else { // 短按
|
|
|
+led_brightness--;
|
|
|
+if (led_brightness < 0) {
|
|
|
+led_brightness = 0;
|
|
|
+}
|
|
|
+pwm_set_duty(PWM_CHANNEL, led_brightness);
|
|
|
+pwm_start();
|
|
|
+}
|
|
|
+}
|
|
|
+}
|
|
|
+
|
|
|
+// 定义按钮C的中断处理函数
|
|
|
+static void IRAM_ATTR button_c_isr_handler(void *arg) {
|
|
|
+ bool led_on = false;
|
|
|
+ if (gpio_get_level(LED_GPIO) == 0) {
|
|
|
+ led_on = true;
|
|
|
+ }
|
|
|
+ led_on = !led_on;
|
|
|
+ gpio_set_level(LED_GPIO, led_on ? 1 : 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ void app_main() {
|
|
|
+ // 初始化GPIO
|
|
|
+ gpio_pad_select_gpio(BUTTON_A_GPIO);
|
|
|
+ gpio_pad_select_gpio(BUTTON_B_GPIO);
|
|
|
+ gpio_pad_select_gpio(BUTTON_C_GPIO);
|
|
|
+ gpio_pad_select_gpio(LED_GPIO);
|
|
|
+ gpio_set_direction(BUTTON_A_GPIO, GPIO_MODE_INPUT);
|
|
|
+ gpio_set_direction(BUTTON_B_GPIO, GPIO_MODE_INPUT);
|
|
|
+ gpio_set_direction(BUTTON_C_GPIO, GPIO_MODE_INPUT);
|
|
|
+ gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT);
|
|
|
+ gpio_set_level(LED_GPIO, 0);
|
|
|
+
|
|
|
+ // 初始化PWM
|
|
|
+ pwm_init(PWM_CHANNEL, NULL);
|
|
|
+ pwm_set_freq(PWM_CHANNEL, PWM_FREQ);
|
|
|
+ pwm_set_duty(PWM_CHANNEL, 0);
|
|
|
+ pwm_start();
|
|
|
+
|
|
|
+ // 设置按钮A的中断
|
|
|
+ gpio_set_intr_type(BUTTON_A_GPIO, GPIO_INTR_ANYEDGE);
|
|
|
+ gpio_install_isr_service(0);
|
|
|
+ gpio_isr_handler_add(BUTTON_A_GPIO, button_a_isr_handler, NULL);
|
|
|
+
|
|
|
+ // 设置按钮B的中断
|
|
|
+ gpio_set_intr_type(BUTTON_B_GPIO, GPIO_INTR_ANYEDGE);
|
|
|
+ gpio_isr_handler_add(BUTTON_B_GPIO, button_b_isr_handler, NULL);
|
|
|
+
|
|
|
+ // 设置按钮C的中断
|
|
|
+ gpio_set_intr_type(BUTTON_C_GPIO, GPIO_INTR_ANYEDGE);
|
|
|
+ gpio_isr_handler_add(BUTTON_C_GPIO, button_c_isr_handler, NULL);
|
|
|
+
|
|
|
+ // 初始化BLE
|
|
|
+ esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
|
|
+ esp_bt_controller_init(&bt_cfg);
|
|
|
+ esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
|
|
+
|
|
|
+ esp_bluedroid_init();
|
|
|
+ esp_bluedroid_enable();
|
|
|
+
|
|
|
+ esp_ble_gatts_register_callback(gatts_event_handler);
|
|
|
+ esp_ble_gatts_app_register(APP_ID);
|
|
|
+}
|