当前版本:1.2.0
ESP32 + ST7796 TFT(320×240)上的过程式表情眼睛。所有面部几何都由 CPU 实时计算,不依赖任何预渲染图片资源,适合做成桌面 AI 宠物或互动小设备的“脸”。
开机先闭眼,2 秒后睁眼醒过来;之后开始随机眨眼、视线移动和表情切换。触摸屏幕可以立刻互动,串口会输出每一次手势和运行状态:
=== ESP32 TFT Eyes — Pure Procedural ===
[OK] TFT ready (SPI=60MHz)
[OK] Touch ready (XPT2046 CS=33, shared SPI, threshold=350)
[TOUCH] Tap #1
[TOUCH] Tap #2
[TOUCH] Tap #3
[TOUCH] Angry face triggered by taps
[STATS] state=ACTIVE bl=100 interval=25ms temp=42.0C
- 19 种表情预设:Normal、Angry、Glee、Happy、Sad、Worried、Focused、Annoyed、Surprised、Skeptic、Frustrated、Unimpressed、Sleepy、Suspicious、Squint、Furious、Scared、Awe、Coquette
- 随机眨眼、视线跟随与权重化表情切换,全部基于
millis()时间基准,帧率无关 - 4 级电源状态机:ACTIVE → RELAX → IDLE → SLEEP,背光平滑渐变
- XPT2046 触摸:单击反馈、双击复位、三连击触发 Angry、长按复位、上滑撒娇、下滑睡觉
- 芯片温度保护:≥70°C 强制降入 IDLE,≥80°C 强制进入 SLEEP
- 事件驱动渲染:画面静止时停止 SPI 传输,降低待机功耗
- 电源键:BOOT 长按 2 秒关机(深睡),按 BOOT 或 EN 开机
- 触摸校准可运行时调整:串口
cal查看,cal <offset> <range>设置并持久化
需要先安装 PlatformIO(VS Code 扩展或 CLI)。
pio run
pio run --target upload
pio device monitor -b 115200
pio test -e nativeTFT_eSPI 已通过 lib_deps 自动下载;屏幕引脚集中在 src/board_config.h,构建开关在 platformio.ini 中,无需修改 User_Setup.h。
| 组件 | 型号 |
|---|---|
| MCU | ESP32(ESP32-WROOM-32 系列) |
| 屏幕 | ST7796 SPI TFT,320×240 |
| 触摸 | XPT2046,与 TFT 共用 SPI 总线 |
| 背光 | GPIO27(低电平关,高电平开) |
| RGB LED | R=GPIO17 / G=GPIO4 / B=GPIO16(低电平点亮) |
| 光敏 | GPIO34 |
| 电池 | 无板载电量 IC(IP5306 / MAX17048);GPIO39 预留 2:1 分压采样 |
| 信号 | GPIO |
|---|---|
| TFT_SCLK / TOUCH_CLK | GPIO14 |
| TFT_MOSI / TOUCH_MOSI | GPIO13 |
| TFT_MISO / TOUCH_MISO | GPIO12 |
| TFT_CS | GPIO15 |
| TFT_DC | GPIO2 |
| TFT_RST | 不接(-1,屏幕复位接板级 RESET) |
| TFT_BL | GPIO27 |
| TOUCH_CS | GPIO33 |
| BOOT(电源键) | GPIO0,长按 2 秒进入深睡 |
| I2C | SDA=GPIO21 / SCL=GPIO22 |
SPI 频率为 60MHz,RGB 顺序为 TFT_BGR。
配套 CYD 2.4" 的外壳模型(STL)放在 hardware/case/:
- cydcase.stl —— 外壳主体
- CYDcaseDisplay.stl —— 屏幕面板 / 前框
建议 PLA、0.2mm 层高打印,打印前按打印机尺寸检查缩放。
每一帧按顺序经过 5 级变换,输出链式传递:
Transition → Transformation → Variation1 → Variation2 → Blink → FinalConfig → EyeDrawer::Draw()
Transition:表情切换,500ms 从 Snapshot 插值到目标配置Transformation:视线方向与透视缩放,200ms 平滑过渡Variation:呼吸、脉冲等微表情Blink:眨眼,100ms → 50ms → 100ms 的梯形波形EyeDrawer:浮点贝塞尔边界 + 扫描线填充,写入 320×120 的 TFT_eSprite 双缓冲后一次性推送到屏幕
| 状态 | 进入条件(距上次交互) | 背光 | 刷新率 | 表情行为 |
|---|---|---|---|---|
| ACTIVE | 0–60 秒 | 100% | 25ms(40fps) | 完整动画 + 随机表情 |
| RELAX | 60 秒 | 50% | 33ms(30fps) | 固定表情、慢速视线、偶发哈欠 |
| IDLE | 3 分钟 | 25% | 41ms(约 24fps) | 固定 Normal、视线回中、偶发眨眼 |
| SLEEP | 5 分钟 | 0% | 不渲染,200ms 触摸轮询 | Sleepy 闭眼静态画面 |
任意触摸都会回到 ACTIVE 并重置空闲计时。背光使用 Gamma 2.2 感知曲线,状态切换时以缓动曲线平滑渐变(初始快、接近目标慢),避免亮度跳变。
CPU 频率随状态调整:ACTIVE 240MHz、RELAX 160MHz、IDLE 80MHz、SLEEP 80MHz;进入 SLEEP 时发送 DISPOFF (0x28),唤醒时发送 DISPON (0x29) 降低面板功耗。
| 手势 | 动作 |
|---|---|
| 单击 | 快速眨眼作为反馈,重置空闲计时 |
| 双击(300ms 内) | 回到 Normal 表情 |
| 三连击(1.5s 内) | 触发 Angry 表情 |
| 长按(2s) | 回到 Normal 表情 |
| 上滑 | 撒娇(Coquette) |
| 下滑 | 进入睡眠模式(Sleepy + Zzz),约 2 秒后切到低功耗 IDLE,再次触摸唤醒 |
按压力度阈值默认 TOUCH_PRESSURE_THRESHOLD = 350,不同面板可能需要微调。
以下开关都定义在 platformio.ini:
| 开关 | 默认 | 说明 |
|---|---|---|
POWER_BATTERY_SENSE_ENABLED |
1 | GPIO39 接好 2:1 分压后启用电池电压采样 |
POWER_LIGHT_SLEEP_ENABLED |
0 | GPIO36 补 10kΩ 上拉后改为 1,启用 LightSleep |
POWER_TEMP_PROTECT_ENABLED |
1 | 芯片温度保护 |
SERIAL_DEBUG_ENABLED |
1 | 串口调试日志;发布固件可改为 0 关闭 |
电池采样引脚实际在 GPIO39(
board_config.h中PIN_BATTERY_ADC),2:1 分压: BAT+ → 100kΩ → GPIO39 → 100kΩ → GND。
ESP32-demo/
├── .github/workflows/
│ └── ci.yml
├── platformio.ini
├── LICENSE
├── README.md
├── assets/readme/
│ └── hero-1.2.0.svg
├── hardware/case/
│ ├── cydcase.stl
│ └── CYDcaseDisplay.stl
├── docs/
│ ├── 技术文档.md
│ ├── ESP32-WROOM-32_引脚参考手册.md
│ └── ESP32-WROOM-32_引脚功能图解.md
├── test/
│ ├── mocks/
│ └── test_native/
└── src/
├── main.cpp
├── Config.h
├── board_config.h
├── Log.h
├── Animation.h
├── Eye.h
├── Eye.cpp
├── Face.h
├── Face.cpp
├── FacePower.h
├── FacePower.cpp
├── PowerIC.h
├── PowerIC.cpp
├── PowerManager.h
└── PowerManager.cpp
- LightSleep 需在 GPIO36 补 10kΩ 上拉并开启构建开关
- 电池电压采样需在 GPIO39 外接 2:1 分压电阻
- 板载无电量 IC(IP5306 / MAX17048)
- 光敏(GPIO34)未启用
- 触摸阈值和 SPI 频率可能因具体面板需要调整
本项目基于 playfultechnology 的 ESP32 OLED Emotive Eyes 移植改造,原始项目由
Alastair Aitchison 发布,遵循 MIT 许可。本仓库以 GPL-3.0 发布,完整条款见
LICENSE。