ESP32-S3-工程管理

文章目录

  • 一、创建工程
    • [   1、从模版创建工程](#   1、从模版创建工程)
      • [     1.新项目向导](#     1.新项目向导)
      • [     2.选择 ESP-IDF 的版本。](#     2.选择 ESP-IDF 的版本。)
      • [     3.选择模版](#     3.选择模版)
      • [     4.项目设置](#     4.项目设置)
      • [     5.打开新项目](#     5.打开新项目)
    • [   2、编写代码](#   2、编写代码)
      • [     1.main.c 文件:](#     1.main.c 文件:)
      • [     2.代码导航与语法高亮](#     2.代码导航与语法高亮)
      • [     3.运行 idf.py reconfigure 任务](#     3.运行 idf.py reconfigure 任务)
    • [   3、构建并烧录代码](#   3、构建并烧录代码)
      • [     1.配置烧录选项](#     1.配置烧录选项)
      • [     2.一键自动构建烧录](#     2.一键自动构建烧录)
      • [     3.执行结果](#     3.执行结果)
    • [   4、代码解析](#   4、代码解析)
      • [     1.首先包含所需的库:](#     1.首先包含所需的库:)
      • [     2.GPIO 引脚定义](#     2.GPIO 引脚定义)
      • [     3.GPIO 初始化](#     3.GPIO 初始化)
      • [     4.无限循环 while(1)](#     4.无限循环 while(1))
  • 二、使用组件
    • [   1、ESP-IDF 组件概述​](#   1、ESP-IDF 组件概述)
    • [   2、组件类型​](#   2、组件类型)
      • [     1.内置组件(Core/Built-in Components):](#     1.内置组件(Core/Built-in Components):)
      • [     2.项目组件(Project Components):](#     2.项目组件(Project Components):)
      • [     3.外部组件(External/Managed Components):](#     3.外部组件(External/Managed Components):)
    • [   3、组件结构​](#   3、组件结构)
      • [     1.源代码](#     1.源代码)
      • [     2.头文件](#     2.头文件)
      • [     3.CMakeLists.txt](#     3.CMakeLists.txt)
      • [     4.idf_component.yml](#     4.idf_component.yml)
    • [   4、项目中的组件​](#   4、项目中的组件)
      • [     1.main/](#     1.main/)
      • [     2.components/](#     2.components/)
      • [     3.managed_components/](#     3.managed_components/)
      • [     4.idf_component.yml](#     4.idf_component.yml)
      • [     5.dependencies.lock](#     5.dependencies.lock)
    • [   5、使用内置 GPIO 组件​](#   5、使用内置 GPIO 组件)
      • [     1.搭建电路​](#     1.搭建电路)
      • [     2.包含 GPIO 库​](#     2.包含 GPIO 库)
      • [     3.示例代码​](#     3.示例代码)
      • [     4.构建并烧录代码​](#     4.构建并烧录代码)
      • [     5.代码解析​](#     5.代码解析)
    • [   6、使用外部 Button 组件​](#   6、使用外部 Button 组件)
      • [     1.搭建电路​](#     1.搭建电路)
      • [     2.包含 button 组件​](#     2.包含 button 组件)
      • [     3.示例代码​](#     3.示例代码)
      • [     4.构建并烧录代码​](#     4.构建并烧录代码)
      • [     5.代码解析​](#     5.代码解析)
    • [   7、自定义组件​](#   7、自定义组件)
      • [     1.VS Code 命令创建组件](#     1.VS Code 命令创建组件)
      • [     2.idf.py命令创建组件](#     2.idf.py命令创建组件)
      • [     3.在main/CMakeLists.txt加入组件目录](#     3.在main/CMakeLists.txt加入组件目录)
      • [     4.清理缓存](#     4.清理缓存)
      • [     5.在main目录中添加自定义.c.h文件](#     5.在main目录中添加自定义.c.h文件)
    • [   8、板级支持包 (BSP)​](#   8、板级支持包 (BSP))
  • 三、工程目录
    • [   1、标准工程目录](#   1、标准工程目录)
    • [   2、顶层目录](#   2、顶层目录)
      • [     1. 顶层 CMakeLists.txt](#     1. 顶层 CMakeLists.txt)
      • [     2. sdkconfig](#     2. sdkconfig)
      • [     3. dependencies.lock](#     3. dependencies.lock)
      • [     4. build/ 编译目录](#     4. build/ 编译目录)
      • [     5. managed_components/](#     5. managed_components/)
      • [     6. .vscode/settings.json](#     6. .vscode/settings.json)
    • [   3、main主目录](#   3、main主目录)
      • [     1. main.c](#     1. main.c)
      • [     2. main/CMakeLists.txt](#     2. main/CMakeLists.txt)
      • [     3. main 内自定义.c/.h](#     3. main 内自定义.c/.h)
    • [   4、components 自定义组件目录](#   4、components 自定义组件目录)
    • [   5、managed_components外部组件目录](#   5、managed_components外部组件目录)
      • [     1. 手动添加远程组件(自动写入 yml 并下载)](#     1. 手动添加远程组件(自动写入 yml 并下载))
      • [     2. 更新所有第三方组件至符合版本区间的最新版](#     2. 更新所有第三方组件至符合版本区间的最新版)
      • [     3. 清空所有下载的第三方组件(缓存错乱时)](#     3. 清空所有下载的第三方组件(缓存错乱时))
      • [     4. 查看当前工程所有组件依赖树](#     4. 查看当前工程所有组件依赖树)

一、创建工程

   1、从模版创建工程

     1.新项目向导

       打开 VS Code,点击 ESP-IDF 扩展,在 "Advanced" 中打开 "新项目向导"。

      

     2.选择 ESP-IDF 的版本。

      

     3.选择模版

       在 "ESP-IDF Templates" 中选择 "sample_project" 模板,然后点击 "Create project using template sample_project"。

      

     4.项目设置

       设置项目名称,存放位置以及相关参数。开发板相关参数可以在创建项目后修改。

       设置完成后点击 "Create Project"。

       注意:

         项目路径中不要包含空格、中文或特殊符号。

      

     5.打开新项目

       点击 "Open Project" 打开新项目。

      

   2、编写代码

     ESP-IDF 会为项目生成许多文件和文件夹。

     1.main.c 文件:

c 复制代码
			#include <stdio.h>
			
			#include "driver/gpio.h"
			#include "freertos/FreeRTOS.h"
			#include "freertos/task.h"
			
			static const gpio_num_t led_pin = GPIO_NUM_7;
			
			void app_main(void)
			{
			    gpio_reset_pin(led_pin);                       // 重置引脚
			    gpio_set_direction(led_pin, GPIO_MODE_OUTPUT); // 设置引脚为输出模式
			
			    while (1)
			    {
			        gpio_set_level(led_pin, 1);      // 设置引脚为高电平,点亮 LED
			        printf("LED state: ON\n");       // 打印 LED 的当前状态
			        vTaskDelay(pdMS_TO_TICKS(1000)); // 任务延时 1000 毫秒 (1秒)
			
			        gpio_set_level(led_pin, 0);      // 设置引脚为低电平,熄灭 LED
			        printf("LED state: OFF\n");      // 打印 LED 的当前状态
			        vTaskDelay(pdMS_TO_TICKS(1000)); // 再次任务延时 1000 毫秒 (1秒)
			    }
			}

     2.代码导航与语法高亮

       对于代码导航和 C/C++ 语法高亮,推荐使用 Microsoft C/C++ 扩展。

       安装该插件后,VS Code 通常能自动进行代码高亮并识别宏定义、库变量等。

     3.运行 idf.py reconfigure 任务

       在编写代码过程中相关库出现红色波浪线提示未定义等问题,一般构建一次项目即可解决,也可以通过下面的方法修复:

         C/C++ 语言扩展依赖于一个名为 compile_commands.json 的文件,该文件位于项目构建目录中。

         可以使用 ESP-IDF: 运行 idf.py reconfigure 任务 来生成此文件。

         使用快捷键 Ctrl + Shift + P 打开 VS Code 命令面板。然后运行 ESP-IDF: 运行 idf.py reconfigure 任务。

      

   3、构建并烧录代码

     1.配置烧录选项

       首先,在构建和烧录之前,请务必检查并设置正确的目标设备、串口和烧录方式。

      

     2.一键自动构建烧录

       点击 工具栏火焰图标 一键构建烧录监视 一键自动依次执行构建、烧录和监视这三个步骤。

     3.执行结果

       烧录完成后,您会看到 LED 开始闪烁。同时,串口监视器会启动并输出如下日志信息:

      

   4、代码解析

     1.首先包含所需的库:

c 复制代码
			#include "driver/gpio.h"
			#include "freertos/FreeRTOS.h"
			#include "freertos/task.h"
			
			stdio.h: C 语言标准输入输出库,我们用它来调用 printf 函数向串口打印信息。
			driver/gpio.h: ESP-IDF 提供的 GPIO 驱动库,包含了配置和操作 GPIO 引脚所需的函数,例如设置引脚方向、读写引脚电平等。
			freertos/FreeRTOS.h 和 freertos/task.h: ESP-IDF 使用 FreeRTOS 作为其实时操作系统。这两个头文件提供了操作系统核心和任务管理相关的 API。在这里,我们主要使用 vTaskDelay 函数来实现精确的延时。

     2.GPIO 引脚定义

c 复制代码
			static const gpio_num_t led_pin = GPIO_NUM_7;
			
			这行代码定义了一个常量 led_pin 来表示 LED 所连接的 GPIO 引脚号。
			gpio_num_t 是 ESP-IDF 中用于表示 GPIO 编号的枚举类型。
			GPIO_NUM_7 是该枚举中的一个取值,表示编号为 7 的通用 IO 引脚(GPIO7)。从可读性与类型安全角度,建议使用 GPIO_NUM_7 而不是直接写字面值 7。
			备注
			不同芯片对 GPIO7 的可用性与限制不同,请检查所用你的开发板的引脚定义。

     3.GPIO 初始化

c 复制代码
			gpio_reset_pin(led_pin);                       // 重置引脚
			gpio_set_direction(led_pin, GPIO_MODE_OUTPUT); // 设置引脚为输出模式
			在 app_main 函数内部,首先对 GPIO 引脚进行初始化设置。
			gpio_reset_pin(led_pin);: 在配置引脚前先将其重置为默认状态,可以避免一些意外问题。
			gpio_set_direction(led_pin, GPIO_MODE_OUTPUT);: 这行代码将选定的 led_pin (GPIO 7) 设置为输出模式。

     4.无限循环 while(1)

c 复制代码
			在 FreeRTOS 任务函数中,通常会使用 while(1) 实现任务的持续运行。这样任务会一直被 FreeRTOS 调度器管理,除非主动调用 vTaskDelete() 删除任务,否则不会退出。无限循环配合 vTaskDelay() 等函数,可以让任务周期性地执行操作,同时让出 CPU 给其他任务,实现多任务并发。
			while (1)
			{
			    gpio_set_level(led_pin, 1);      // 设置引脚为高电平,点亮 LED
			    printf("LED state: ON\n");       // 打印 LED 的当前状态
			    vTaskDelay(pdMS_TO_TICKS(1000)); // 任务延时 1000 毫秒 (1秒)
			
			    gpio_set_level(led_pin, 0);      // 设置引脚为低电平,熄灭 LED
			    printf("LED state: OFF\n");      // 打印 LED 的当前状态
			    vTaskDelay(pdMS_TO_TICKS(1000)); // 再次任务延时 1000 毫秒 (1秒)
			}
			gpio_set_level(led_pin, 1);: 
				设置 led_pin 引脚的输出高电平。
			printf():
				ESP-IDF 支持标准 C 语言的 printf(),可将信息输出到串口终端,便于调试和状态监控。
			vTaskDelay(pdMS_TO_TICKS(1000));:
				该函数让当前 FreeRTOS 任务延时指定的 tick 数,延时期间任务进入阻塞态,释放 CPU 使用权。
				pdMS_TO_TICKS(1000) 宏将 1000 毫秒转换为 tick 数,确保延时为 1000 毫秒,此过程是非阻塞的。

二、使用组件

   1、ESP-IDF 组件概述​

    

     ESP-IDF 采用组件化设计,将系统的各项功能(如操作系统、网络协议栈、驱动、外设支持等)划分为独立的"组件"(Component)。

     每个组件是一个可复用、独立的代码包,专注于实现某一特定功能。

     在项目构建时,组件会被编译为静态库,并由主应用程序或其他组件进行链接和调用。

     在此架构基础上,开发者可以灵活地添加自定义组件或集成第三方组件(如特定的云服务、协议或驱动)。

     通过将外部组件与 ESP-IDF 的内部核心组件相结合,可实现项目功能的扩展与定制,进而达成项目整体的模块化与高效复用。

     带来的优势包括:清晰的分层与依赖管理、代码复用、易于扩展与更新,从而降低项目复杂度,加快开发迭代。

   2、组件类型​

     在 ESP-IDF 项目中,组件主要分为以下三类:

     1.内置组件(Core/Built-in Components):

       这些是 ESP-IDF 框架自带的核心组件,位于 ESP-IDF 安装目录下的 components 文件夹中,提供底层驱动、网络协议栈、FreeRTOS 操作系统等基础功能。

       开发者可以直接在代码中包含其头文件并使用,无需额外配置。

     2.项目组件(Project Components):

       这些是开发者在项目根目录下的 components 文件夹中创建的组件,适合存放项目特有、可复用的功能模块,有助于保持主逻辑 main 的整洁和项目的模块化。

     3.外部组件(External/Managed Components):

       这些组件由社区或第三方开发者创建,并发布到 ESP-IDF 组件注册表 (ESP Component Registry)。

       可以通过 IDF 组件管理器 自动下载和集成到项目中,下载后会存放在项目根目录下的 managed_components 文件夹中。

   3、组件结构​

     一个完整的 ESP-IDF 组件通常包含以下内容:

     1.源代码

       组件实现的核心功能代码文件。

     2.头文件

       对外暴露的接口声明,供其他组件或主程序调用。

     3.CMakeLists.txt

       定义源代码和头文件的编译方式。

       声明组件依赖关系。

       注册组件到构建系统。

       配置可选特性。

       作为 CMake 构建描述文件,指示编译器如何编译、链接和构建该组件。

     4.idf_component.yml

       组件管理器描述文件,列出该组件依赖的其他组件及其版本信息。ESP-IDF 组件管理器会根据此文件自动下载和集成所需依赖,确保依赖关系满足。

   4、项目中的组件​

     一个包含组件的项目的目录结构示例如下:

c 复制代码
			myProject/
			├── CMakeLists.txt
			├── sdkconfig
			├── dependencies.lock
			├── main/
			│   ├── CMakeLists.txt
			│   ├── main.c
			│   ├── src1.c
			│   └── idf_component.yml
			├── components/
			│   ├── component1/
			│   │   ├── CMakeLists.txt
			│   │   ├── Kconfig
			│   │   └── src1.c
			│   └── component2/
			│       ├── CMakeLists.txt
			│       ├── Kconfig
			│       ├── src1.c
			│       └── include/
			│           └── component2.h
			├── managed_components/
			│   └── namespace__component-name/
			│       ├── CMakeLists.txt
			│       ├── idf_component.yml
			│       ├── src1.c
			│       └── include/
			│           └── src1.h
			└── build/

     1.main/

       项目主组件目录,包含项目的主要源代码。

       main 目录下通常有自己的 CMakeLists.txt 和可选的 idf_component.yml,用于声明主组件的依赖关系。

       应用程序必须包含一个 main 组件(名称可更改),这是保存应用程序逻辑的主要组件。

     2.components/

       项目自定义组件目录。每个子目录为一个组件,包含源代码、头文件、CMakeLists.txt、Kconfig 等。

       可用于组织可复用代码或引入第三方组件。

       若有同名组件,优先使用 components/ 下的版本。

     3.managed_components/

       由 IDF 组件管理器 自动创建,用于存放通过组件管理器下载的托管组件。

       每个托管组件通常包含 idf_component.yml,定义组件元数据和依赖关系。

       请勿手动修改该目录内容,如需修改,可将组件复制到 components/ 目录下。

     4.idf_component.yml

       组件管理器描述文件,声明组件的元数据及其依赖项。

       可存在于 main/、components/ 下的每个组件目录,以及 managed_components/ 下的托管组件目录。

       该文件是可选的,仅在需要声明依赖时才需要。

     5.dependencies.lock

       由 IDF 组件管理器 自动生成,记录当前项目使用的所有托管组件及其精确版本。

       请勿手动修改,只有当项目中存在 idf_component.yml 文件时才会生成该文件。

   5、使用内置 GPIO 组件​

       通过使用 ESP-IDF 内置的 esp_driver_gpio 组件 来读取按钮的电平状态。

     1.搭建电路​

       需要使用的器件有:

         按钮 * 1

         面包板 * 1

         导线

         ESP32 开发板

       ESP32-S3 引脚:

         3v3<-按钮->gpio7

     2.包含 GPIO 库​

       创建一个项目。

       在包含 ESP-IDF 内置组件前,请先查看相应组件的文档。

       根据文档中的指引完成以下步骤:

       首先在 main.c 中包含头文件:

         #include "driver/gpio.h"

       然后在 main/CMakeLists.txt 中声明 esp_driver_gpio 组件:

         idf_component_register(SRCS "main.c"

         INCLUDE_DIRS "."

         REQUIRES esp_driver_gpio)

     3.示例代码​

       将以下代码复制到 main/main.c 中:

c 复制代码
			#include <stdio.h>
			
			#include "driver/gpio.h"
			#include "freertos/FreeRTOS.h"
			#include "freertos/task.h"
			
			#define BUTTON_GPIO GPIO_NUM_7 // 按钮连接的 GPIO 引脚
			
			void app_main(void)
			{
			    // 配置 GPIO
			    gpio_config_t io_conf = {
			        .pin_bit_mask = (1ULL << BUTTON_GPIO), // 选中 GPIO7
			        .mode = GPIO_MODE_INPUT,               // 设置为输入模式
			        .pull_up_en = GPIO_PULLUP_ENABLE,      // 启用内部上拉电阻
			        .pull_down_en = GPIO_PULLDOWN_DISABLE, // 禁用内部下拉电阻
			        .intr_type = GPIO_INTR_DISABLE         // 禁用中断
			    };
			    gpio_config(&io_conf); // 应用配置
			
			    // 主循环:持续读取按钮状态
			    while (1) {
			        int level = gpio_get_level(BUTTON_GPIO); // 读取 GPIO 电平
			        printf("Button value: %d\n", level);
			        vTaskDelay(pdMS_TO_TICKS(20)); // 延时 20 毫秒,避免独占 CPU
			    }
			}

     4.构建并烧录代码​

       配置烧录选项:

         检查并设置正确的目标设备、串口和烧录方式。

       烧录:

         一键自动依次执行构建、烧录和监视这三个步骤。

       执行结果:

         烧录完成后,串口监视器会开始打印信息。

         当按钮未按下时,由于内部上拉电阻的作用,GPIO7 读取到高电平,串口监视器输出 Button value: 1。

         当按钮被按下时,GPIO7 被连接到 GND,读取到低电平,串口监视器输出 Button value: 0。

      

     5.代码解析​

c 复制代码
			包含头文件:
				#include "driver/gpio.h"
				#include "freertos/FreeRTOS.h"
				#include "freertos/task.h"
				driver/gpio.h: 包含了配置和操作 GPIO 所需的函数声明和类型定义。
				freertos/FreeRTOS.h 和 freertos/task.h: 提供 FreeRTOS 操作系统 API,我们使用 vTaskDelay 来实现非阻塞延时。
			定义 GPIO 引脚:
				#define BUTTON_GPIO GPIO_NUM_7
				使用宏定义将按钮连接的引脚(GPIO7)赋予一个有意义的名称,便于阅读和修改。
			配置 GPIO:
				gpio_config_t io_conf = {
				    .pin_bit_mask = (1ULL << BUTTON_GPIO),
				    .mode = GPIO_MODE_INPUT,
				    .pull_up_en = GPIO_PULLUP_ENABLE,
				    .pull_down_en = GPIO_PULLDOWN_DISABLE,
				    .intr_type = GPIO_INTR_DISABLE
				};
				gpio_config(&io_conf);
				
				使用 gpio_config_t 结构体来一次性配置所有参数。
				.mode = GPIO_MODE_INPUT: 将引脚设置为输入模式,以读取外部电平。
				.pull_up_en = GPIO_PULLUP_ENABLE: 启用内部上拉电阻。当按钮未按下时,此电阻将引脚电平拉高至 VCC,确保一个稳定的默认高电平状态,避免引脚悬空。
				.pin_bit_mask: 指定要配置的引脚,通过位移操作 (1ULL << BUTTON_GPIO) 来选中 GPIO7。表达式 (1ULL << BUTTON_GPIO) 是一种高效的位操作。1ULL 代表一个 64 位无符号长整型 1,将其左移 BUTTON_GPIO(即 7)位,会生成一个仅在第 7 位为 1 的位掩码,从而精确地选中 GPIO7。
			主循环:
				while (1) {
				    int level = gpio_get_level(BUTTON_GPIO);
				    printf("Button value: %d\n", level);
				    vTaskDelay(pdMS_TO_TICKS(20));
				}
				
				while(1) 循环持续执行,不断检测按钮状态。
				gpio_get_level(BUTTON_GPIO): 读取指定 GPIO 引脚的当前电平状态(0 或 1)。
				vTaskDelay(...): 让当前任务暂停一小段时间(20 毫秒),将 CPU 时间让给其他任务。这在循环中至关重要,可以防止任务独占 CPU 资源,是 FreeRTOS 编程的基本实践。

   6、使用外部 Button 组件​

     1.搭建电路​

       需要使用的器件有:

         按钮 * 1

         面包板 * 1

         导线

         ESP32 开发板

       ESP32-S3 引脚:

         3v3<-按钮->gpio7

     2.包含 button 组件​

       对于外部库(button),使用组件管理器和注册表。

       1)创建一个项目。

       2)前往 组件注册表(ESP Component Registry)。

         https://components.espressif.com/

       3)搜索 "button" 组件(espressif/button)

         espressif/button

       4)复制右侧的指令:

         idf.py add-dependency "espressif/button^4.2.0"

        

       5)点击 打开 ESP-IDF 终端,粘贴命令。

        

         注意:

         添加依赖后,需要执行一次完整清理,使旧的构建缓存失效。

         下次构建时,构建系统会重新运行 CMake 配置,自动下载新组件并注册其头文件路径。

         在 VS Code 中执行 > ESP-IDF: Full Clean Project,或在终端执行:

           idf.py fullclean

       6)包含头文件

         在代码中包含相应的头文件并调用组件文档和文件夹中提供的函数。

     3.示例代码​

c 复制代码
			#include <stdio.h>
			
			#include "driver/gpio.h"
			#include "freertos/FreeRTOS.h"
			#include "freertos/task.h"
			#include "esp_log.h"
			#include "iot_button.h"
			#include "button_gpio.h"
			
			#define BUTTON_GPIO GPIO_NUM_7
			#define BUTTON_ACTIVE_LEVEL 0
			
			static const char *TAG = "button_example";
			
			// 单击回调函数
			static void button_single_click_cb(void *arg, void *usr_data)
			{
			    ESP_LOGI(TAG, "BUTTON_SINGLE_CLICK");
			}
			
			// 双击回调函数
			static void button_double_click_cb(void *arg, void *usr_data)
			{
			    ESP_LOGI(TAG, "BUTTON_DOUBLE_CLICK");
			}
			
			void app_main(void)
			{
			    // 定义按键配置
			    const button_config_t btn_cfg = {0};
			    const button_gpio_config_t btn_gpio_cfg = {
			        .gpio_num = BUTTON_GPIO,             // 按键连接的 GPIO 编号
			        .active_level = BUTTON_ACTIVE_LEVEL, // 有效电平(0 为低电平有效,1 为高电平有效)
			    };
			
			    // 创建按键句柄
			    button_handle_t gpio_btn = NULL;
			    esp_err_t ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_cfg, &gpio_btn);
			    if (ret != ESP_OK)
			    {
			        ESP_LOGE(TAG, "Button create failed");
			        return;
			    }
			
			    // 注册单击事件
			    iot_button_register_cb(gpio_btn, BUTTON_SINGLE_CLICK, NULL, button_single_click_cb, NULL);
			
			    // 注册双击事件
			    iot_button_register_cb(gpio_btn, BUTTON_DOUBLE_CLICK, NULL, button_double_click_cb, NULL);
			
			    // 主循环
			    while (1)
			    {
			        vTaskDelay(pdMS_TO_TICKS(1000));
			    }
			}

     4.构建并烧录代码​

       配置烧录选项:

         首先,在构建和烧录之前,请务必检查并设置正确的目标设备、串口和烧录方式。

       烧录:

         点击 一键自动依次执行构建、烧录和监视这三个步骤。

       执行结果:

         烧录完成后,串口监视器会开始打印信息。

         当单击按钮时,监视器将输出:I (xxxx) button_example: BUTTON_SINGLE_CLICK

         当快速双击按钮时,监视器将输出:I (xxxx) button_example: BUTTON_DOUBLE_CLICK

      

     5.代码解析​

c 复制代码
			espressif/button 组件支持检测多种按键事件,如按下、释放、单击、双击、连续点击、长按开始、长按保持和长按释放等,并可为每种事件注册回调函数。
			每个按键事件都可以注册一个回调函数。
			当事件发生时,组件会自动调用对应的回调函数,具有高效性和实时性,不会丢失事件。
			包含头文件:
				#include "iot_button.h"
				#include "button_gpio.h"
				iot_button.h 提供按键组件的核心 API 和事件定义。
				button_gpio.h 提供 GPIO 按键的特定配置结构体和创建函数。该组件还支持 ADC 按键和矩阵按键。
			定义回调函数:
				// 单击回调函数
				static void button_single_click_cb(void *arg, void *usr_data)
				{
				    ESP_LOGI(TAG, "BUTTON_SINGLE_CLICK");
				}
				// 双击回调函数
				static void button_double_click_cb(void *arg, void *usr_data)
				{
				    ESP_LOGI(TAG, "BUTTON_DOUBLE_CLICK");
				}
				针对不同的按键事件(如单击、双击)定义专门的回调函数。当组件检测到相应事件时,会自动调用这些函数。这里我们通过日志打印出检测到的事件信息。
			配置并创建 GPIO 按键:
				const button_config_t btn_cfg = {0};
				const button_gpio_config_t btn_gpio_cfg = {
				    .gpio_num = BUTTON_GPIO,
				    .active_level = BUTTON_ACTIVE_LEVEL,
				};
				button_handle_t gpio_btn = NULL;
				esp_err_t ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_cfg, &gpio_btn);
				if (ret != ESP_OK)
				{
				    ESP_LOGE(TAG, "Button create failed");
				    return;
				}
				button_config_t 用于通用配置,button_gpio_config_t 用于 GPIO 相关参数。
				使用 iot_button_new_gpio_device() 创建 GPIO 按键实例。
			注册事件回调:
				iot_button_register_cb(gpio_btn, BUTTON_SINGLE_CLICK, NULL, button_single_click_cb, NULL);
				iot_button_register_cb(gpio_btn, BUTTON_DOUBLE_CLICK, NULL, button_double_click_cb, NULL);
				iot_button_register_cb() 函数的作用是将一个事件和一个回调函数"绑定"起来。
				第一个参数是按键句柄。
				第二个参数是事件类型,例如 BUTTON_SINGLE_CLICK(单击)或 BUTTON_DOUBLE_CLICK(双击)。更多事件请参考:按键事件。
				第三个参数是 event_args,用于传递事件参数。对于普通事件可传入 NULL;对于需要自定义的特殊事件(如长按时长、多次点击等),则需传入相应的参数。
				第四个参数为回调函数。
				第五个参数为用户数据指针。
			主循环:
				此组件的事件检测和回调函数调用是在其内部任务(由 FreeRTOS 软定时器驱动)中完成的,因此无需在主循环 while(1) 中编写任何轮询代码。
				保留一个空的 while(1) 循环是为了让 app_main() 不会提前返回,以保证主任务持续运行,系统稳定可靠。

   7、自定义组件​

     1.VS Code 命令创建组件

       使用快捷键 Ctrl + Shift + P 打开 VS Code 命令面板。然后运行 > ESP-IDF: 创建新 ESP-IDF 组件。

      

     2.idf.py命令创建组件

       idf.py create-component <组件名>

       idf.py create-component Test2

       进入组件目录,否则就会建立在当前目录下。

     3.在main/CMakeLists.txt加入组件目录

       idf_component_register(SRCS "main.c"

         INCLUDE_DIRS "."

         INCLUDE_DIRS ".../components/Test/include" //组件Test头文件目录

         INCLUDE_DIRS ".../components/Test2/include"//组件Test1头文件目录

         REQUIRES esp_driver_gpio)

     4.清理缓存

       每次创建或下载新组件后,都需要执行一次完整清理,使旧的构建缓存失效。

       下次构建时,构建系统会重新运行 CMake 配置,正确识别并集成新组件。

       在 VS Code 中执行 > ESP-IDF: Full Clean Project,或在终端执行:

         idf.py fullclean

     5.在main目录中添加自定义.c.h文件

       main文件中直接添加头文件即可使用。

c 复制代码
			s3_demo/
			├─ main/
			│  ├─ main.c          // 主程序、FreeRTOS任务入口
			│  ├─ led_driver.c    // 自定义源文件
			│  └─ led_driver.h    // 对应头文件
			├─ CMakeLists.txt     // 工程编译配置
			└─ sdkconfig

   8、板级支持包 (BSP)​

     板级支持包(BSP,Board Support Package)是在 ESP-IDF 中以组件形式提供的、针对特定开发板的硬件抽象与初始化包。

     它封装了板载外设(如显示屏、触摸、音频编解码器、SD 卡、LED、按钮等)的引脚配置与驱动初始化,提供统一的 API,便于快速上手、跨板复用代码并减少配置错误。

     像任何 ESP-IDF 组件一样,BSP 可以通过组件管理器使用 idf_component.yml 集成到项目中。

三、工程目录

   1、标准工程目录

c 复制代码
		esp32s3_demo/                     # 工程根目录(VSCode必须打开此文件夹)
		├─ .vscode/                       # VSCode IDE配置,不参与编译
		│  ├─ settings.json               # EIM路径、目标芯片、串口、插件参数
		│  ├─ launch.json                 # OpenOCD/JTAG调试配置
		│  └─ extensions.json             # 推荐插件清单
		├─ components/                    # 自定义本地组件(模块化开发核心)
		│  └─ led_driver/
		│     ├─ idf_component.yml         # 组件版本、依赖、芯片兼容声明
		│     ├─ CMakeLists.txt            # 编译注册脚本
		│     ├─ led_driver.c              # 驱动实现
		│     └─ led_driver.h              # 对外头文件
		├─ main/                          # 程序唯一入口目录(强制存在)
		│  ├─ main.c                      # app_main() 上电入口
		│  ├─ custom_func.c               # main内自定义源文件
		│  ├─ custom_func.h
		│  └─ CMakeLists.txt              # main编译脚本(高频修改)
		├─ build/                         # 编译产物(自动生成,fullclean可清空)
		│  ├─ *.bin                       # 烧录固件:bootloader、分区表、app.bin
		│  ├─ *.elf                       # JTAG调试镜像
		│  ├─ ninja构建缓存、obj目标文件
		│  └─ config/                     # sdkconfig编译缓存
		├─ managed_components/            # 组件管理器自动拉取的第三方远程组件
		├─ sdkconfig                      # menuconfig全局配置存储文件(日志/USB-JTAG/FreeRTOS)
		├─ sdkconfig.defaults             # 工程默认配置模板,批量量产统一参数
		├─ dependencies.lock              # 第三方组件版本锁定文件(v6新增强化依赖管理)
		├─ CMakeLists.txt                 # 工程顶层编译入口(固定模板)
		└─ README.md                      # 工程说明文档

   2、顶层目录

     1. 顶层 CMakeLists.txt

       v6.0.1 模板无改动,固定写法,仅修改工程名:

         cmake_minimum_required(VERSION 3.16)

         include($ENV{IDF_PATH}/tools/cmake/project.cmake)

         project(esp32s3_demo) # 工程名

       作用:加载 IDF 编译工具链,定义固件输出名称。

     2. sdkconfig

       v6.0.1 日志、USB-JTAG、FreeRTOS、双核调度、PSRAM 全部配置保存在此;

       禁止手动编辑,统一使用 idf.py menuconfig 修改;

       切换 IDF 版本 / 芯片型号建议删除,重建配置避免缓存冲突。

     3. dependencies.lock

       v5.x 无强制锁文件,v6.0.1 组件管理器强制支持版本锁定;

       执行 idf.py update-dependencies 生成,多人协作、量产固定第三方组件版本,防止自动升级导致编译报错。

     4. build/ 编译目录

       v6 编译逻辑优化,缓存结构调整:

       一键清理:idf.py fullclean,完整删除 build 文件夹;

       核心烧录文件:build/esp32s3_demo.bin(合并分区表 + bootloader + 应用);

       .elf 文件:USB-JTAG 硬件断点调试必备。

     5. managed_components/

       v6 组件管理器大幅优化,idf.py add-dependency 拉取的第三方库全部存放于此;

       依赖规则由 components/xxx/idf_component.yml 定义。

     6. .vscode/settings.json

       存储 idf.eimIdfJsonPath 路径、默认芯片esp32s3、串口 COM;

       报错 Cannot read properties of undefined (reading 'idfPath') 根源:路径错误 / 未打开工程文件夹 / EIM 未激活 IDF。

   3、main主目录

     1. main.c

       唯一入口函数 void app_main(void),芯片上电自动执行;

       所有硬件初始化、FreeRTOS 任务创建、业务逻辑起点。

     2. main/CMakeLists.txt

       核心函数 idf_component_register(),新增.c必须写入SRCS,否则报undefined reference:

         idf_component_register(

         SRCS "main.c" "custom_func.c"

         INCLUDE_DIRS "."

         REQUIRES driver freertos log usb esp_usb_jtag

         )

       参数说明:

         SRCS:参与编译的所有.c源文件;

         INCLUDE_DIRS:头文件搜索路径,.代表当前 main 文件夹;

         REQUIRES:依赖 IDF 内置组件(v6 内置组件名无变更)。

     3. main 内自定义.c/.h

       适合小型工程;多外设、多任务大型项目推荐拆分至components。

   4、components 自定义组件目录

     每个独立功能模块单独文件夹,配套 4 个文件:

     xxx.c:函数实现,内部变量加static私有化;

     xxx.h:对外接口、宏、结构体,全局可#include "xxx.h";

     CMakeLists.txt:编译注册,控制源码、头文件、本地依赖;

     idf_component.yml:v6 强化组件管理,声明版本、芯片兼容、远程依赖。

   5、managed_components外部组件目录

     managed_components 是 ESP Component Manager(ECM 组件管理器) 自动创建、自动维护的第三方组件存放目录,完全自动生成,禁止手动修改、手动新增文件。

     1. 手动添加远程组件(自动写入 yml 并下载)

       idf.py add-dependency esp_lcd^1.4.5

       执行后:

         自动在对应组件的 idf_component.yml 添加依赖;

         自动下载代码到 managed_components/esp_lcd;

         更新 dependencies.lock。

     2. 更新所有第三方组件至符合版本区间的最新版

       idf.py update-dependencies

     3. 清空所有下载的第三方组件(缓存错乱时)

       Remove-Item -Recurse -Force managed_components

       idf.py fullclean

       idf.py build

     4. 查看当前工程所有组件依赖树

       idf.py component-deps

相关推荐
智购科技无人售货机厂家2 小时前
2026自动售货机连接器选型指南:从IP等级到插拔寿命的工程实践~YH
单片机·嵌入式硬件
Jason_zhao_MR4 小时前
电能质量监测为什么需要PTP精确时钟同步
linux·单片机·嵌入式硬件·嵌入式
Freak嵌入式5 小时前
RP2040 PIO 编程模型与状态机原理:从硬件架构到工作逻辑全解析
java·大数据·开发语言·单片机·嵌入式硬件·硬件架构
Messy create5 小时前
【BMS-AFE-断路检测】
单片机·嵌入式硬件·能源
恶魔泡泡糖5 小时前
stm32F103C8T6标准库DWT基础应用1
stm32·单片机·嵌入式硬件
LCG元5 小时前
STM32L4 LPUART 实战:Stop2 模式下低功耗串口唤醒与不定长接收
stm32·单片机·嵌入式硬件
星河单片机5 小时前
STM32+VK2828U7G5模块GPS定位+NMEA解析
stm32·单片机·嵌入式硬件
白搞电子5 小时前
ESP-Mosaico 掌上游戏开发:LVGL 抛硬币动画、音频混音与 BMI270 摇晃触发
单片机·嵌入式硬件·物联网·游戏·音视频
新晨单片机设计6 小时前
S004A-基于STM32单片机密码锁【Proteus仿真+Keil程序+原理图】
stm32·单片机·proteus