|  | @@ -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);
 | 
	
		
			
				|  |  | +}
 |