Appearance
第一章:芯片认知与环境搭建
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)
| 存储器 | 大小 | 用途 |
|---|---|---|
| 内部 SRAM | 512 KB | 代码 + 数据(运行时) |
| 外部 Flash | 16 MB | 程序存储、文件系统 |
| 外部 PSRAM | 8 MB | 大缓冲区、图像处理 |
| RTC 慢速内存 | 8 KB | 深度睡眠保留数据 |
| ROM | 384 KB | 启动代码、基础库 |
与普通 C 程序的关键区别
PC 程序 嵌入式程序
─────────────────────────────────────────
有操作系统 裸机 or RTOS
无限内存(虚拟) 内存极其有限
printf 输出到终端 printf 输出到 UART
程序崩溃 → 报错退出 程序崩溃 → 看门狗复位
库函数随意用 每个字节都要考虑1.2 ESP-IDF 环境搭建
方法一:VS Code 插件(推荐新手)
- 安装 VS Code
- 安装插件:搜索
ESP-IDF,安装 Espressif IDF 插件 - 按
Ctrl+Shift+P→ESP-IDF: Configure ESP-IDF Extension - 选择 Express 安装,选择 IDF 版本 v5.2(推荐)
- 等待下载完成(需要科学上网或使用国内镜像)
国内镜像加速(在安装界面选择):
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.x1.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: 运行计数: 11.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());menuconfig 配置系统
bash
idf.py menuconfig常用配置路径:
Component config → ESP System Settings → CPU frequency→ 设置 240MHzComponent 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:环境验证(基础)
目标:确认开发环境正常工作
任务:
- 完成 ESP-IDF 安装,运行
idf.py --version截图 - 创建 hello_world 项目,成功烧录到 ESP32-S3
- 在串口监视器中看到输出
验收标准:串口输出包含 "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:思考题
回答以下问题(写在注释里或笔记中):
vTaskDelay(pdMS_TO_TICKS(1000))和 C 标准库的sleep(1)有什么区别?为什么嵌入式中要用前者?ESP32-S3 有 16MB Flash,但内部 SRAM 只有 512KB。如果你要处理一张 1MB 的图片,应该把它放在哪里?怎么访问?
app_main()函数和 PC 程序的main()有什么相同点和不同点?如果app_main()返回了会发生什么?
本章小结
| 知识点 | 掌握程度自评 |
|---|---|
| ESP32-S3 架构和内存布局 | ⬜⬜⬜⬜⬜ |
| IDF 环境安装与配置 | ⬜⬜⬜⬜⬜ |
| 项目结构和 CMake | ⬜⬜⬜⬜⬜ |
| 编译、烧录、监视流程 | ⬜⬜⬜⬜⬜ |
| ESP_LOG 日志系统 | ⬜⬜⬜⬜⬜ |
| esp_err_t 错误处理 | ⬜⬜⬜⬜⬜ |
下一章:GPIO 与 LED 控制 →