ESP-IDF 使用方式与典型场景
四、使用方式与典型场景
示例一:WiFi 联网 + GPIO 控制 + 日志输出
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#define LED_GPIO GPIO_NUM_2
#define WIFI_OK BIT0
static const char *TAG = "app";
static EventGroupHandle_t s_evt;
static void wifi_event_handler(void *arg, esp_event_base_t base,
int32_t id, void *data)
{
if (base == WIFI_EVENT && id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (base == WIFI_EVENT && id == WIFI_EVENT_STA_DISCONNECTED) {
ESP_LOGW(TAG, "断开,1 秒后重连");
vTaskDelay(pdMS_TO_TICKS(1000));
esp_wifi_connect(); // 必须重连,否则永远不再上线
} else if (base == IP_EVENT && id == IP_EVENT_STA_GOT_IP) {
xEventGroupSetBits(s_evt, WIFI_OK);
ESP_LOGI(TAG, "拿到 IP,联网成功");
}
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init()); // WiFi 依赖 NVS,必须先初始化
s_evt = xEventGroupCreate();
gpio_config_t io = {
.pin_bit_mask = 1ULL << LED_GPIO,
.mode = GPIO_MODE_OUTPUT,
};
ESP_ERROR_CHECK(gpio_config(&io));
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_ERROR_CHECK(esp_event_handler_instance_register(
WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(
IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL, NULL));
wifi_config_t wc = { 0 };
strncpy((char *)wc.sta.ssid, "<你的 SSID>", sizeof(wc.sta.ssid) - 1);
strncpy((char *)wc.sta.password, "<你的密码>", sizeof(wc.sta.password) - 1);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wc));
ESP_ERROR_CHECK(esp_wifi_start());
// 等联网成功再进入主循环
xEventGroupWaitBits(s_evt, WIFI_OK, pdFALSE, pdTRUE, portMAX_DELAY);
while (1) {
gpio_set_level(LED_GPIO, 1);
vTaskDelay(pdMS_TO_TICKS(500));
gpio_set_level(LED_GPIO, 0);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
三个易错点:NVS 必须先初始化,WiFi 协议栈依赖它,跳过会直接报错;断连回调里必须调用重连,否则掉线一次就再也不上线;app_main 返回后任务会退出,主循环要自己写,不能依赖框架帮你维持。
示例二:用 idf.py 的完整工作流与常用配置
# 建工程(从官方示例拷贝是最快的起手方式)
cp -r $IDF_PATH/examples/get-started/hello_world myapp && cd myapp
# 设定目标芯片(建工程初期就要定,之后改会重置配置)
idf.py set-target esp32s3
# 打开配置菜单:设置 Flash 容量、分区表、日志级别、WiFi 省电等
idf.py menuconfig
# 常用配置路径(菜单名称以当前版本文档为准):
# Component config → Log output → Default log verbosity (量产前调到 Warning 或更低)
# Component config → ESP System Settings → Channel for console output
# Serial flasher config → Flash size
# Partition Table → Partition Table (Single factory app, no OTA / Factory app, two OTA...)
# 编译
idf.py build
# 只编译、不烧录,查看体积构成
idf.py size
# 烧录并打开串口监视(指定端口)
idf.py -p <串口> -b 460800 flash monitor
# 退出监视:Ctrl + ]
# 单独烧录分区表 / 应用 / 引导
idf.py partition-table-flash
idf.py app-flash
# 擦除整片 Flash(换 Flash 大小或分区表改动后建议先擦)
idf.py -p <串口> erase-flash
# 生成并分析 Core Dump(崩溃定位)
idf.py coredump-info
idf.py coredump-debug
把 sdkconfig.defaults 提交到版本管理是团队协作的关键:它让「每个人的 menuconfig 配置」变成可复现的默认值,新人拉下代码就能得到一致的配置,避免「在我机器上能跑」。
适合与不适合的场景
适合:需要完整网络协议栈与安全能力的联网设备;需要 OTA 升级的量产产品;需要精细控制内存、功耗、任务调度的场景;多芯片型号(ESP32 家族内)复用同一套代码。
不适合:只做一次简单实验、连灯都不想点太多行的教学场景(Arduino 更快);团队完全没有 C 与构建系统经验时(上手成本高);需要跨芯片厂商(比如同时用 Nordic 与 ST)统一代码库的场景(应选 Zephyr 这类跨厂商 RTOS)。
