Skip to content

第一章:芯片认知与环境搭建

1.1 ESP32-S3 架构概览

核心架构

┌─────────────────────────────────────────────────────┐
│                   ESP32-S3 芯片                      │
│                                                     │
│  ┌──────────────┐    ┌──────────────┐               │
│  │  CPU Core 0  │    │  CPU Core 1  │  Xtensa LX7   │
│  │  (PRO_CPU)   │    │  (APP_CPU)   │  最高 240MHz  │
│  └──────┬───────┘    └──────┬───────┘               │
│         └──────────┬────────┘                       │
│                    │ 内部总线                        │
│  ┌─────────────────┼──────────────────────────┐     │
│  │  16MB Flash  8MB PSRAM  ROM  SRAM  RTC_MEM  │     │
│  └─────────────────────────────────────────────┘     │
│                                                     │
│  外设:GPIO / UART / SPI / I2C / I2S / USB / ADC    │
│        PWM(LEDC) / RMT / PCNT / TWAI / SDMMC        │
└─────────────────────────────────────────────────────┘

内存布局(N16R8)

存储器大小用途
内部 SRAM512 KB代码 + 数据(运行时)
外部 Flash16 MB程序存储、文件系统
外部 PSRAM8 MB大缓冲区、图像处理
RTC 慢速内存8 KB深度睡眠保留数据
ROM384 KB启动代码、基础库

与普通 C 程序的关键区别

PC 程序                    嵌入式程序
─────────────────────────────────────────
有操作系统                  裸机 or RTOS
无限内存(虚拟)            内存极其有限
printf 输出到终端           printf 输出到 UART
程序崩溃 → 报错退出         程序崩溃 → 看门狗复位
库函数随意用                每个字节都要考虑

1.2 ESP-IDF 环境搭建

方法一:VS Code 插件(推荐新手)

  1. 安装 VS Code
  2. 安装插件:搜索 ESP-IDF,安装 Espressif IDF 插件
  3. Ctrl+Shift+PESP-IDF: Configure ESP-IDF Extension
  4. 选择 Express 安装,选择 IDF 版本 v5.2(推荐)
  5. 等待下载完成(需要科学上网或使用国内镜像)

国内镜像加速(在安装界面选择):

IDF Mirror: https://dl.espressif.cn/dl/esp-idf
Tools Mirror: https://dl.espressif.cn/dl/

方法二:命令行安装

bash
# Windows(PowerShell)
winget install Git.Git Python.Python.3.11

# 克隆 IDF
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
git checkout v5.2

# 安装工具链
./install.ps1 esp32s3

# 激活环境(每次开新终端都要执行)
. ./export.ps1

验证安装

bash
idf.py --version
# 输出:ESP-IDF v5.2.x

1.3 第一个程序:Hello World

创建项目

bash
# 从模板创建
idf.py create-project hello_world
cd hello_world

# 设置目标芯片(重要!)
idf.py set-target esp32s3

项目结构

hello_world/
├── CMakeLists.txt          # 顶层构建文件
├── sdkconfig               # 配置文件(menuconfig 生成)
├── main/
│   ├── CMakeLists.txt      # main 组件构建文件
│   └── main.c              # 你的代码在这里
└── components/             # 自定义组件(可选)

main/main.c

c
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"          // ESP 日志系统
#include "esp_chip_info.h"    // 芯片信息

static const char *TAG = "HELLO";  // 日志标签

void app_main(void)
{
    // ESP_LOGI 比 printf 更好:带时间戳、标签、日志级别
    ESP_LOGI(TAG, "Hello, ESP32-S3!");

    // 获取芯片信息
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    ESP_LOGI(TAG, "芯片型号: %s", CONFIG_IDF_TARGET);
    ESP_LOGI(TAG, "CPU 核心数: %d", chip_info.cores);
    ESP_LOGI(TAG, "Flash: %dMB", spi_flash_get_chip_size() / (1024 * 1024));

    // 主循环
    int count = 0;
    while (1) {
        ESP_LOGI(TAG, "运行计数: %d", count++);
        vTaskDelay(pdMS_TO_TICKS(1000));  // 延时 1000ms(不阻塞 RTOS)
    }
}

编译、烧录、监视

bash
# 编译
idf.py build

# 烧录(替换 COM3 为你的串口号)
idf.py -p COM3 flash

# 打开串口监视器
idf.py -p COM3 monitor

# 一步完成:编译+烧录+监视
idf.py -p COM3 flash monitor

退出监视器Ctrl + ]

串口输出示例

I (312) HELLO: Hello, ESP32-S3!
I (318) HELLO: 芯片型号: esp32s3
I (322) HELLO: CPU 核心数: 2
I (326) HELLO: Flash: 16MB
I (1326) HELLO: 运行计数: 0
I (2326) HELLO: 运行计数: 1

1.4 ESP-IDF 核心概念

日志系统

c
#include "esp_log.h"

static const char *TAG = "MY_APP";

ESP_LOGE(TAG, "错误: %s", msg);    // Error   - 红色
ESP_LOGW(TAG, "警告: %d", val);    // Warning - 黄色
ESP_LOGI(TAG, "信息: %d", val);    // Info    - 绿色
ESP_LOGD(TAG, "调试: %d", val);    // Debug   - 白色
ESP_LOGV(TAG, "详细: %d", val);    // Verbose - 白色

错误处理(ESP-IDF 惯用法)

c
#include "esp_err.h"

esp_err_t ret = some_function();

// 方法1:手动检查
if (ret != ESP_OK) {
    ESP_LOGE(TAG, "操作失败: %s", esp_err_to_name(ret));
    return;
}

// 方法2:宏断言(失败则重启)
ESP_ERROR_CHECK(some_function());

// 方法3:带日志的检查
ESP_ERROR_CHECK_WITHOUT_ABORT(some_function());
bash
idf.py menuconfig

常用配置路径:

  • Component config → ESP System Settings → CPU frequency → 设置 240MHz
  • Component config → Log output → Default log verbosity → 调整日志级别
  • Serial flasher config → Flash size → 设置 16MB

1.5 CMakeLists.txt 说明

顶层 CMakeLists.txt

cmake
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(hello_world)

main/CMakeLists.txt

cmake
idf_component_register(
    SRCS "main.c"           # 源文件列表
    INCLUDE_DIRS "."        # 头文件目录
    REQUIRES               # 依赖的组件
        esp_log
        esp_system
)

📝 第一章练习题

练习 1-1:环境验证(基础)

目标:确认开发环境正常工作

任务

  1. 完成 ESP-IDF 安装,运行 idf.py --version 截图
  2. 创建 hello_world 项目,成功烧录到 ESP32-S3
  3. 在串口监视器中看到输出

验收标准:串口输出包含 "Hello, ESP32-S3!" 字样


练习 1-2:修改 Hello World(基础)

目标:熟悉编译-烧录流程

任务:修改 main.c,实现以下输出格式:

I (xxx) BOOT: ================================
I (xxx) BOOT: ESP32-S3 开发板启动成功
I (xxx) BOOT: 芯片: esp32s3 | 核心: 2 | Flash: 16MB
I (xxx) BOOT: ================================
I (xxx) MAIN: 第 1 秒运行中...
I (xxx) MAIN: 第 2 秒运行中...

要求

  • 使用两个不同的 TAG("BOOT" 和 "MAIN")
  • 启动信息只打印一次
  • 循环信息每秒打印,显示秒数

练习 1-3:芯片信息读取(进阶)

目标:学习查阅 ESP-IDF API 文档

任务:编写程序,启动时打印以下信息:

芯片型号:    ESP32-S3
修订版本:    v0.2
CPU 频率:    240 MHz
Flash 大小:  16 MB
PSRAM 大小:  8 MB
MAC 地址:    AA:BB:CC:DD:EE:FF
IDF 版本:    v5.2.x

提示 API

c
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_mac.h"
#include "esp_idf_version.h"
#include "esp_psram.h"

esp_chip_info_t info;
esp_chip_info(&info);

uint8_t mac[6];
esp_read_mac(mac, ESP_MAC_WIFI_STA);

size_t psram_size = esp_psram_get_size();

练习 1-4:错误处理练习(进阶)

目标:掌握 ESP-IDF 错误处理模式

任务:编写一个函数 init_system(),模拟初始化流程:

c
// 要求实现以下逻辑:
// 1. 调用 step1()、step2()、step3() 三个函数
// 2. 每个函数返回 esp_err_t
// 3. 任何一步失败,打印错误信息并返回错误码
// 4. 全部成功,打印 "系统初始化完成"
// 5. 在 app_main 中调用并用 ESP_ERROR_CHECK 包裹

esp_err_t step1(void) { return ESP_OK; }
esp_err_t step2(void) { return ESP_ERR_NO_MEM; }  // 模拟失败
esp_err_t step3(void) { return ESP_OK; }

考察点esp_err_to_name()、错误传递、ESP_ERROR_CHECK


练习 1-5:思考题

回答以下问题(写在注释里或笔记中):

  1. vTaskDelay(pdMS_TO_TICKS(1000)) 和 C 标准库的 sleep(1) 有什么区别?为什么嵌入式中要用前者?

  2. ESP32-S3 有 16MB Flash,但内部 SRAM 只有 512KB。如果你要处理一张 1MB 的图片,应该把它放在哪里?怎么访问?

  3. app_main() 函数和 PC 程序的 main() 有什么相同点和不同点?如果 app_main() 返回了会发生什么?


本章小结

知识点掌握程度自评
ESP32-S3 架构和内存布局⬜⬜⬜⬜⬜
IDF 环境安装与配置⬜⬜⬜⬜⬜
项目结构和 CMake⬜⬜⬜⬜⬜
编译、烧录、监视流程⬜⬜⬜⬜⬜
ESP_LOG 日志系统⬜⬜⬜⬜⬜
esp_err_t 错误处理⬜⬜⬜⬜⬜

下一章GPIO 与 LED 控制 →

个人知识库