Chapter 01

ESP32 快速入门

了解 ESP32 硬件架构、选择合适的开发框架,并完成第一个 IoT 程序

ESP32 与 ESP8266 的区别

ESP8266 是乐鑫 2014 年发布的第一款 Wi-Fi SoC,以极低的价格(约 1 美元)迅速风靡 Maker 社区。ESP32 是其 2016 年发布的继任者,在几乎所有维度都做了大幅提升。理解它们的区别有助于你在项目中做出正确的芯片选型。

特性ESP8266ESP32
CPU 核心单核 Xtensa LX106 @160MHz双核 Xtensa LX6 @240MHz
SRAM80KB(可用约 50KB)520KB(分段)
Flash外部 SPI Flash(通常 4MB)外部 SPI Flash(通常 4MB)
Wi-Fi802.11 b/g/n 2.4GHz802.11 b/g/n 2.4GHz
蓝牙BLE 4.2 + 经典蓝牙
ADC1 路 10bit ADC18 路 12bit ADC(2 组)
DAC2 路 8bit DAC
GPIO17 个(部分有复用限制)34 个(GPIO 矩阵任意复用)
深度睡眠电流约 20μA约 10μA
硬件安全安全启动、Flash 加密、硬件加密加速
选型建议

如果你的项目只需要基本 Wi-Fi 联网且成本极度敏感,ESP8266 仍是合理选择。但如果需要蓝牙、多路 ADC、更多内存或更复杂的任务处理,ESP32 是不二之选。本教程全程使用 ESP32。

双核 Xtensa LX6 架构详解

ESP32 的处理器是 Tensilica 公司(现属 Cadence)设计的 Xtensa LX6 架构,乐鑫对其进行了定制化扩展。理解这个架构对于后续的多任务开发和调试至关重要。

┌─────────────────────────────────────────────────────────┐ │ ESP32 SoC │ │ │ │ ┌────────────┐ ┌────────────┐ │ │ │ CPU0 │ │ CPU1 │ ← 双核 Xtensa LX6 │ │ │ PRO_CPU │ │ APP_CPU │ 最高 240MHz │ │ │(Wi-Fi协议)│ │(应用代码)│ │ │ └─────┬──────┘ └─────┬──────┘ │ │ └────────┬─────────┘ │ │ │ 内部总线 │ │ ┌─────────────┼──────────────────────────┐ │ │ │ ▼ │ │ │ │ ┌────────────────┐ │ │ │ │ │ Cache / IRAM │ 128KB 指令RAM │ │ │ │ │ DRAM 520KB │ 数据RAM │ │ │ │ └────────────────┘ │ │ │ │ │ │ │ │ Wi-Fi BT ADC DAC GPIO SPI I2C │ │ │ │ UART I2S RMT LEDC RTC ULP │ │ │ └────────────────────────────────────────┘ │ │ │ │ 外部 SPI Flash(通常 4MB) / 外部 PSRAM(可选) │ └─────────────────────────────────────────────────────────┘

两个核心的职责分工

CPU0 / PRO_CPU
默认由 ESP-IDF 的 Wi-Fi/蓝牙协议栈占用,运行 lwIP 网络栈和无线驱动。也可以运行用户代码,但需注意与协议栈的竞争。
CPU1 / APP_CPU
默认运行用户应用代码。FreeRTOS 的 main 任务(即 app_main)在此核心上运行。可以将性能敏感任务绑定到此核心。
IRAM(指令 RAM)
192KB,存放需要快速执行的代码(如中断处理程序)。从 IRAM 执行的代码速度是从 Flash 执行的 10 倍以上,因为不需要缓存预热。
DRAM(数据 RAM)
320KB,存放运行时数据(堆栈、全局变量、堆)。其中一部分(64KB)在深度睡眠时仍保持供电(RTC SRAM),可用于存储唤醒后需要的数据。
Flash(外部)
通常 4MB,通过 SPI 总线连接,存放程序代码、只读数据、文件系统分区。代码执行时通过 MMU 映射和 Cache 加速,Flash 也可通过分区表划分不同用途区域。
RTC 低功耗核心
独立的 ULP(超低功耗)协处理器,主 CPU 深度睡眠时仍可工作,用于定时唤醒或传感器轮询,耗电仅微安级别。

开发框架对比

ESP32 生态支持三种主流开发框架,各有侧重:

ESP-IDF(官方 C/C++ SDK)

乐鑫官方维护,功能最完整,文档最权威。使用 CMake 构建系统,FreeRTOS 为内置 OS。适合生产级产品和需要精细控制的项目。学习曲线较陡,但收益最大。

Arduino Core for ESP32

将 Arduino API 移植到 ESP32,代码风格熟悉,生态库丰富(数千个 Arduino 库)。适合快速原型和 Maker 项目。底层仍调用 ESP-IDF,但封装了复杂细节。

PlatformIO

作为 VS Code 插件运行的现代化 IDE,支持 ESP-IDF 和 Arduino 两套框架,提供依赖管理、串口监视器、调试器集成。推荐作为 Arduino 开发的 IDE 替代。

MicroPython / CircuitPython

在 ESP32 上运行精简版 Python,开发速度最快,适合教学和脚本级应用。性能较差,不适合实时要求高的项目,内存占用也较大。

安装 ESP-IDF 开发环境

前置要求

ESP-IDF 需要 Python 3.7+、Git 和若干系统工具。以下是各平台的安装方式:

# ── macOS ──
# 1. 安装 Homebrew(如未安装)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 2. 安装依赖
brew install cmake ninja dfu-util python3

# ── Ubuntu / Debian Linux ──
sudo apt-get install git wget flex bison gperf python3 python3-pip \
  python3-venv cmake ninja-build ccache libffi-dev libssl-dev \
  dfu-util libusb-1.0-0

# ── Windows ──
# 推荐使用官方 ESP-IDF Windows Installer:
# https://dl.espressif.com/dl/esp-idf/?idf=latest

克隆 ESP-IDF 并安装工具链

# 克隆 ESP-IDF(推荐使用稳定版,如 v5.2)
mkdir -p ~/esp
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
git checkout v5.2
git submodule update --init --recursive

# 安装 Xtensa/RISC-V 工具链和工具
./install.sh esp32

# 设置环境变量(每个终端会话都需要运行)
. $HOME/esp/esp-idf/export.sh

# 或将以下别名加入 ~/.bashrc / ~/.zshrc 方便调用
alias get_idf='. $HOME/esp/esp-idf/export.sh'

# 验证安装
idf.py --version    # 应输出 ESP-IDF v5.2.x
VS Code 插件更方便

安装 Espressif IDF 官方 VS Code 扩展(ID: espressif.esp-idf-extension),它会自动完成 ESP-IDF 的下载、配置和工具链安装,并提供图形化的 Flash、Monitor、调试界面,是最推荐的入门方式。

创建第一个 ESP-IDF 项目

项目结构

# 复制 hello_world 示例
cp -r $IDF_PATH/examples/get-started/hello_world ~/esp/
cd ~/esp/hello_world

# ESP-IDF 项目标准结构:
hello_world/
├── CMakeLists.txt       # 顶层 CMake:注册项目名
├── sdkconfig            # 配置文件(menuconfig 生成)
├── partitions.csv       # 可选:自定义分区表
└── main/
    ├── CMakeLists.txt   # 组件 CMake:注册源文件
    └── hello_world_main.c

Hello World 源码解析

// main/hello_world_main.c
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_chip_info.h"

static const char *TAG = "HELLO";

void app_main(void)
{
    /* ESP_LOGI:Info 级别日志,格式类似 printf */
    ESP_LOGI(TAG, "Hello, ESP32!");

    /* 获取芯片信息 */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    ESP_LOGI(TAG, "ESP32 芯片:%d 个 CPU 核心, Wi-Fi%s%s",
             chip_info.cores,
             (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
             (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");

    for (int i = 10; i >= 0; i--) {
        ESP_LOGI(TAG, "%d 秒后重启...", i);
        vTaskDelay(pdMS_TO_TICKS(1000));   // 延迟 1000ms
    }
    esp_restart();   // 软件重启
}
ESP_LOG 日志系统

ESP-IDF 使用 ESP_LOGE/W/I/D/V 五个级别的日志宏(Error/Warning/Info/Debug/Verbose)。TAG 是模块标识字符串,便于过滤。日志级别可在 menuconfig 中全局或按 TAG 控制,Release 时可完全关闭节省 Flash 空间。

编译、烧录与监视

# 配置目标芯片(首次必须运行)
idf.py set-target esp32

# 可选:打开图形化配置菜单
idf.py menuconfig

# 编译项目
idf.py build

# 烧录到设备(替换 /dev/ttyUSB0 为实际串口)
idf.py -p /dev/ttyUSB0 flash

# 打开串口监视器(Ctrl+] 退出)
idf.py -p /dev/ttyUSB0 monitor

# 一键:编译 + 烧录 + 监视
idf.py -p /dev/ttyUSB0 flash monitor

LED 闪烁实战

ESP-IDF 版本

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"

#define LED_PIN    GPIO_NUM_2   // 大多数 DevKit 板载 LED 在 GPIO2
static const char *TAG = "BLINK";

void app_main(void)
{
    /* 配置 GPIO2 为输出模式 */
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << LED_PIN),
        .mode         = GPIO_MODE_OUTPUT,
        .pull_up_en   = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type    = GPIO_INTR_DISABLE,
    };
    gpio_config(&io_conf);

    while (1) {
        gpio_set_level(LED_PIN, 1);          // LED 亮
        ESP_LOGI(TAG, "LED ON");
        vTaskDelay(pdMS_TO_TICKS(500));

        gpio_set_level(LED_PIN, 0);          // LED 灭
        ESP_LOGI(TAG, "LED OFF");
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

Arduino 版本(对比参考)

#define LED_PIN 2

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  Serial.println("LED ON");
  delay(500);
  digitalWrite(LED_PIN, LOW);
  Serial.println("LED OFF");
  delay(500);
}
GPIO2 注意事项

GPIO2 在许多 ESP32 开发板上连接了板载 LED,同时也与 SD 卡的数据引脚复用,还影响 Boot 模式(上电时低电平进入下载模式)。烧录时如果 LED 不断闪烁导致失败,可以尝试断开连接到 GPIO2 的外部设备。

常见 ESP32 开发板选型

ESP32-DevKitC
乐鑫官方开发板,ESP-WROOM-32 模组,38 引脚,最常见的参考设计。适合所有入门和原型项目。
ESP32-S3
ESP32 的升级版,增加 USB OTG、AI 向量指令、更多内存,适合需要 USB 接口或 TinyML 推理的项目。
ESP32-C3
RISC-V 单核 160MHz,低成本,支持 Wi-Fi 和 BLE 5,适合成本敏感的批量生产项目。
ESP32-CAM
集成 OV2640/OV5640 摄像头和 microSD 卡槽,适合图像识别、监控摄像头等视觉类 IoT 项目。
TTGO T-Display
集成 1.14 寸 ST7789 TFT 彩屏,适合需要本地显示的便携设备,屏幕驱动库资源丰富。