ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ESP32-S3打造SoulCage互动吊坠:从TFT屏幕驱动到电源管理全解析

ESP32-S3打造SoulCage互动吊坠:从TFT屏幕驱动到电源管理全解析 1. 项目缘起与整体设计思路1.1 这个吊坠到底是个什么东西SoulCage 直译过来叫“灵魂囚笼”听起来挺中二但它的本质其实是一个带屏幕的互动式电子吊坠。核心玩法是一块小尺寸 TFT 屏幕里关着一个“数字灵魂”——一个会呼吸、会闪烁、会随着你晃动而做出反应的光点或小生物。你把它挂在脖子上它就像随身携带的一个小生命安静的时候微微脉动你走动时它会兴奋地跳动你把它翻过来它甚至会“生气”。这个项目的硬件核心是ESP32-S3一块在创客圈里非常能打的微控制器。选它不是因为别的就是因为它同时满足了三个硬性条件第一体积够小有 QFN 封装的模组可以塞进吊坠尺寸的 PCB第二自带 WiFi 和蓝牙后续想扩展手机互动不用换主控第三算力足够驱动 SPI 接口的 TFT 屏幕并且跑得动实时动画。屏幕用的是TFT_eSPI这个库来驱动配合一块 1.14 寸或 1.3 寸的 IPS 屏分辨率 135x240 或 240x240刚好够画一个简单的像素风灵魂。适合谁来参考这篇内容如果你已经玩过 Arduino、点过 LED、接过几根杜邦线想做一个有外壳、能戴出门、别人看了会问“这啥”的小玩意那这个项目就是为你准备的。如果你完全零基础也没关系我会把每一步拆到你能跟着做但你需要有耐心因为这个项目涉及焊接、外壳组装和调试不是插上面包线就能收工的级别。1.2 为什么选 ESP32-S3 而不是 Arduino Nano 或 RP2040这个问题我在立项的时候纠结了很久最后选 ESP32-S3 是基于以下几个实际考量。算力与内存。驱动一块 240x240 的 IPS 屏做 30fps 的动画每帧要刷新的像素是 57600 个16 位色深就是 115200 字节的数据量。Arduino Nano 的 ATmega328P 只有 2KB RAM连一帧的缓冲都放不下直接出局。RP2040 有 264KB RAM跑这个没问题但它的优势在于 PIO 编程对于 SPI 屏幕驱动来说并没有比 ESP32-S3 更简单。ESP32-S3 有 512KB 的 SRAM双核 240MHz跑 TFT_eSPI 加动画逻辑绰绰有余甚至还能剩出资源做蓝牙连接。封装尺寸。ESP32-S3 有官方模组 ESP32-S3-WROOM-1尺寸是 18mm x 25.5mm虽然不算特别小但对于一个吊坠来说如果你把 PCB 设计成 30mm x 50mm 左右的椭圆形是完全可以塞进去的。RP2040 的芯片本身更小7mm x 7mm但它需要外部 Flash 和晶振整体面积算下来差不多。开发便利性。ESP32-S3 在 Arduino IDE 里的支持已经非常成熟板子管理器里直接选“ESP32S3 Dev Module”就能用不需要额外的配置。TFT_eSPI 库对 ESP32 系列的支持也是最好的有专门的优化。功耗。这一点对吊坠来说很关键。ESP32-S3 支持多种低功耗模式在只驱动屏幕显示简单动画的情况下配合一块 300mAh 的锂聚合物电池可以做到 4-6 小时的续航。如果你把亮度调低、动画帧率降到 15fps撑 8 小时也不是不可能。注意ESP32-S3 的 GPIO 数量虽然多但并不是所有引脚都能随便用。GPIO 0、3、45、46 是 strapping 引脚上电时的电平状态会影响启动模式接屏幕的时候要避开或者加下拉电阻。GPIO 19 和 20 是 USB D-/D如果你要用 USB 下载程序这两个脚不能接其他外设。1.3 屏幕选型为什么是 ST7789 而不是 ILI9341TFT_eSPI 支持的屏幕驱动芯片很多最常见的是 ILI93412.4 寸以上和 ST77891.3 寸以下。对于吊坠这种尺寸ST7789 是唯一合理的选择原因很简单ILI9341 的屏幕最小也是 2.4 寸对角线 6 厘米挂在脖子上像块砖。ST7789 驱动的 IPS 屏有几个规格要注意区分分辨率常见的有 240x240、135x240、240x320。吊坠用 240x240 最合适正方形视觉上最平衡。接口必须是 SPI 接口因为 ESP32-S3 的并行接口引脚太多吊坠 PCB 走线会很痛苦。引脚数一般有 7 针VCC、GND、SCL、SDA、RES、DC、CS和 8 针多一个 BLK 背光控制两种。建议选 8 针的背光可以 PWM 调光省电。我实测下来中景园的 1.3 寸 240x240 IPS 屏配合 TFT_eSPI 库在 ESP32-S3 上刷满屏纯色大约需要 12ms也就是理论最高 80fps 左右。实际跑动画的时候因为要计算像素稳定在 30-40fps 没问题。1.4 在 Tinkercad 里先做电路仿真验证Tinkercad Circuits 是一个免费的在线电路仿真平台虽然它不支持 ESP32-S3只支持 Arduino Uno 等少数几款但你可以用它来验证外围电路的逻辑。比如SPDT 开关的接线方式。SoulCage 上有一个 SPDT 滑动开关用来切换“充电模式”和“运行模式”。在 Tinkercad 里你可以用 SPDT 开关加 LED 来模拟这个逻辑确认开关的公共端、常开端、常闭端接对了没有。分压电阻的计算。如果你要用 ESP32-S3 的 ADC 来检测电池电压需要两个电阻分压。Tinkercad 里可以直接搭出来用万用表测中间点的电压验证分压比是否正确。LED 指示灯的逻辑。充电时亮红灯、充满亮绿灯这个逻辑在 Tinkercad 里用几个 LED 和电阻就能验证。提示Tinkercad 的仿真不能替代真实焊接但它能帮你省下至少两轮打板的钱。我第一版 PCB 就是因为 SPDT 开关的引脚顺序搞反了导致开关拨到“运行”时实际是断开电池、接通充电白白浪费了两周等板子。2. 核心细节解析与实操要点2.1 ESP32-S3 的引脚分配与 TFT_eSPI 配置TFT_eSPI 库的配置是整个项目里最容易卡住新手的环节。它不像其他库那样在代码里传引脚参数而是通过一个叫User_Setup.h的头文件来配置。这个文件在 Arduino 的 libraries 文件夹里路径通常是Documents/Arduino/libraries/TFT_eSPI/User_Setup.h。你需要修改的关键行如下#define ST7789_DRIVER // 告诉库用的是 ST7789 驱动 #define TFT_WIDTH 240 #define TFT_HEIGHT 240 #define TFT_CS 10 // 片选 #define TFT_DC 9 // 数据/命令切换 #define TFT_RST 8 // 复位 #define TFT_SCLK 12 // SPI 时钟 #define TFT_MOSI 11 // SPI 数据 #define TFT_BL 7 // 背光控制可选 #define SPI_FREQUENCY 40000000 // SPI 时钟频率40MHz这里有几个坑我要提前说清楚。第一SPI 频率不是越高越好。ST7789 的 datasheet 标称最高 62.5MHz但实际走线长度、PCB 质量、杜邦线质量都会影响稳定性。我试过 80MHz屏幕直接花屏降到 40MHz 就非常稳定。如果你用杜邦线连接建议先降到 27MHz 测试确认能显示后再往上加。第二TFT_BL 引脚如果不用 PWM 调光可以直接接 3.3V。但吊坠的电池容量有限背光是大头一定要用 PWM 控制。ESP32-S3 的 LEDC 外设可以输出 PWM代码里用ledcSetup()和ledcAttachPin()配置即可。第三GPIO 编号要避开 strapping 引脚。我上面给的 7、8、9、10、11、12 都是安全的。如果你换成 GPIO 0 做 CS上电时如果屏幕没有正确初始化GPIO 0 被拉低ESP32-S3 会进入下载模式程序就跑不起来。2.2 灵魂动画的渲染逻辑“数字灵魂”的视觉效果本质上是一个基于噪声函数的粒子系统。我试过几种方案最后选了一个计算量小、效果又好的方法用 Perlin 噪声驱动一个圆形光点的半径和透明度变化。具体来说屏幕中心有一个基础圆半径 20 像素。每一帧我用三个不同频率的 Perlin 噪声值分别控制半径偏移r 20 noise(t * 0.5) * 8透明度alpha 128 noise(t * 0.3 100) * 127颜色偏移hue noise(t * 0.2 200) * 360Perlin 噪声的实现我用的是FastNoiseLite库它非常轻量在 ESP32-S3 上跑一次 1D 噪声大约只要 2 微秒。每帧计算 3 次噪声加上绘制圆形的 SPI 传输时间整体帧率能稳定在 35fps 左右。绘制圆形不能用tft.fillCircle()因为那个函数不支持透明度。我的做法是先用tft.fillScreen(TFT_BLACK)清屏然后用tft.drawPixel()逐像素画一个带 alpha 混合的圆。听起来很慢但实际上 240x240 的屏幕圆的直径最大也就 56 像素需要计算的像素点大约 2500 个ESP32-S3 完全扛得住。实操心得如果你觉得逐像素画太慢可以预计算一个圆形模板数组存每个像素相对于圆心的距离。运行时只需要查表加噪声偏移速度能再快一倍。我用的是uint8_t dist_map[56][56]占用 3136 字节对 ESP32-S3 来说九牛一毛。2.3 SPDT 开关的硬件逻辑设计SPDT 是“单刀双掷”开关三个引脚公共端COM、常开端NO、常闭端NC。在 SoulCage 里我用它来实现充电与运行的切换。电路逻辑是这样的开关拨到“充电”位置时COM 连到 NC电池的正极接到 TP4056 充电模块的 B 输入端同时断开 ESP32-S3 的供电。开关拨到“运行”位置时COM 连到 NO电池正极接到 ESP32-S3 的 3.3V 稳压器输入端。这样设计的好处是充电时主控完全断电不会出现“边充边用”导致的电池管理混乱。TP4056 的 BAT 输出直接接电池OUT 输出接负载但我不建议用 OUT 给 ESP32-S3 供电因为 TP4056 的放电保护电流只有 1A 左右ESP32-S3 峰值电流可能超过这个值。更稳妥的方案是电池直接接一个独立的 DW01 保护板再接到开关。在 Tinkercad 里验证这个逻辑很简单用一个 SPDT 开关、两个 LED、两个 330 欧姆电阻和一块 9V 电池。开关拨到一边红灯亮拨到另一边绿灯亮。确认接线无误后再画 PCB。2.4 电池与电源管理吊坠的电池我选的是301230 规格的锂聚合物电池容量 110mAh尺寸 3mm x 12mm x 30mm。这个尺寸刚好能塞进我设计的吊坠外壳里。如果你想要更长续航可以用 401230150mAh或 501230200mAh但外壳要相应加厚。充电芯片用的是TP4056这是最经典的单节锂电充电 IC外围只需要一个电阻设定充电电流、两个 LED 指示状态。充电电流我设定在 100mA对应的电阻值是 10kΩ公式I 1200 / RR 单位 kΩI 单位 mA。100mA 充 110mAh 电池大约 1.5 小时充满对吊坠来说可以接受。稳压部分ESP32-S3 需要 3.3V 供电我用的是ME6211C33这是一颗超低压差 LDO静态电流只有 40uA非常适合电池供电的场景。它的最大输出电流是 500mAESP32-S3 在 WiFi 关闭、屏幕中等亮度下大约消耗 80mA余量充足。注意锂聚合物电池非常娇贵过充、过放、短路都会导致鼓包甚至起火。TP4056 模块一定要买带 DW01 保护芯片的版本或者自己在电池和电路之间加一块保护板。我见过有人直接把电池焊到 TP4056 的 B B- 上结果电池鼓得像个小气球幸好发现得早。3. 实操过程与核心环节实现3.1 在 Tinkercad 里搭建验证电路虽然 Tinkercad 不支持 ESP32-S3但你可以用 Arduino Uno 来验证电源切换逻辑和SPDT 开关接线。具体步骤如下打开 Tinkercad Circuits新建一个电路。从元件库拖入Arduino Uno、SPDT 开关、红色 LED、绿色 LED、两个 330Ω 电阻、9V 电池。接线电池正极接 SPDT 的 COM 端。SPDT 的 NC 端接红色 LED 正极NO 端接绿色 LED 正极。两个 LED 的负极各接一个电阻电阻另一端接电池负极。点击“开始仿真”拨动开关观察 LED 切换。这个仿真验证的是开关在切换时两个回路是互斥的。实际项目中红色 LED 代表“充电中”绿色 LED 代表“运行中”逻辑完全一致。如果你还想验证分压电路可以再加两个电阻比如 100kΩ 和 100kΩ串联在电池正负极之间用 Tinkercad 的万用表测中间点电压。9V 电池经过 1:1 分压中间点应该是 4.5V。实际项目中电池是 3.7V-4.2V分压后是 1.85V-2.1VESP32-S3 的 ADC 量程是 0-3.3V刚好能测。3.2 PCB 设计与打板PCB 我用的是KiCad免费开源功能足够。板子尺寸设计成 28mm x 48mm 的椭圆形厚度 1.6mm。布局上ESP32-S3 模组放在中间偏上屏幕排线接口放在顶部电池放在背面充电模块和开关放在底部。几个设计要点屏幕排线接口ST7789 的 FPC 排线是 0.5mm 间距、8 针需要用一个 FPC 连接器。我用的型号是Molex 5034800800立贴式高度 1.2mm。天线净空区ESP32-S3 模组的 PCB 天线下方不能铺铜也不能走线。我在板子顶部留了 15mm x 8mm 的净空区确保 WiFi 和蓝牙信号不受影响。电池焊盘用两个大焊盘间距 2mm方便焊接电池引线。焊盘旁边丝印标注“”“-”防止焊反。开关开孔SPDT 开关我用的是SS12D00微型滑动开关柄长 3mm需要在外壳上开一个 3mm x 1.5mm 的槽。打板我用的嘉立创5 片 28mm x 48mm 的板子沉金工艺总价不到 30 块钱。从下单到收货大约 5 天。3.3 焊接与组装焊接顺序很重要先焊矮的元件再焊高的元件。我的顺序是ESP32-S3 模组用热风枪 280°C 吹焊或者用烙铁加焊锡膏。模组底部有散热焊盘必须焊牢否则大电流时会不稳定。LDO 和充电 ICME6211C33 和 TP4056 都是 SOT-23-5 封装引脚间距 0.95mm用尖头烙铁加 0.3mm 焊锡丝配合放大镜操作。电阻电容0603 封装用镊子夹住先焊一端再焊另一端。FPC 连接器这是最难的引脚间距 0.5mm我用了助焊剂加拖焊法焊完后用放大镜检查有没有连锡。SPDT 开关直插元件最后焊。电池引线用 30AWG 硅胶线长度 3cm焊到电池焊盘上。注意正负极不要接反。实操心得焊接 FPC 连接器的时候我建议先用高温胶带把连接器固定在 PCB 上防止移位。拖焊的时候烙铁温度设 320°C刀头烙铁比尖头更好用因为刀头能同时接触多个引脚焊锡会自然分开。焊完后用万用表蜂鸣档测相邻引脚确认没有短路。3.4 代码烧录与调试代码烧录用 Arduino IDE板子选“ESP32S3 Dev Module”端口选对应的 COM 口。第一次烧录时需要按住 BOOT 键再按 RESET 键让 ESP32-S3 进入下载模式。烧录完成后按 RESET 键运行。代码结构分为三部分初始化配置 TFT_eSPI、LEDC PWM、ADC。主循环读取加速度计我用的是 LIS3DHI2C 接口根据加速度值调整灵魂动画的参数。动画渲染每帧计算噪声、绘制圆形、刷新屏幕。加速度计的数据用来控制灵魂的“情绪”静止时灵魂缓慢呼吸半径变化幅度小。晃动时灵魂快速跳动半径变化幅度大。翻转时Z 轴为负灵魂变成红色表示“生气”。调试的时候我建议先用Serial.println()输出加速度值确认数据正常后再接入动画逻辑。TFT_eSPI 的tft.setCursor()和tft.print()也可以用来在屏幕上显示调试信息非常方便。4. 常见问题与排查技巧实录4.1 屏幕不亮或花屏这是最常见的问题排查顺序如下现象可能原因解决方法完全黑屏背光没接或没开检查 TFT_BL 是否接 3.3V 或 PWM 输出白屏初始化失败检查 RST 引脚是否接对SPI 频率是否过高花屏SPI 频率过高或走线太长降低 SPI_FREQUENCY 到 27MHz颜色不对颜色顺序配置错误在 User_Setup.h 里调整 TFT_RGB_ORDER显示偏移分辨率设置错误确认 TFT_WIDTH 和 TFT_HEIGHT 与实际屏幕一致我遇到过一次花屏折腾了一下午最后发现是杜邦线太长20cmSPI 信号质量太差。换成 10cm 的线就正常了。所以如果你在面包板上测试尽量用短线。4.2 ESP32-S3 无法进入下载模式这个问题通常和 strapping 引脚有关。ESP32-S3 的 GPIO 0 在上电时如果被拉低会进入下载模式。如果你的电路里 GPIO 0 接了其他外设比如屏幕的 CS上电时屏幕还没初始化GPIO 0 可能被拉低导致芯片一直停在下载模式。解决方法把屏幕的 CS 换到其他 GPIO比如 GPIO 10。或者在上电时确保 GPIO 0 为高电平可以加一个 10kΩ 的上拉电阻。4.3 电池续航太短如果你发现充满电只能用一两个小时检查以下几点背光亮度把 PWM 占空比从 100% 降到 30%续航能翻倍。屏幕刷新率从 60fps 降到 30fps功耗降低约 20%。WiFi 和蓝牙如果不用在代码里调用WiFi.mode(WIFI_OFF)和btStop()关闭。LDO 静态电流ME6211C33 的静态电流是 40uA如果换成普通 LDO比如 AMS1117静态电流 5mA电池几天就耗光了。我实测下来110mAh 电池、背光 30%、30fps、WiFi 关闭的情况下续航大约 5.5 小时。如果你想要更长可以换 200mAh 电池续航能到 10 小时。4.4 灵魂动画卡顿如果动画看起来一顿一顿的先检查帧率。在代码里加一个计数器每秒打印一次帧数。如果低于 20fps可能是以下原因噪声计算太慢FastNoiseLite 虽然快但如果你每帧调用几十次也会拖慢。减少到 3-5 次。逐像素绘制太慢改用预计算模板或者用tft.pushImage()直接推一张预渲染的图片。SPI 传输瓶颈240x240 全屏刷新在 40MHz SPI 下需要约 12ms如果你每帧都全屏刷新帧率上限就是 80fps。但如果你只刷新变化区域速度会快很多。避坑技巧TFT_eSPI 有一个tft.setSwapBytes(true)的设置如果你用 pushImage 显示图片颜色不对的时候试试这个。另外tft.init()之后一定要调用tft.setRotation()否则屏幕方向可能不对。4.5 充电时指示灯不亮TP4056 的充电指示灯逻辑是充电中红灯亮充满绿灯亮。如果两个都不亮检查电池是否接反了。TP4056 的 B 接电池正极B- 接负极接反了芯片不工作。充电电流设定电阻是否焊好。10kΩ 电阻如果虚焊充电电流为 0。USB 供电是否正常。用万用表测 TP4056 的 VCC 引脚应该是 5V。我遇到过一批 TP4056 模块充电指示灯是共阳极的和常见规格相反导致我以为没充电其实是灯亮的方式不对。所以买模块的时候要看清楚规格书。5. 外壳设计与佩戴体验5.1 3D 打印外壳的设计要点外壳我用 Fusion 360 设计分前后两片用 M2 螺丝固定。尺寸是 32mm x 52mm x 12mm比 PCB 稍大一圈留出 2mm 的壁厚。设计要点屏幕开窗屏幕可视区域是 24mm x 24mm开窗做成 23mm x 23mm稍微小一点遮住屏幕边缘的排线。开关开槽SPDT 开关的柄是 3mm x 1.5mm开槽做成 4mm x 2mm留出活动余量。充电口TP4056 的 USB 口是 Micro USB 或 Type-C开槽要对准。我用的 Type-C开槽 9mm x 3.5mm。挂绳孔顶部留一个 4mm 直径的孔穿挂绳用。散热孔ESP32-S3 和 LDO 会发热外壳底部开几个 1mm 的小孔帮助散热。打印材料我用的是PETG比 PLA 更耐摔而且有一定的韧性。打印参数层高 0.2mm填充 20%壁厚 1.2mm。5.2 佩戴舒适度调整吊坠挂在脖子上重量和尺寸很关键。我第一版外壳用了实心填充重量 28 克戴久了脖子酸。第二版改成 20% 填充重量降到 18 克舒服多了。另外挂绳的选择也有讲究。我用的是2mm 直径的伞绳长度 60cm刚好到胸口位置。如果你想要更轻可以用 1.5mm 的蜡线但承重差一些。实操心得外壳的内侧可以贴一层薄海绵或绒布防止 PCB 和外壳摩擦导致短路。我用的是 1mm 厚的 EVA 泡棉剪成和外壳内腔一样的形状用双面胶固定。5.3 后续扩展方向这个项目做完之后我还在想几个扩展方向。一个是加一个电容触摸按键按一下灵魂会做出不同反应比如变颜色、加速跳动。ESP32-S3 自带触摸引脚不需要额外芯片。另一个是加一个微型振动马达灵魂“生气”的时候震动一下反馈更直接。如果你有蓝牙音箱或者智能家居中枢还可以让 SoulCage 通过蓝牙发送状态比如“灵魂开心”时让灯变暖色“灵魂生气”时让灯变红色。ESP32-S3 的蓝牙 5.0 支持 BLE功耗很低对续航影响不大。我个人在实际操作中的体会是这个项目最难的不是代码也不是焊接而是把所有的东西塞进一个足够小的外壳里。我前后改了四版 PCB才把尺寸压到 28mm x 48mm。如果你也想做类似的项目建议先用纸板剪一个和 PCB 一样大的模型把屏幕、电池、开关都摆上去确认空间够用再画板。这个笨办法帮我省了至少三次打板的钱。
返回列表