ESP32-S3编程开发指南

基于小智AI项目实战经验,本指南详细介绍ESP32-S3的编程开发,从基础外设控制到复杂AI应用的完整开发流程。

一、开发环境选择

1.1 开发框架对比

框架ESP-IDFArduino ESP32PlatformIO
复杂度
性能最优一般
功能完整性完整受限较完整
调试能力
小智推荐⭐⭐⭐⭐⭐⭐⭐⭐
推荐: 小智AI项目使用ESP-IDF进行核心开发,确保最佳性能和完整功能支持

1.2 ESP-IDF开发环境搭建

Windows环境配置

# 1. 下载ESP-IDF 5.3.2
# 从 https://dl.espressif.com/dl/esp-idf/ 下载

# 2. 安装到非C盘目录
# 例如: D:\Espressif\esp-idf

# 3. 配置环境变量 (自动完成)
# 双击桌面 "ESP-IDF 5.3 PowerShell"

# 4. 验证安装
idf.py --version
# 输出: ESP-IDF v5.3.2

Linux/macOS环境

# 1. 安装依赖
sudo apt-get install git wget flex bison gperf python3-pip

# 2. 克隆ESP-IDF
git clone -b v5.3.2 --recursive https://github.com/espressif/esp-idf.git

# 3. 安装工具链
cd esp-idf
./install.sh

# 4. 设置环境变量
. ./export.sh

1.3 Arduino开发环境(可选)

# Arduino IDE 2.x设置
# 文件 -> 首选项 -> 附加开发板管理器网址
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

# 工具 -> 开发板 -> 开发板管理器
# 搜索"esp32"并安装最新版本

# 选择开发板: ESP32S3 Dev Module

二、基础GPIO编程

2.1 数字IO控制

LED控制示例 (ESP-IDF)

#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define LED_PIN GPIO_NUM_48  // 板载RGB LED

void app_main() {
    // 配置GPIO为输出
    gpio_reset_pin(LED_PIN);
    gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
    
    while(1) {
        gpio_set_level(LED_PIN, 1);  // 点亮LED
        vTaskDelay(pdMS_TO_TICKS(500));
        gpio_set_level(LED_PIN, 0);  // 熄灭LED
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

按键输入处理

#include "driver/gpio.h"

#define BUTTON_PIN GPIO_NUM_0  // Boot按钮

void button_init() {
    gpio_reset_pin(BUTTON_PIN);
    gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
    gpio_set_pull_mode(BUTTON_PIN, GPIO_PULLUP_ENABLE);
}

bool is_button_pressed() {
    return gpio_get_level(BUTTON_PIN) == 0;  // 按下为低电平
}

2.2 PWM调光控制

#include "driver/ledc.h"

#define PWM_CHANNEL LEDC_CHANNEL_0
#define PWM_TIMER   LEDC_TIMER_0
#define PWM_PIN     GPIO_NUM_2
#define PWM_FREQ    5000  // 5kHz
#define PWM_RESOLUTION LEDC_TIMER_8_BIT  // 8位分辨率 (0-255)

void pwm_init() {
    // 配置定时器
    ledc_timer_config_t timer_config = {
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .timer_num = PWM_TIMER,
        .duty_resolution = PWM_RESOLUTION,
        .freq_hz = PWM_FREQ,
        .clk_cfg = LEDC_AUTO_CLK
    };
    ledc_timer_config(&timer_config);
    
    // 配置通道
    ledc_channel_config_t channel_config = {
        .channel = PWM_CHANNEL,
        .duty = 0,
        .gpio_num = PWM_PIN,
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .timer_sel = PWM_TIMER
    };
    ledc_channel_config(&channel_config);
}

void set_brightness(uint8_t brightness) {
    ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL, brightness);
    ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL);
}

三、音频系统编程

3.1 I2S音频接口配置

麦克风接口(INMP441)

#include "driver/i2s.h"

#define I2S_MIC_PORT    I2S_NUM_0
#define I2S_MIC_WS      GPIO_NUM_4
#define I2S_MIC_SCK     GPIO_NUM_5  
#define I2S_MIC_SD      GPIO_NUM_6
#define SAMPLE_RATE     16000
#define SAMPLE_BITS     I2S_BITS_PER_SAMPLE_32BIT

void i2s_mic_init() {
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX,
        .sample_rate = SAMPLE_RATE,
        .bits_per_sample = SAMPLE_BITS,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,
        .dma_buf_count = 8,
        .dma_buf_len = 1024,
    };
    
    i2s_pin_config_t pin_config = {
        .ws_io_num = I2S_MIC_WS,
        .ck_io_num = I2S_MIC_SCK,
        .data_in_num = I2S_MIC_SD,
        .data_out_num = I2S_PIN_NO_CHANGE
    };
    
    i2s_driver_install(I2S_MIC_PORT, &i2s_config, 0, NULL);
    i2s_set_pin(I2S_MIC_PORT, &pin_config);
}

size_t read_microphone(int32_t* buffer, size_t samples) {
    size_t bytes_read;
    i2s_read(I2S_MIC_PORT, buffer, samples * sizeof(int32_t), 
             &bytes_read, portMAX_DELAY);
    return bytes_read / sizeof(int32_t);
}

扬声器接口(MAX98357A)

#define I2S_SPK_PORT    I2S_NUM_1
#define I2S_SPK_BCLK    GPIO_NUM_15
#define I2S_SPK_LRC     GPIO_NUM_16
#define I2S_SPK_DIN     GPIO_NUM_7

void i2s_speaker_init() {
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_TX,
        .sample_rate = 16000,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,
        .dma_buf_count = 8,
        .dma_buf_len = 1024,
    };
    
    i2s_pin_config_t pin_config = {
        .ws_io_num = I2S_SPK_LRC,
        .ck_io_num = I2S_SPK_BCLK,
        .data_out_num = I2S_SPK_DIN,
        .data_in_num = I2S_PIN_NO_CHANGE
    };
    
    i2s_driver_install(I2S_SPK_PORT, &i2s_config, 0, NULL);
    i2s_set_pin(I2S_SPK_PORT, &pin_config);
}

void play_audio(const int16_t* audio_data, size_t samples) {
    size_t bytes_written;
    i2s_write(I2S_SPK_PORT, audio_data, samples * sizeof(int16_t),
              &bytes_written, portMAX_DELAY);
}

3.2 音频信号处理

音量控制

#include <math.h>

void adjust_volume(int16_t* audio_buffer, size_t samples, float volume) {
    // volume范围: 0.0-2.0 (0%到200%)
    for(size_t i = 0; i < samples; i++) {
        float sample = audio_buffer[i] * volume;
        
        // 防止溢出
        if(sample > 32767) sample = 32767;
        if(sample < -32768) sample = -32768;
        
        audio_buffer[i] = (int16_t)sample;
    }
}

噪音抑制简单实现

void simple_noise_gate(int16_t* audio_buffer, size_t samples, int16_t threshold) {
    for(size_t i = 0; i < samples; i++) {
        if(abs(audio_buffer[i]) < threshold) {
            audio_buffer[i] = 0;  // 小于阈值的信号置零
        }
    }
}

四、网络通信编程

4.1 Wi-Fi连接管理

Wi-Fi事件处理

#include "esp_wifi.h"
#include "esp_event.h"

static EventGroupHandle_t wifi_event_group;
const int WIFI_CONNECTED_BIT = BIT0;

static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                              int32_t event_id, void* event_data) {
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        esp_wifi_connect();
        ESP_LOGI("WiFi", "重新连接WiFi...");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI("WiFi", "连接成功,IP:" IPSTR, IP2STR(&event->ip_info.ip));
        xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

void wifi_init(const char* ssid, const char* password) {
    wifi_event_group = xEventGroupCreate();
    
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();
    
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    
    esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, 
                                       &wifi_event_handler, NULL, NULL);
    esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
                                       &wifi_event_handler, NULL, NULL);
    
    wifi_config_t wifi_config = {};
    strcpy((char*)wifi_config.sta.ssid, ssid);
    strcpy((char*)wifi_config.sta.password, password);
    
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
    
    // 等待连接
    xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, false, true, 
                       portMAX_DELAY);
}

4.2 WebSocket客户端

小智AI WebSocket通信

#include "esp_websocket_client.h"

static esp_websocket_client_handle_t client;

static void websocket_event_handler(void *handler_args, esp_event_base_t base,
                                   int32_t event_id, void *event_data) {
    esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
    
    switch (event_id) {
        case WEBSOCKET_EVENT_CONNECTED:
            ESP_LOGI("WebSocket", "连接成功");
            break;
            
        case WEBSOCKET_EVENT_DATA:
            ESP_LOGI("WebSocket", "收到数据: %.*s", data->data_len, (char*)data->data_ptr);
            // 处理AI服务器响应
            handle_ai_response((char*)data->data_ptr, data->data_len);
            break;
            
        case WEBSOCKET_EVENT_ERROR:
            ESP_LOGE("WebSocket", "连接错误");
            break;
            
        case WEBSOCKET_EVENT_DISCONNECTED:
            ESP_LOGI("WebSocket", "断开连接");
            break;
    }
}

void websocket_init(const char* uri) {
    esp_websocket_client_config_t websocket_cfg = {
        .uri = uri,
        .task_stack = 4096,
    };
    
    client = esp_websocket_client_init(&websocket_cfg);
    esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, 
                                 websocket_event_handler, (void *)client);
    esp_websocket_client_start(client);
}

void send_audio_data(const char* audio_base64) {
    char json_message[2048];
    snprintf(json_message, sizeof(json_message),
             "{\"type\":\"audio\",\"data\":\"%s\"}", audio_base64);
    
    esp_websocket_client_send_text(client, json_message, strlen(json_message), 
                                  portMAX_DELAY);
}

4.3 HTTP客户端

#include "esp_http_client.h"

esp_err_t http_post_json(const char* url, const char* json_data, char* response_buffer, size_t buffer_size) {
    esp_http_client_config_t config = {
        .url = url,
        .method = HTTP_METHOD_POST,
    };
    
    esp_http_client_handle_t client = esp_http_client_init(&config);
    
    esp_http_client_set_header(client, "Content-Type", "application/json");
    esp_http_client_set_post_field(client, json_data, strlen(json_data));
    
    esp_err_t err = esp_http_client_perform(client);
    
    if (err == ESP_OK) {
        int data_read = esp_http_client_read_response(client, response_buffer, buffer_size - 1);
        response_buffer[data_read] = '\0';
    }
    
    esp_http_client_cleanup(client);
    return err;
}

五、传感器接口编程

5.1 I2C通信

OLED显示屏(SSD1306)

#include "driver/i2c.h"

#define I2C_MASTER_PORT     I2C_NUM_0
#define I2C_MASTER_SDA_IO   GPIO_NUM_41
#define I2C_MASTER_SCL_IO   GPIO_NUM_42
#define I2C_MASTER_FREQ_HZ  100000
#define SSD1306_ADDR        0x3C

void i2c_master_init() {
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };
    
    i2c_param_config(I2C_MASTER_PORT, &conf);
    i2c_driver_install(I2C_MASTER_PORT, conf.mode, 0, 0, 0);
}

void ssd1306_write_command(uint8_t cmd) {
    i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();
    i2c_master_start(cmd_handle);
    i2c_master_write_byte(cmd_handle, SSD1306_ADDR << 1 | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd_handle, 0x00, true);  // 命令模式
    i2c_master_write_byte(cmd_handle, cmd, true);
    i2c_master_stop(cmd_handle);
    i2c_master_cmd_begin(I2C_MASTER_PORT, cmd_handle, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd_handle);
}

5.2 SPI通信

#include "driver/spi_master.h"

#define SPI_HOST        SPI2_HOST
#define SPI_MOSI_PIN    GPIO_NUM_11
#define SPI_MISO_PIN    GPIO_NUM_13  
#define SPI_SCLK_PIN    GPIO_NUM_12
#define SPI_CS_PIN      GPIO_NUM_10

spi_device_handle_t spi_device;

void spi_init() {
    spi_bus_config_t bus_cfg = {
        .mosi_io_num = SPI_MOSI_PIN,
        .miso_io_num = SPI_MISO_PIN,
        .sclk_io_num = SPI_SCLK_PIN,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 4096
    };
    
    spi_device_interface_config_t dev_cfg = {
        .clock_speed_hz = 1*1000*1000,  // 1MHz
        .mode = 0,
        .spics_io_num = SPI_CS_PIN,
        .queue_size = 7,
    };
    
    ESP_ERROR_CHECK(spi_bus_initialize(SPI_HOST, &bus_cfg, SPI_DMA_CH_AUTO));
    ESP_ERROR_CHECK(spi_bus_add_device(SPI_HOST, &dev_cfg, &spi_device));
}

六、多任务编程

6.1 FreeRTOS任务管理

小智AI任务架构

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"

// 任务优先级定义
#define AUDIO_TASK_PRIORITY     5  // 最高优先级
#define NETWORK_TASK_PRIORITY   3  
#define DISPLAY_TASK_PRIORITY   2
#define SENSOR_TASK_PRIORITY    1  // 最低优先级

// 消息队列
QueueHandle_t audio_queue;
QueueHandle_t ai_response_queue;

// 音频处理任务
void audio_task(void* parameter) {
    int16_t audio_buffer[1024];
    
    while(1) {
        // 从麦克风读取音频
        size_t samples = read_microphone((int32_t*)audio_buffer, 1024);
        
        // 语音活动检测
        if(is_voice_active(audio_buffer, samples)) {
            // 发送到语音识别队列
            xQueueSend(audio_queue, audio_buffer, 0);
        }
        
        vTaskDelay(pdMS_TO_TICKS(20));  // 20ms采样
    }
}

// AI处理任务
void ai_task(void* parameter) {
    int16_t audio_data[1024];
    
    while(1) {
        if(xQueueReceive(audio_queue, audio_data, portMAX_DELAY)) {
            // 语音识别
            char* text = speech_to_text(audio_data, 1024);
            
            if(text) {
                // 发送到AI服务器
                char* response = query_ai_service(text);
                
                if(response) {
                    // 发送AI响应到播放队列
                    xQueueSend(ai_response_queue, response, 0);
                }
                
                free(text);
                free(response);
            }
        }
    }
}

// 显示任务
void display_task(void* parameter) {
    char display_text[128];
    
    while(1) {
        if(xQueueReceive(ai_response_queue, display_text, pdMS_TO_TICKS(100))) {
            // 更新OLED显示
            ssd1306_display_text(display_text);
            
            // TTS语音合成并播放
            synthesize_and_play(display_text);
        }
        
        // 更新WiFi信号显示
        update_signal_strength();
        
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void create_xiaozhi_tasks() {
    // 创建消息队列
    audio_queue = xQueueCreate(10, sizeof(int16_t) * 1024);
    ai_response_queue = xQueueCreate(5, sizeof(char) * 128);
    
    // 创建任务
    xTaskCreatePinnedToCore(audio_task, "AudioTask", 4096, NULL, 
                           AUDIO_TASK_PRIORITY, NULL, 1);  // 核心1
    
    xTaskCreatePinnedToCore(ai_task, "AITask", 8192, NULL,
                           NETWORK_TASK_PRIORITY, NULL, 0);  // 核心0
    
    xTaskCreate(display_task, "DisplayTask", 4096, NULL,
               DISPLAY_TASK_PRIORITY, NULL);
}

6.2 中断处理

按键中断处理

#include "driver/gpio.h"

#define BUTTON_PIN     GPIO_NUM_0
#define VOLUME_UP_PIN  GPIO_NUM_40  
#define VOLUME_DN_PIN  GPIO_NUM_39

static QueueHandle_t gpio_evt_queue = NULL;

// 中断服务程序(ISR)
static void IRAM_ATTR gpio_isr_handler(void* arg) {
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

// GPIO事件处理任务
static void gpio_task(void* arg) {
    uint32_t io_num;
    
    while(1) {
        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            switch(io_num) {
                case BUTTON_PIN:
                    ESP_LOGI("GPIO", "唤醒按钮按下");
                    handle_wake_button();
                    break;
                    
                case VOLUME_UP_PIN:
                    ESP_LOGI("GPIO", "音量+按钮按下");
                    volume_up();
                    break;
                    
                case VOLUME_DN_PIN:
                    ESP_LOGI("GPIO", "音量-按钮按下");
                    volume_down();
                    break;
            }
        }
    }
}

void gpio_interrupt_init() {
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
    
    // 配置GPIO
    gpio_config_t io_conf = {
        .intr_type = GPIO_INTR_NEGEDGE,  // 下降沿触发
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = (1ULL << BUTTON_PIN) | (1ULL << VOLUME_UP_PIN) | (1ULL << VOLUME_DN_PIN),
        .pull_down_en = 0,
        .pull_up_en = 1,
    };
    gpio_config(&io_conf);
    
    // 安装中断服务
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    gpio_isr_handler_add(BUTTON_PIN, gpio_isr_handler, (void*) BUTTON_PIN);
    gpio_isr_handler_add(VOLUME_UP_PIN, gpio_isr_handler, (void*) VOLUME_UP_PIN);
    gpio_isr_handler_add(VOLUME_DN_PIN, gpio_isr_handler, (void*) VOLUME_DN_PIN);
    
    // 创建GPIO事件处理任务
    xTaskCreate(gpio_task, "gpio_task", 2048, NULL, 10, NULL);
}

七、调试和优化

7.1 日志系统

#include "esp_log.h"

// 日志标签定义
static const char* TAG_AUDIO = "AUDIO";
static const char* TAG_WIFI = "WIFI";
static const char* TAG_AI = "AI";

void debug_log_example() {
    // 不同级别的日志
    ESP_LOGE(TAG_AUDIO, "错误: 音频初始化失败");
    ESP_LOGW(TAG_WIFI, "警告: Wi-Fi信号弱 (-75dBm)");
    ESP_LOGI(TAG_AI, "信息: AI响应时间 %dms", 1250);
    ESP_LOGD(TAG_AUDIO, "调试: 音频缓冲区 %d/%d", 512, 1024);
    ESP_LOGV(TAG_AI, "详细: HTTP请求头完整");
    
    // 十六进制数据打印
    uint8_t buffer[16] = {0x01, 0x02, 0x03, 0x04};
    ESP_LOG_BUFFER_HEX(TAG_AUDIO, buffer, 16);
}

// 运行时设置日志级别
void set_log_levels() {
    esp_log_level_set("AUDIO", ESP_LOG_DEBUG);
    esp_log_level_set("WIFI", ESP_LOG_INFO);
    esp_log_level_set("AI", ESP_LOG_WARN);
}

7.2 性能监控

#include "esp_timer.h"
#include "esp_system.h"

// 执行时间测量
uint64_t measure_execution_time(void (*function)()) {
    uint64_t start = esp_timer_get_time();
    function();
    uint64_t end = esp_timer_get_time();
    return end - start;  // 微秒
}

// 内存使用监控
void print_memory_usage() {
    size_t free_heap = esp_get_free_heap_size();
    size_t min_free = esp_get_minimum_free_heap_size();
    
    ESP_LOGI("MEMORY", "空闲堆内存: %d bytes", free_heap);
    ESP_LOGI("MEMORY", "最小空闲: %d bytes", min_free);
}

// CPU使用率监控
void print_task_stats() {
    char buffer[1024];
    vTaskGetRunTimeStats(buffer);
    ESP_LOGI("TASKS", "任务运行统计:\n%s", buffer);
}

7.3 错误处理

#include "esp_err.h"

// 错误处理宏
#define CHECK_ERROR(x) do { \
    esp_err_t rc = (x); \
    if (rc != ESP_OK) { \
        ESP_LOGE("ERROR", "错误 %s:%d %s", __FILE__, __LINE__, esp_err_to_name(rc)); \
        return rc; \
    } \
} while(0)

// 小智AI错误代码
typedef enum {
    XIAOZHI_OK = 0,
    XIAOZHI_ERR_AUDIO_INIT = -1,
    XIAOZHI_ERR_WIFI_CONNECT = -2,
    XIAOZHI_ERR_AI_SERVICE = -3,
    XIAOZHI_ERR_MEMORY = -4,
} xiaozhi_err_t;

const char* xiaozhi_err_to_name(xiaozhi_err_t error) {
    switch(error) {
        case XIAOZHI_OK: return "OK";
        case XIAOZHI_ERR_AUDIO_INIT: return "AUDIO_INIT_FAILED";
        case XIAOZHI_ERR_WIFI_CONNECT: return "WIFI_CONNECT_FAILED";
        case XIAOZHI_ERR_AI_SERVICE: return "AI_SERVICE_ERROR";
        case XIAOZHI_ERR_MEMORY: return "MEMORY_ERROR";
        default: return "UNKNOWN_ERROR";
    }
}

八、高级特性

8.1 OTA固件升级

#include "esp_ota_ops.h"
#include "esp_http_client.h"

esp_err_t ota_update_from_url(const char* url) {
    esp_http_client_config_t config = {
        .url = url,
        .cert_pem = NULL,
    };
    
    esp_err_t ret = esp_https_ota(&config);
    if (ret == ESP_OK) {
        ESP_LOGI("OTA", "OTA更新成功,重启中...");
        esp_restart();
    } else {
        ESP_LOGE("OTA", "OTA更新失败: %s", esp_err_to_name(ret));
    }
    return ret;
}

8.2 低功耗模式

#include "esp_sleep.h"

void enter_deep_sleep(uint64_t sleep_time_us) {
    // 配置唤醒源
    esp_sleep_enable_timer_wakeup(sleep_time_us);
    esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0);  // Boot按钮唤醒
    
    ESP_LOGI("SLEEP", "进入深度睡眠 %lld秒", sleep_time_us / 1000000);
    esp_deep_sleep_start();
}

void enter_light_sleep(uint32_t sleep_time_ms) {
    esp_sleep_enable_timer_wakeup(sleep_time_ms * 1000);
    esp_light_sleep_start();
}

下一步学习: