做硬件这行,从Arduino Uno这类纯MCU板子跳到带WiFi的SoC,最直观的体验就是“板子终于能上网了”。而如果你现在选型,大概率会被ESP32S3 Dev Module这个名字吸引——它不光是带无线,而是直接把双核、向量指令、PSRAM这些曾经只在更高端芯片上出现的东西全塞进了一块可以插面包板的开发板里。我说句实话,用Arduino IDE开发它,属于“买得起、学得会、用得上”的典型选择,尤其适合做带屏幕的桌面小工具、摄像头图传、离线语音识别,甚至入门TinyML。这篇文章就围绕这个开发板,从硬件选型、Arduino环境配置、引脚规划到实际跑通几个典型场景,掰开揉碎聊聊。
先给不了解的朋友定位一下:ESP32S3 Dev Module是Arduino IDE开发板管理器里,针对ESP32-S3芯片的一种通用开发板配置选项。你手里拿到的实体板子可能来自不同厂家,丝印五花八门,但只要芯片是ESP32-S3,选这个板型基本都能跑。它和普通ESP32最大的区别在于:内核升级到双核LX7、支持向量指令(做AI推理更快)、板载或外挂了PSRAM(大内存跑图像任务不捉襟见肘)、而且自带USB OTG接口(可以模拟键鼠、当串口用)。这些特性组合起来,让这块板子在物联网、边缘计算、人机交互设备领域非常能打。
1. 项目概述:ESP32S3到底是什么定位
1.1 硬件底子:双核、向量指令与PSRAM
先把最核心的硬件参数捋一遍。ESP32-S3用的是双核Xtensa LX7处理器,主频最高240MHz,内置512KB SRAM。这个双核不是摆设,两个核心可以分别跑不同任务,比如一个核处理WiFi协议栈,另一个核跑用户逻辑代码,这在做需要同时联网和响应外设的项目时非常实用。
比双核更值钱的是它的向量指令支持。通俗点说,它在处理器层面加入了专门加速矩阵运算的指令集,像图像缩放、音频特征提取、神经网络推理这类计算密集任务,比同价位的普通MCU快几倍。这也是为什么现在很多人拿ESP32S3跑TensorFlow Lite Micro做关键词唤醒、手势识别,而不是选纯MCU。
PSRAM更是重头戏。很多ESP32S3模块直接集成8MB的OPI PSRAM,Arduino里启用之后,你可以放心地分配大缓冲区来处理摄像头帧数据。我实测过,没PSRAM的板子拍VGA分辨率的照片,帧缓冲都分配不出来,而有PSRAM之后开个JPEG编码缓冲区毫无压力。所以如果你打算做摄像头、做带界面的屏幕应用,PSRAM是硬需求。
1.2 和ESP32、ESP32C3等兄弟型号怎么选
很多人选型时会在ESP32、ESP32C3、ESP32S3之间纠结。这三者虽然都带WiFi和蓝牙,但侧重点完全不一样。
| 型号 | 核心 | 内存 | PSRAM | USB | AI加速 | 适合场景 |
|---|---|---|---|---|---|---|
| ESP32 | 双核LX6 240MHz | 520KB SRAM | 可选 | 无 | 无 | 通用IoT、经典永流传 |
| ESP32C3 | 单核RISC-V 160MHz | 400KB SRAM | 无 | 无 | 无 | 低功耗、简单传感器节点 |
| ESP32S3 | 双核LX7 240MHz | 512KB SRAM | 可选,最大8MB以上 | 有 | 向量指令 | 图像、语音、AI、带屏设备 |
我个人的建议是:如果只是做个温湿度上报、继电器控制,ESP32甚至ESP8266都够;如果想尝鲜RISC-V且对功耗有要求,选C3;但如果你想一步到位,做点带屏幕、带摄像头、带语音交互的“智能硬件”,直接选S3,省得以后换平台。
1.3 典型应用场景与适合人群
这块板子的应用场景,我总结为四类:
- 桌面小工具:带一块TFT屏幕显示天气、时间、倒计时,配合WiFi拉取网络数据,双核跑得游刃有余。
- 智能家居节点:接入Home Assistant或其他MQTT平台,控制灯光、读取传感器,板载WiFi和BLE双协议兼容性很强。
- 摄像头/图像应用:搭配OV2640或OV5640摄像头,做拍照上传、简单的人脸检测、颜色识别。PSRAM和向量指令让这类应用真正变得可用。
- 语音交互:ESP32S3支持ESP-SR语音识别方案,可以做离线唤醒词识别,比如“你好小智”这种,不依赖云服务,隐私性好。
适合的读者也很明确:有Arduino基础、想从纯单片机过渡到联网设备的人;想用低成本硬件做AIoT原型验证的工程师;还有喜欢折腾的DIY爱好者。说实话,这块板子的学习曲线不算陡,只要你会Arduino的基本语法,半天就能跑起WiFi例程。
2. Arduino IDE环境配置与开发板设置
2.1 第一步:安装开发板支持包与驱动
在Arduino IDE里使用ESP32S3,首先要安装ESP32开发板支持包。我这里建议直接用Arduino IDE 2.x版本,界面更现代,开发板管理器下载速度也更快。打开IDE后,进入“文件-首选项”,在“附加开发板管理器网址”里填上官方维护的ESP32包地址。
填好之后,在“工具-开发板-开发板管理器”里搜索esp32,找到ESP32系列支持包,点安装。这个过程会下载不少工具链,耐心等到完成。装完之后,你的IDE里就会多出一大批ESP32相关的板型选项。
如果你手里的板子带板载USB转串口芯片,比如常见的CP2102或CH340,第一次插上电脑可能没反应。这时候需要去设备管理器看一眼,如果出现未知设备,装对应驱动就行。Windows系统一般会自动联网找驱动,个别老系统需要手动装。这一步卡住的人不少,但解决方案很简单,基本就是装个驱动的事。
2.2 开发板菜单里那些选项怎么选
在“工具”菜单里选中你的开发板型号时,你会看到一长串选项,很多新手直接被劝退。其实这里面的核心选项就几个,我建议的配置如下:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| Board | ESP32S3 Dev Module | 通用选项,兼容大多数ESP32S3开发板 |
| Upload Speed | 921600 | 速度快,如果下载失败再降到115200 |
| USB CDC On Boot | 视板子而定 | 用原生USB选Enabled,用板载串口芯片选Disabled |
| CPU Frequency | 240MHz | 默认全速,省电场景可降160MHz |
| Flash Size | 4MB/8MB/16MB | 必须和板子实际Flash一致,选错会导致启动异常 |
| Flash Mode | QIO 80MHz | 绝大多数板子默认,如果启动失败换DIO |
| Partition Scheme | 默认或Huge APP | 需要上传大固件时选Huge APP;要OTA就选对应方案 |
| PSRAM | OPI PSRAM | 如果你的板子有8MB PSRAM,务必启用,否则内存不够用 |
这里有几个关键点,值得多解释两句。
USB CDC On Boot是新手最容易忽略的坑。如果你的板子是靠外置USB转串口芯片(看板子上有没有一个独立的小芯片,丝印通常是CP2102或者CH340),那么这个选项选Disabled,因为烧录和串口打印都走芯片的UART通道。如果你的板子直接用ESP32S3的原生USB口(板子可能只有一个USB口,而且芯片上直接引出了USB差分线),那么这个选项选Enabled,否则烧录后串口监视器看不到任何打印信息。
Flash Size决定了分区表怎么分配。选小了浪费空间,选大了可能导致固件写入超出实际容量,最直接的表现就是烧录成功但板子反复重启或运行不稳定。买板子时问清楚是4MB、8MB还是16MB版本,这个参数别靠猜。
2.3 下载模式与串口选择的两个坑
ESP32S3下载固件有两种模式:一种是靠板载USB转串口芯片自动切换boot模式,另一种是靠原生USB。在Arduino IDE中,如果你选ESP32S3 Dev Module,默认用的往往是UART口下载。但问题来了:如果你的板子只有一个USB口,而且这个USB口直接连的是ESP32S3的原生USB外设,那你需要把“USB Mode”选为Hardware CDC and JTAG,并且“USB CDC On Boot”选Enabled。否则就会出现“端口能识别,但上传时一直显示Connecting...”。
另一个坑是手动进入下载模式。有些板子由于电路设计原因,自动下载不可靠。遇到这种情况,别慌:按住板子上的BOOT按键,然后点上传,看到IDE输出“Connecting...”后按一下复位键EN/RST,松开BOOT,下载就能正常进行。这个操作在Espressif系板卡上是经典方案,我用了很多年,成功率几乎是100%。
提示:买ESP32S3开发板时,尽量选带板载串口芯片的版本。原生USB虽然理论上更方便,但在Arduino IDE里有时候反而要折腾驱动和CDC设置,对新手不够友好。
3. 引脚规划与外围电路设计
3.1 关键引脚速查
ESP32-S3总共引出45个GPIO,但并不是所有引脚都能随便用。开发板上一些引脚被板载功能占用或承担特殊角色,我整理了一个速查表,做项目之前先对着看一遍,能帮你少走不少弯路。
| 引脚 | 功能 | 注意事项 |
|---|---|---|
| GPIO0 | BOOT按键 | 低电平触发,下载模式时会用到 |
| GPIO19/20 | 原生USB D-/D+ | 直连USB座时不可做普通IO |
| GPIO43/44 | UART0 TX/RX | 一般连板载串口芯片,默认日志输出 |
| GPIO45 | 部分板子连接串口芯片供电使能或状态脚 | 慎用,看原理图 |
| GPIO46 | 复位控制 | 部分开发板上连接EN(反向),不可做普通IO |
| GPIO35/36/37 | 常见RGB灯或按键 | 不同厂家定义不同,看丝印 |
不同品牌的ESP32S3开发板,引脚占用差异非常明显。比如我之前用的一款板子,GPIO38接了板载RGB灯,另一款板子却在GPIO33上。所以拿到板子第一件事,是去下载对应开发板的原理图或引脚图。没有原理图,至少也要看板子背面的丝印说明。
3.2 哪些引脚要重点避开
除了上面表格里的引脚,还有几类引脚需要格外小心。
第一类是Strapping引脚。ESP32S3上电时,某些引脚的电平状态会被芯片读取,用来决定启动模式。比如GPIO0(决定是否进入下载模式)、GPIO3、GPIO45、GPIO46等。如果这些引脚外部接了强上拉或强下拉,可能导致板子无法正常启动。设计电路时,如果非要用这些引脚,记得确保上电瞬间的电平在合理范围内,或者干脆避开。
第二类是模组未引出的引脚。很多ESP32S3模组只引出了一部分GPIO到开发板排针。比如GPIO26到GPIO32,在WROOM-1模组里是内部连接Flash/PSRAM的,没有物理引出。你在Arduino里扫描这些引脚,会发现它们永远读不到外部信号。这一点和普通Arduino Uno“所有引脚都在排针上”的体验完全不同,写代码前先确认引脚是否真正可用。
第三类是ADC与WiFi的冲突。ESP32S3的ADC2通道在WiFi开启时会受到干扰,采样值会变得不稳定。我之前做电池电压监测,一开始用了ADC2引脚,结果WiFi一连接数据就乱跳,排查了半天才发现是这个原因。所以涉及模拟量采集,优先用ADC1的引脚(GPIO1到GPIO10),能避开不少麻烦。
3.3 常用协议引脚推荐分配
ESP32S3的大部分外设(I2C、SPI、UART等)都可以通过GPIO矩阵映射到任意引脚,这就是所谓的“引脚可配置”。这意味着你基本不会遇到“引脚不够用”的物理限制,只需要注意避免冲突。
我通常会这样分配引脚:
| 功能 | 推荐引脚 | 说明 |
|---|---|---|
| I2C(屏幕/传感器) | GPIO8(SDA)、GPIO9(SCL) | 也可以任选其他GPIO,软件配置 |
| SPI(LCD/摄像头) | GPIO11-14 | 部分开发板默认硬件SPI引脚,跑得快 |
| UART(调试/外设) | GPIO43/44默认,可换 | 如果想保留串口日志,别占用这个 |
| PWM/LED | GPIO48等任意输出脚 | 避开特殊引脚即可 |
| 按键输入 | GPIO47、GPIO0(复用BOOT) | GPIO0在运行阶段做按键是常见做法 |
这里特别提一下I2C:ESP32S3的Wire库支持任意引脚,所以你完全可以把SDA和SCL放在顺手的位置,不用死记硬背默认引脚。实际项目中,我习惯把屏幕的I2C放在GPIO8/9,传感器挂另一组I2C引脚,这样后期改硬件也不影响软件。
4. 核心应用场景实操
4.1 WiFi联网与本地控制:一个可直接跑的示例
说了这么多配置,直接上个能跑的代码。这个例子演示ESP32S3连接WiFi后,在局域网里提供一个Web页面来控制板载LED。它覆盖了WiFi连接、WebServer库、GPIO控制这三个最常用的操作,非常适合作为上板后的第一个测试程序。
代码比较简单,直接用Arduino IDE新建工程粘贴即可。注意把SSID和密码改成你自己的。
#include <WiFi.h> #include <WebServer.h> const char* ssid = "你的WiFi名"; const char* password = "你的WiFi密码"; #define LED_PIN 48 WebServer server(80); void handleRoot() { String html = "<html><body><h1>ESP32S3 Web LED</h1>"; html += "<p><a href=\"/on\">开灯</a></p>"; html += "<p><a href=\"/off\">关灯</a></p>"; html += "</body></html>"; server.send(200, "text/html", html); } void setup() { pinMode(LED_PIN, OUTPUT); Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("IP地址: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.on("/on", []() { digitalWrite(LED_PIN, HIGH); server.send(200, "text/html", "<html><body>灯已开 <a href=\"/\">返回</a></body></html>"); }); server.on("/off", []() { digitalWrite(LED_PIN, LOW); server.send(200, "text/html", "<html><body>灯已关 <a href=\"/\">返回</a></body></html>"); }); server.begin(); Serial.println("HTTP服务器已启动"); } void loop() { server.handleClient(); }关于GPIO48,这是很多ESP32S3开发板上的板载LED引脚,如果你的板子不是这个引脚,看丝印改一下就行。
这个示例跑通后,你就掌握了ESP32S3联网的基础链路。想扩展的话,可以换成MQTT协议把数据上报到服务器,或者用WebSocket做实时双向通信。不过对刚上手的人来说,先让网页能控制LED,再往上面加东西,心理负担小得多。
4.2 双核并行:把两个核心都用起来
ESP32S3的双核如果不主动用,其实和单核没太大区别。Arduino默认的setup()和loop()只跑在Core 1上,Core 0主要跑WiFi协议栈。但当你需要同时做两种计算密集任务时,把任务分配到指定核上就能明显提升流畅度。
下面这段代码演示了用xTaskCreatePinnedToCore创建两个独立任务,分别跑在两个核上。一个任务让LED以500ms间隔闪烁,另一个任务每2秒打印一次“Core 0运行中”。这只是一个模板,实际项目里可以把传感器读取和网络处理分开放在不同核上。
#include "Arduino.h" void blinkTask(void *pvParameters) { pinMode(48, OUTPUT); while (true) { digitalWrite(48, HIGH); delay(500); digitalWrite(48, LOW); delay(500); } } void printTask(void *pvParameters) { while (true) { Serial.println("Core 0运行中,空闲时间充裕"); delay(2000); } } void setup() { Serial.begin(115200); delay(1000); xTaskCreatePinnedToCore( blinkTask, // 任务函数 "blink", // 任务名 4096, // 栈大小(字节) NULL, // 传入参数 1, // 优先级(数字越高越优先) NULL, // 任务句柄 0 // 绑定到Core 0 ); xTaskCreatePinnedToCore( printTask, "print", 4096, NULL, 1, NULL, 1 // 绑定到Core 1 ); } void loop() { // 主循环空闲,任务由FreeRTOS调度 delay(1000); }这里要注意两个关键参数:栈大小和优先级。栈大小分配过小,任务运行时会触发看门狗重启;分配过大则浪费SRAM。一般建议从4096字节起步,如果任务里用了复杂的库函数或大数组,再加大到8192甚至更高。优先级方面,ESP32S3上WiFi协议栈跑在最高优先级,你给用户任务设置的优先级尽量不要超过它,否则可能影响网络稳定性。
提示:
xTaskCreatePinnedToCore创建的任务是FreeRTOS的任务,不受Arduinodelay()的调度限制。这是ESP32系列相对传统Arduino板子的一大优势,善于利用它,你的程序才能真正发挥双核性能。
4.3 PSRAM与图片/内存密集型应用
很多人在Arduino环境下使用ESP32S3,最爽的一点就是可以直接用PSRAM。默认Arduino环境里,psramInit()会自动执行,你甚至不需要额外初始化。但要真正用好它,需要在写代码时明确告诉编译器:这个数组放到PSRAM里,而不是内部SRAM。
一个典型场景是摄像头应用。OV2640输出VGA分辨率的RGB565帧,一帧数据大约需要320*240*2=153600字节,也就是150KB左右。这个大小放在512KB的SRAM里当然放得下,但如果同时要做JPEG编码、后续处理,缓冲区翻倍,SRAM就捉襟见肘了。用PSRAM做帧缓冲,问题就迎刃而解。
代码里分配PSRAM内存的方式如下:
// 使用heap_caps_malloc分配PSRAM内存 uint8_t *framebuffer = (uint8_t*)heap_caps_malloc(320 * 240 * 2, MALLOC_CAP_SPIRAM); if (framebuffer == NULL) { Serial.println("PSRAM分配失败"); } else { Serial.println("PSRAM分配成功"); // 使用framebuffer... // 用完释放 heap_caps_free(framebuffer); }用heap_caps_malloc配合MALLOC_CAP_SPIRAM标志,就能把大块内存放在PSRAM里。如果你使用esp32-camera库,库内部会自动检测PSRAM并优先使用它,无需额外配置,只要在编译时启用了PSRAM选项。
注意一点,PSRAM的访问速度比内部SRAM慢,但性能瓶颈通常不在内存带宽,而是摄像头传感器的传输速率和SD卡写入速度。所以实际体验几乎没有差别,但可用内存却大了十几倍。这也是ESP32S3比ESP32老款芯片更适合做图像应用的核心原因。
4.4 轻量AI推理与向量指令加速
聊到ESP32S3,绕不开“边缘AI”这个标签。和ESP32、ESP32C3不同,ESP32S3的向量指令可以对神经网络算子做加速。在Arduino环境里,你可以跑TensorFlow Lite Micro库,虽然目前官方支持Arduino的版本还不够完善,但社区资料已经很丰富了。
我实际跑过一个关键词识别模型,用来识别“是/否”两个词,模型大小压缩到200KB以内,在240MHz主频下推理一次约50ms左右,这已经是可用水平了。放在ESP32上,同样模型可能要100ms以上。
跑TinyML的关键步骤通常包括这几步:
- 用TensorFlow训练并量化模型,一般转成int8量化格式,模型文件控制在几百KB内。
- 把模型数组嵌入Arduino工程,或者放到SD卡里读取。
- 在代码里初始化TensorFlow Lite Micro解释器,设置输入输出张量。
- 采集麦克风数据,做MFCC特征提取,喂给模型,读取分类结果。
这个方向内容量很大,真要展开能写一整篇。这里我强调一点:入门别想着一步到位跑图像分类,先跑一个语音关键词识别,或者用板载IMU传感器做动作识别,难度低很多,但能把整条链路跑通。等你熟悉了TensorFlow Lite Micro的流程,再往图像方向扩展也不迟。
5. 常见问题与排查技巧实录
5.1 下载失败与串口乱码
用ESP32S3 Dev Module配置下载固件,最经典的问题就是上传时报错A fatal error occurred: Timed out waiting for packet content。这个报错的意思是:IDE无法和芯片的bootloader握手成功。原因通常是USB口模式不对、下载驱动不稳定、或者手动boot模式没有触发。
我实际的排查顺序是:
- 先确认设备管理器里能识别到串口。如果看不到端口,优先查驱动和数据线。数据线看似简单,但很多劣质USB线只能充电,没有数据线芯,插上去毫无反应。这个问题在Arduino系列开发板里太常见了。
- 如果端口正常,把上传速度降下来。921600不行就115200,虽然慢一点,但稳定。有些带长导线的开发板或者供电不稳的环境,高速下载就是会失败。
- 还不行就按住BOOT键,点上传,再按一下EN键。这一套手动下载流程能解决99%的顽固问题。
- 最后再看IDE里选择的USB CDC On Boot和USB Mode是否匹配板子的物理接口。
串口乱码的问题通常集中在USB CDC On Boot设置错误。选错了会导致串口监视器输出乱码甚至完全不打印。我见过不少新手在原生USB板的配置里选了Disabled,结果WiFi能连上但Serial.println什么也看不到,就是这个原因。
5.2 意外复位与电源问题
ESP32S3跑着跑着突然重启,是最让人头疼的问题之一。这种问题排查起来往往不是单一原因,但最常见的诱因是电源不稳定。
ESP32S3的峰值功耗能到500mA以上,特别是在WiFi发射功率最大的一瞬间。如果你的供电方式是电脑USB口直供,或者是用了劣质面包板电源模块,瞬时电压跌落就会触发芯片的欠压复位。解决方法是:外接一个至少1A输出的5V电源,或者用稳压芯片给3.3V引脚稳定供电。这里特别提醒:千万别用Arduino Uno的3.3V输出去供电给ESP32S3,那个引脚电流能力太弱,带不动WiFi模块。
另一个隐藏的电源坑是:部分开发板在启用PSRAM时,如果Flash电压域配置不正确,会导致启动阶段反复重启。此时检查编译选项里的Flash Mode,如果当前是QIO,尝试改成DIO。这招解决了我手里一块杂牌板子的诡异重启问题。
5.3 问题速查表
把能想到的问题汇总成表,方便后面排查。这个表我每次做新项目时都会翻一遍,省了不少调试时间。
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 上传失败,提示Timed out | USB模式选错/没进下载模式 | 按住BOOT再试,降波特率,核对USB CDC选项 |
| 端口识别不到 | 缺驱动/劣质数据线 | 装CP2102/CH340驱动,换四芯数据线 |
| 串口监视器无输出 | USB CDC On Boot未开启 | 改为Enabled并重新烧录 |
| 串口输出乱码 | 波特率不匹配/选错串口 | 核对Serial.begin()和监视器波特率 |
| 烧录成功但无法启动 | Flash Size选择错误/Flash Mode不匹配 | 改Flash Size和QIO/DIO选项 |
| 运行中随机重启 | 电源电流不足/PSRAM配置错误 | 换电源、检查PSRAM和Flash模式 |
| WiFi连接但数据丢包 | 天线附近有金属干扰/电源噪声 | 调整天线位置、加强滤波电容 |
| ADC读数不稳定 | 用了ADC2通道且WiFi开启 | 切换到ADC1引脚 |
5.4 关于开发板版本差异的提醒
最后还要提醒一点关于板子本身的问题。“ESP32S3 Dev Module”是一个通用的Board配置文件,但实体板子的Flash大小和PSRAM有无差别很大。同样叫Dev Module,有的配4MB Flash无PSRAM,有的配16MB Flash加8MB PSRAM。编译配置里选错这些参数,轻则功能受限,重则无法启动。
所以我买开发板时有个习惯:下单前看准商品标题里的参数后缀,到手后拍下丝印或型号。比如WROOM-1和WROOM-1 N8R8就是两种典型版本,前者无PSRAM,后者带8MB PSRAM。别嫌麻烦,这一步能避免后面一连串的玄学问题。
写在最后的小体会
用ESP32S3 Dev Module做开发这段时间,我最大的感受是:它的上限很高,但下限也没有想象中那么低。所谓上限高,是因为它能干的事远超传统Arduino板——联网、图像、语音、AI都能沾边;所谓下限不低,是因为配置项多、引脚坑多、电源要求高,初学者很容易在一开始就被各种莫名其妙的问题劝退。
我个人跑项目的经验是:拿到板子先花半小时确认硬件版本和引脚占用,再花半小时跑通最简单的WiFi例程,然后才动工做业务逻辑。这个顺序看着浪费时间,实际能帮你省下大量排查问题的时间。如果你做的是摄像头或带屏项目,PSRAM大容量绝对是最大的帮手;如果你做的是低功耗传感器节点,那这块板子可能不是最优先的选择,它更适合算力密集型任务。
后续你可以试试把ESP-NOW、OTA远程升级、蓝牙配网这些功能加进来,它们都是ESP32S3生态里非常成熟的能力。从Arduino Uno这样的入门板,切换到ESP32S3这样的AIoT平台,过程会有不少新鲜感,也会踩不少坑,但每一次跑通新功能的成就感是实实在在的。祝你玩得开心。