> 技术文档 > 【SoC】【ESP32】ESP-IDF+VSCode的初步使用

【SoC】【ESP32】ESP-IDF+VSCode的初步使用


一、简介

       ESP-IDF(Espressif IoT Development Framework)是乐鑫为其 ESP32、ESP32-S 系列、ESP32-C 系列等芯片提供的官方物联网开发框架,基于 FreeRTOS 操作系统,支持 C、C++ 和 Lua 等语言,用于快速开发物联网、智能家居、工业控制等地方的嵌入式应用。

(1)主要特点:

  1. 硬件抽象层:提供 Wi-Fi、蓝牙、以太网、SPI、I2C、UART 等外设的驱动和 API。
  2. 丰富组件:包含文件系统(FAT、SPIFFS)、网络协议栈(TCP/IP、MQTT、HTTP)、安全框架(SSL/TLS)等。
  3. 工具链支持:集成 CMake 构建系统、idf.py 命令行工具,支持一键编译、烧录、调试。
  4. 跨平台:支持 Windows、Linux、macOS 开发环境。
  5. 示例与文档:提供大量官方示例和详细文档,便于快速上手。

(2)基本开发流程:

  1. 环境搭建:安装 ESP-IDF 工具链(包含编译器、调试工具等)。
  2. 项目创建:基于示例模板或自定义创建项目。
  3. 配置:通过idf.py menuconfig配置项目参数(如 Wi-Fi、串口波特率等)。
  4. 开发:编写代码实现业务逻辑。
  5. 编译与烧录:使用idf.py build编译,idf.py flash烧录到设备。
  6. 调试:通过idf.py monitor查看串口输出或调试信息。

(3)典型应用场景:

  • 低功耗物联网设备(如温湿度传感器)
  • 智能家居控制(如智能开关、灯光控制)
  • 工业自动化数据采集
  • 无线通信中继设备

       ESP-IDF 适合需要高性能、低功耗、丰富通信接口的嵌入式系统开发,尤其在物联网领域应用广泛。

二、创建工程

1.新建文件夹ESP32_Example

2. 使用命令idf.py build初始化该工程 

注:CMakeLists.txt是帮助链接编译的文件

3.对于 ESP - IDF 等开发框架中component文件夹的功能,用于明确该目录在项目结构里承担存放特定代码(第三方组件、用户程序驱动代码 )的角色 。使用命令idf.py create-component + 文件名字

4.在ESP32_Example下新建一个文件夹components,把所有组件放在components下

5.设置目标芯片

使用查询命令idf.py --list-targets查看有哪些芯片类型

idf.py set-target

成功设置

6.输入命令idf.py menuconfig启动文本界面进行详细配置

7.设置SPI Flash速度模式,默认(DIO)即可

按下ESC退出

7.使用命令idf.py -p COM8 flash下载代码,这里只是检测是否能正常下载

8.编写测试函数

9.测试函数编译

10.测试函数下载

11.测试函数监控,使用命令idf.py monitor

可以看到了成功打印了hello,然后按下ctrl + ] 退出监控器。

12.清除编译文件

idf.py fullclean

三、使用VSCode+ESP-IDF插件编写代码

1.使用VSCode打开工程文件夹ESP32_Example

2.配置工程

选择下载程序方式、接口和目标芯片

3.扳手按钮编译

4.闪电按钮烧写

5.电视按钮启用监控

初步测试没问题。 

6.最下方的芯片选择后的齿轮按钮进行SDK的详细配置

flash

ESP32-S3-N16R8 中, “N16” 代表的是16MB 的 Flash,“R8” 表示8MB 的 PSRAM。所以这款芯片的 Flash 大小是 16MB。

Partition Table

选择自定义分区表分区表自定义名称:partitions_tabel_16MB.csv

PSRAM

使能外部SRAM,主要调整为八线模式和80MHz

CPU Frequency

FreeRTOS

一、GDB Stub(调试相关)

GDB Stub 是 FreeRTOS 中用于支持 GDB 调试器的组件,允许通过 GDB 查看任务状态、断点调试等。

  • Enable listing FreeRTOS tasks through GDB Stub
    启用后,GDB 调试器可以列出当前所有 FreeRTOS 任务的信息(如任务名、状态、优先级等),方便调试时监控任务运行状态。
  • Maximum number of tasks supported by GDB Stub: 32
    GDB Stub 最多支持同时显示 32 个任务的信息(超过则无法通过 GDB 完整列出)。
二、FreeRTOS Kernel(内核核心配置)
1. 内核基础
  • Run the Amazon SMP FreeRTOS kernel instead (FEATURE UNDER DEVELOPMENT)
    启用后将使用亚马逊的 SMP(对称多处理)版本 FreeRTOS 内核(实验性功能),支持多核心同时运行任务(适用于 ESP32S3 等双核芯片)。默认不启用时,使用标准单核心调度的 FreeRTOS 内核。
  • Run FreeRTOS only on first core
    限制 FreeRTOS 仅在芯片的第一个核心(Core 0)上运行,第二个核心(若有,如 ESP32S3 的 Core 1)可用于其他裸机程序或独立任务。
  • configTICK_RATE_HZ: 1000
    FreeRTOS 系统时钟节拍频率,单位为 Hz。此处设置为 1000,即每秒产生 1000 个时钟节拍(每个节拍间隔 1ms),用于任务调度、延时(如 vTaskDelay())等时间相关操作。节拍频率越高,时间精度越高,但内核开销略增。
2. 栈溢出检测
  • configCHECK_FOR_STACK_OVERFLOW: Check using canary bytes (Method 2)
    启用栈溢出检测功能,采用「金丝雀字节(canary bytes)」方式(方法 2):在任务栈的末尾放置特殊标记字节(金丝雀值),每次任务切换时检查标记是否被改写,若改写则判定为栈溢出(会触发栈溢出钩子函数)。这是一种常用的内存越界检测机制。
3. 任务与内存相关
  • configNUM_THREAD_LOCAL_STORAGE_POINTERS: 1
    每个任务可分配的「线程本地存储指针(TLS)」数量。TLS 用于存储任务私有数据(如任务专属的变量),此处最多支持 1 个指针。
  • configMINIMAL_STACK_SIZE (Idle task stack size): 1536
    空闲任务(Idle Task)的栈大小(单位:字节)。空闲任务是 FreeRTOS 自动创建的最低优先级任务,用于系统空闲时运行,栈大小需根据系统最小需求配置(此处 1536 字节适用于多数嵌入式场景)。
  • configMAX_TASK_NAME_LEN: 16
    任务名称的最大长度(包含终止符 \\0),超过则会被截断。例如,任务名最长为 15 个可见字符 + 1 个终止符。
  • configENABLE_BACKWARD_COMPATIBILITY
    启用后兼容旧版本 FreeRTOS 的 API 或宏定义(如旧版中的函数参数、结构体成员),避免因版本升级导致的兼容性问题。
4. 定时器功能
  • configUSE_TIMERS
    启用 FreeRTOS 软件定时器功能,允许创建周期性或一次性定时器(通过 xTimerCreate() 等 API)。
  • configTIMER_SERVICE_TASK_NAME: Tmr Svc
    定时器服务任务的名称(默认 Tmr Svc),该任务负责处理所有软件定时器的触发逻辑。
  • configTIMER_SERVICE_TASK_CORE_AFFINITY: No affinity
    定时器服务任务的核心绑定(适用于多核芯片),「No affinity」表示不固定核心,由内核自动调度到任意核心。
  • configTIMER_TASK_PRIORITY: 1
    定时器服务任务的优先级(数值越大优先级越高),此处为 1(较低优先级,避免抢占关键任务)。
  • configTIMER_TASK_STACK_DEPTH: 2048
    定时器服务任务的栈大小(2048 字节),需根据定时器回调函数的复杂度调整(若回调函数复杂,需增大栈大小)。
  • configTIMER_QUEUE_LENGTH: 10
    定时器命令队列的长度,用于存储待处理的定时器操作(如启动、停止定时器),超过 10 个则需等待队列空闲。
5. 队列与通知
  • configQUEUE_REGISTRY_SIZE: 0
    队列注册表的大小,用于将队列 / 信号量与名称关联(通过 vQueueAddToRegistry()),方便调试时识别队列。0 表示禁用该功能。
  • configTASK_NOTIFICATION_ARRAY_ENTRIES: 1
    每个任务的「任务通知数组」长度。任务通知是一种轻量级的通信机制(替代信号量 / 队列),此处最多支持 1 个通知条目(每个任务可接收 1 种通知)。
6. 调试与统计
  • configUSE_TRACE_FACILITY
    启用跟踪功能,支持 FreeRTOS 的跟踪宏(如 vTaskList() 列出任务状态、vTaskGetRunTimeStats() 统计任务运行时间),用于系统性能分析。
  • configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES
    启用链表数据完整性检查,在 FreeRTOS 内部链表(如任务就绪链表、阻塞链表)的节点中添加校验字节,检测链表是否被意外篡改(如内存越界导致的链表损坏)。
  • configGENERATE_RUN_TIME_STATS
    启用任务运行时间统计功能,可通过 vTaskGetRunTimeStats() 获取每个任务的运行时间占比(需配合硬件定时器实现)。
  • configUSE_APPLICATION_TASK_TAG
    允许为任务设置「标签(tag)」,通过 vTaskSetApplicationTaskTag() 关联一个整数或指针,用于标识任务(如区分任务类型、归属模块)。
三、Port(端口配置,与硬件相关)

针对特定硬件平台(如 ESP32S3 的 Xtensa 架构)的 FreeRTOS 移植配置。

  • Wrap task functions
    对任务函数进行包装(如添加进入 / 退出钩子),通常用于调试或跟踪任务的创建 / 销毁。
  • Enable stack overflow debug watchpoint
    启用栈溢出调试断点(依赖硬件 watchpoint 功能),当栈指针超出栈范围时触发调试中断,方便定位栈溢出问题。
  • Enable thread local storage pointers deletion callbacks
    启用线程本地存储(TLS)指针的删除回调,当任务销毁时自动调用 TLS 指针的清理函数(释放资源)。
  • Enable task pre-deletion hook
    启用任务删除前的钩子函数(vTaskPreDeleteHook()),在任务被删除前执行自定义逻辑(如释放任务持有的资源)。
  • Enable static task clean up hook (DEPRECATED)
    启用静态任务的清理钩子(已过时),用于静态创建的任务(xTaskCreateStatic())销毁时的资源清理。
  • Check that mutex semaphore is given by owner task
    检查互斥锁(mutex)的释放操作是否由持有锁的任务执行(避免其他任务释放不属于自己的锁,导致死锁)。
  • ISR stack size: 1536
    中断服务程序(ISR)的栈大小(1536 字节),用于处理中断时的临时数据存储(栈不足会导致系统崩溃)。
  • Enable backtrace from interrupt to task context
    启用从中断上下文到任务上下文的回溯功能,当发生中断时,可追踪中断前正在运行的任务调用栈(方便调试中断相关问题)。
  • Use float in Level 1 ISR
    允许在 Level 1 中断服务程序中使用浮点数(需硬件支持浮点运算,且会增加中断处理开销)。
  • Tick timer source (Xtensa Only): SYSTIMER 0 (level 1)
    选择 FreeRTOS 系统节拍(tick)的定时器源(仅 Xtensa 架构),此处使用 SYSTIMER 0(系统定时器 0),且为 Level 1 中断(较高优先级,确保节拍计时准确)。
  • Place FreeRTOS functions into Flash
    将 FreeRTOS 函数存储在 Flash 中(而非 RAM),节省 RAM 空间(适用于 RAM 有限的嵌入式设备)。
  • *Tests compliance with Vanilla FreeRTOS port _CRITICAL calls
    检查与「标准 FreeRTOS 端口」中临界区函数(如 taskENTER_CRITICAL())的兼容性,确保临界区操作符合官方规范。
四、Extra(额外配置)
  • Allow external memory as an argument to xTaskCreateStatic (READ HELP)
    允许将外部内存(如 SPI RAM)作为参数传递给 xTaskCreateStatic()(静态创建任务的 API),即任务的栈和控制块可存储在外部内存中(需确保外部内存的访问速度和稳定性)。

有如下更改:

100对应的节拍周期是10ms,1000对应的节拍周期是1ms

7.保存SDK配置后,ctrl+shift+p打开分区表编辑器

这是 ESP-IDF Partition Table Editor(ESP-IDF 分区表编辑器) 的界面,用于可视化配置 ESP32/ESP32-S3 等设备的 Flash 分区表。以下逐行解释核心内容:

1. 界面标题与功能说明

  • ESP-IDF Partition Table Editor
    标题:明确这是 ESP-IDF 框架的分区表可视化工具。
  • Partition Editor can help you to easily edit, build & flash partition table through GUI...
    功能说明:无需手动编辑 CSV 文件,可通过图形界面(GUI)轻松编辑、构建和烧录分区表。

2. 操作按钮(右上角)

  • Select Flash Method
    选择烧录方式:指定如何将分区表烧录到设备(如串口、JTAG 等)。
  • Build
    构建:根据当前配置生成分区表二进制文件(.bin)。
  • Flash
    烧录:将生成的分区表二进制文件烧录到设备的 Flash 中。

3. 分区表配置区域

表格中每行对应一个 Flash 分区,包含以下字段:

字段 1:Name(分区名称)
  • nvs:Non-Volatile Storage(非易失性存储)分区,用于保存设备配置、键值对数据(如 WiFi 密码、自定义参数)。
  • phy_init:PHY(物理层)初始化数据分区,存储 WiFi / 蓝牙射频的校准参数。
  • factory:工厂应用分区,存储默认的固件镜像(设备首次启动或恢复出厂设置时运行的程序)。
  • vfs:Virtual File System(虚拟文件系统)分区,类型为 fat(FAT 文件系统),可用于存储文件(如配置文件、日志)。
  • storage:自定义存储分区,类型为 spiffs(SPIFFS 文件系统),适合嵌入式设备的轻量级文件存储。
字段 2:Type(分区类型)
  • data:数据分区(存储配置、文件系统等非程序数据)。
  • app:应用分区(存储固件程序,可被 Bootloader 加载运行)。
字段 3:Sub Type(子类型)
  • nvs:对应 nvs 分区,标识该数据分区用于 NVS。
  • phy:对应 phy_init 分区,标识该数据分区用于 PHY 初始化。
  • factory:对应 factory 分区,标识该应用分区为工厂固件。
  • fat:对应 vfs 分区,标识该数据分区使用 FAT 文件系统。
  • spiffs:对应 storage 分区,标识该数据分区使用 SPIFFS 文件系统。
字段 4:Offset(分区起始偏移)
  • 如 0x90000xF000 等,表示该分区在 Flash 中的起始地址(相对于 Flash 起始位置)。
  • 需注意分区之间不能重叠,且需符合 Flash 擦除块(erase block)对齐要求。
字段 5:Size(分区大小)
  • 如 0x6000(24KB)、0x1F0000(2,048KB = 2MB)等,表示该分区占用的 Flash 空间大小。
字段 6:Encrypted(加密)
  • 复选框:启用后,该分区数据会被加密(需配合 ESP-IDF 的安全机制,如 Secure Boot、Flash 加密)。
字段 7:×(删除按钮)
  • 点击可删除对应分区的配置。

4. 关键分区的作用

  • nvs:必选分区,用于保存设备运行时的配置(掉电不丢失)。
  • phy_init:必选分区(若使用 WiFi / 蓝牙),存储射频校准参数,确保无线通信稳定。
  • factory:必选分区,存储默认固件,设备启动时 Bootloader 会优先加载此分区的程序。
  • vfs(FAT):可选分区,适合存储文件(如文本、二进制数据),支持电脑直接挂载访问。
  • storage(SPIFFS):可选分区,轻量级文件系统,适合嵌入式设备(无需复杂的文件系统支持)。

5. 实际应用场景

  • 分区表的作用:将 Flash 划分为多个逻辑区域,分别存储程序、配置、文件系统等,让不同功能的数据互不干扰。
  • 修改注意事项
    • 调整分区大小或偏移时,需确保 Flash 总容量足够(如 ESP32-S3-N16R8 的 Flash 是 16MB)。
    • 若新增文件系统分区(如 vfsstorage),需在代码中初始化对应的文件系统(如 esp_vfs_fat_mount() 或 esp_spiffs_mount())。
    • 烧录新分区表后,若覆盖了原有数据分区(如 nvs),可能导致配置丢失,需谨慎操作。

简单说,这个界面让你可视化管理 ESP32 设备的 Flash 分区,像分硬盘区一样把 Flash 划给固件、配置、文件系统等不同功能使用,避免手动写 CSV 配置的麻烦~

分区如下:

8.编译烧写

头文件报红问题:

验证了程序正常,但是这里头文件报红是因为VSCode里找不到组件文件,需要配置一下路径,这个组件的位置其实是在ESP-IDF里带的组件源码

方法一:

(1)可以在文件夹.vscode下手动添加c_cpp_properties.json,或者点击VSCode的右下角的WIN32点击JSON可以得到自动生成的c_cpp_properties.json文件

(2)\"D:/Espressif/frameworks/esp-idf-v5.4/components\"你需要将你安装的ESP-IDF里的组件路径导入VSCode的json配置文件里,然后如果还有波浪线需要使用VSCode的自带的快速修复自动添加路径。

方法二:

按下ctrl+shift+P,输入Add VS Code Configuration Folder,然后VSCode会把我们自动配置路径,以及更好地完善组件文件与用户文件地内联关系,可以自己去看看,了解一下。

结果:

11.bsp_led和main的CMakeLists分别需要补充依赖

bsp_led

# idf_component_register(SRCS \"bsp_led.c\"#  INCLUDE_DIRS \"include\")idf_component_register( SRCS \"bsp_led.c\" # 合并两个源文件 INCLUDE_DIRS \"include\" # 合并头文件目录 REQUIRES driver  # 声明依赖 driver 组件)

main

idf_component_register(SRCS \"ESP32_Example.c\"  INCLUDE_DIRS \".\"  REQUIRES bsp_led )

10.编写点灯测试代码

bsp_led.c

#include #include \"freertos/FreeRTOS.h\"#include \"freertos/task.h\"#include \"driver/gpio.h\"#include \"bsp_led.h\"void bsp_led_init(void){ // 设置GPIO1为输出 gpio_set_direction(GPIO_NUM_1, GPIO_MODE_OUTPUT); // // GPIO配置结构体 // gpio_config_t io_conf = { // .pin_bit_mask = (1ULL<<GPIO_NUM_1), // 选择GPIO1 // .mode = GPIO_MODE_OUTPUT,  // 设置为输出模式 // .pull_up_en = GPIO_PULLUP_ENABLE, // 启用上拉 // .pull_down_en = GPIO_PULLDOWN_DISABLE, // 禁用下拉 // .intr_type = GPIO_INTR_DISABLE // 禁用中断 // }; // // 配置GPIO // esp_err_t ret = gpio_config(&io_conf); // if (ret != ESP_OK) { // printf(\"GPIO配置失败\\n\"); // }}void bsp_led_toggle(void){ // 切换GPIO1的状态 gpio_set_level(GPIO_NUM_1, !gpio_get_level(GPIO_NUM_1)); //vTaskDelay(pdMS_TO_TICKS(1000)); // 延时1秒}

main.c(ESP32_Example.c)

#include \"freertos/FreeRTOS.h\"#include \"freertos/task.h\"// #include \"nvs_flash.h\"#include \"esp_system.h\"#include \"esp_chip_info.h\"// #include \"esp_psram.h\"// #include \"esp_flash.h\"#include \"bsp_led.h\" /* 包含 LED 头文件 *//*** @brief 程序入口* @param 无* @retval 无*/void app_main(void){// esp_err_t ret;// uint32_t flash_size;// esp_chip_info_t chip_info; /* 定义芯片信息结构体变量 */// ret = nvs_flash_init(); /* 初始化 NVS */// if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)// {// ESP_ERROR_CHECK(nvs_flash_erase());// ret = nvs_flash_init();// }// esp_flash_get_size(NULL, &flash_size); /* 获取 FLASH 大小 */// esp_chip_info(&chip_info);// printf(\"内核: cup 数量%d\\n\",chip_info.cores); /* 获取 CPU 内核数并显示 */// /* 获取 FLASH 大小并显示 */// printf(\"FLASH size:%ld MB flash\\n\",flash_size / (1024 * 1024));// /* 获取 PARAM 大小并显示 */// printf(\"PSRAM size: %d bytes\\n\", esp_psram_get_size());bsp_led_init(); /* 初始化 LED */while(1){printf(\"Hello-ESP32\\r\\n\");bsp_led_toggle(); /* 切换 LED 状态 */vTaskDelay(1000);}}

参考链接:
       【正点原子】手把手教你学ESP32S3快速入门
       ESP32的ESP-IDF在VScode工程下,头文件标红警告、报错、无法跳转