
1. 项目缘起与整体设计思路1.1 为什么要做一块“伪”智能手表手上有一块闲置的卡西欧F-91W表带断了表壳也花得不成样子但那个经典的方形表盘和树脂外壳的造型一直让我觉得可惜。与此同时抽屉里躺着几块ESP32开发板平时用来做温湿度采集、蓝牙控制小车之类的项目一直没找到一个能长期戴在身上、又有实用价值的载体。某天刷到有人把ESP32塞进电子表外壳的帖子突然觉得这事儿可以干——用ESP32做核心保留卡西欧的外观风格实现时间显示、温湿度监测、蓝牙通知提醒这些基础功能成本控制在百元以内还能随时改代码扩展功能。这个项目的核心定位很明确不是要替代手机或真正的智能手表而是做一个“带单片机的电子表”。它解决的需求也很具体——我想要一块续航够用、能看时间、能显示环境温湿度、能通过蓝牙接收手机通知提醒的手表同时外观要有复古数码表的味道。适合有基础焊接能力、玩过Arduino或ESP32的爱好者参考纯小白也能跟着做但需要一定的动手能力。1.2 硬件选型的取舍逻辑选ESP32而不是STM32或51单片机理由很直接内置WiFi和蓝牙。蓝牙用来做通知推送和配置WiFi留着以后扩展NTP对时或者OTA升级。51单片机虽然便宜但加蓝牙模块和屏幕驱动之后整体复杂度和成本反而上去了。STM32性能强但蓝牙方案需要外挂模块开发环境对新手也不够友好。屏幕方面我试过0.96寸OLED和1.14寸TFT两种方案。OLED功耗低、对比度高但尺寸太小塞进卡西欧表壳后可视面积不够。最终选了1.14寸ST7789 TFT屏分辨率135x240IPS全视角驱动简单SPI接口占用引脚少亮度也够户外看。电池用3.7V 502030规格的锂聚合物电池容量约250mAh实测中等亮度下能撑6到8小时日常通勤够用晚上充电就行。主控板我选的是ESP32-C3 SuperMini体积小、价格低、支持蓝牙5.0而且引脚布局紧凑刚好能塞进表壳内部。充电管理用TP4056模块带过充过放保护输出接一个ME6211 LDO稳压到3.3V给ESP32和屏幕供电。整个硬件方案的核心思路就是小体积、低功耗、模块化每个部分都能单独替换或升级。1.3 外观方案与结构处理卡西欧F-91W的原装表壳内部空间非常有限直接塞ESP32肯定放不下。我的做法是保留表壳正面和表带接口把后盖掏空用3D打印一个加厚的后盖来容纳电路。表盘部分把原装的液晶屏拆掉换成TFT屏用黑色亚克力板切割出合适的窗口边缘用热熔胶固定。按键方面原装的四个侧键保留两个分别接ESP32的GPIO9和GPIO10用作功能切换和屏幕开关。3D打印后盖的模型我用Fusion 360画的壁厚1.2mm内部留出电池和主板的卡槽充电口开在底部用Type-C母座引出。打印材料用PETG耐温性和韧性比PLA好戴在手上不容易因为出汗变形。整个装配过程不需要螺丝靠卡扣和少量热熔胶固定方便后期拆修。注意拆原装表壳的时候表镜和表壳之间有一圈防水胶圈拆完基本就废了所以这个项目做出来不防水洗手时最好摘下来。2. 核心硬件连接与电路细节2.1 ESP32-C3与ST7789屏幕的SPI接线ST7789用SPI接口驱动ESP32-C3的SPI引脚可以灵活映射我选了一组不冲突的引脚。具体接线如下ST7789引脚ESP32-C3引脚功能说明VCC3.3V逻辑供电GNDGND共地SCLGPIO4SPI时钟SDAGPIO6SPI数据RESGPIO7复位DCGPIO5数据/命令选择CSGPIO10片选BLKGPIO3背光控制背光控制引脚接GPIO3通过PWM调节亮度。实测背光电流约20mA直接由GPIO驱动会超过ESP32单脚推荐电流所以我在背光引脚和屏幕BLK之间加了一个2N7002 NMOS做开关GPIO3控制栅极源极接地漏极接屏幕BLK屏幕BLK再通过一个100Ω电阻接3.3V。这样GPIO只需要提供逻辑电平背光电流走MOS管安全很多。SPI时钟频率我设的是40MHz再高会出现花屏40MHz下刷一整屏大概15ms肉眼看不到闪烁。如果你用的排线比较长建议降到20MHz稳定性更好。2.2 电源管理与充电电路电池正极接TP4056的B负极接B-TP4056的OUT和OUT-分别接ME6211的VIN和GNDME6211的VOUT输出3.3V给ESP32和屏幕。TP4056的充电电流我设的是500mA通过更换RPROG电阻实现公式是Icharge 1200 / RPROG (kΩ)要得到500mARPROG取2.4kΩ。实际焊接时我用的是2.2kΩ充电电流约545mA稍微大一点没关系电池支持1C充电250mAh的电池用500mA充也就半小时左右。ME6211的压差在200mV左右电池电压降到3.5V时输出还能稳在3.3V再低就掉压了。ESP32-C3的工作电压范围是3.0V到3.6V所以电池从4.2V放到3.4V这段时间系统都能正常工作。实测从满电到自动关机大约7小时屏幕亮度50%、蓝牙广播间隔1秒的情况下。2.3 按键与外部中断的实战配置手表上保留了两个物理按键接在GPIO9和GPIO10上另一端接地。按键按下时引脚被拉低所以配置为内部上拉输入。这里我用的是外部中断而不是轮询原因是轮询会占用CPU时间而且按键响应有延迟。ESP32的外部中断配置在Arduino IDE里很简单pinMode(BUTTON_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), handleButton, FALLING);FALLING表示下降沿触发也就是按键按下的瞬间。中断服务函数里我只做一件事设置一个标志位主循环检测到标志位再执行具体操作。千万不要在中断里做耗时操作比如刷屏、读传感器、串口打印否则会触发看门狗复位。我一开始在中断里直接调了屏幕刷新函数结果手表每隔几秒就重启排查了半天才发现是中断里执行时间太长。按键消抖我用的是软件延时消抖在中断触发后记录时间戳如果两次中断间隔小于200ms就忽略。这个方法比在中断里delay靠谱不会阻塞其他中断。3. 软件框架与核心功能实现3.1 Arduino IDE环境搭建与离线包处理开发环境我用的是Arduino IDE 2.3.2ESP32支持包版本2.0.14。国内下载支持包经常失败我的做法是手动下载离线包在Arduino IDE的“首选项”里找到“附加开发板管理器网址”填入ESP32的官方JSON地址然后在开发板管理器里搜索“esp32”选择2.0.14版本安装。如果网络不稳定可以直接去GitHub下载esp32-2.0.14.zip解压到Arduino15/packages/esp32/hardware/esp32/2.0.14目录下重启IDE就能识别。库方面需要装三个TFT_eSPI用于屏幕驱动ESP32BLEKeyboard用于蓝牙HIDAdafruit_SHT31用于温湿度传感器。TFT_eSPI的配置比较特殊需要修改User_Setup.h文件把屏幕驱动型号、引脚定义、SPI频率都改对。我直接把配置文件里的ST7789驱动打开注释掉其他驱动然后填入上面表格里的引脚号。这一步如果搞错屏幕要么不亮要么颜色反色要么偏移。实操心得TFT_eSPI的User_Setup.h修改后最好把整个库文件夹复制一份备份下次换项目直接替换省得重新配。3.2 时间显示与NTP对时逻辑时间显示是手表的基础功能。ESP32本身有RTC但精度一般一天误差几秒到几十秒。我的方案是开机时连WiFi用NTP对时然后断开WiFi靠RTC走时。NTP服务器用pool.ntp.org时区设成东八区代码里用configTime(8 * 3600, 0, pool.ntp.org)。对时成功后把时间写入RTC之后每24小时重新对一次或者手动按键触发对时。屏幕刷新策略上我只刷新变化的部分而不是整屏重绘。比如秒数变化时只更新秒数所在的区域背景不重画。这样刷屏时间从15ms降到2ms左右功耗也低。TFT_eSPI提供了sprite功能可以创建一个内存画布先在画布上画好再一次性推送到屏幕避免闪烁。我用了一个240x135的sprite占用约64KB内存ESP32-C3的400KB RAM完全够用。时间显示的字体我用的是TFT_eSPI自带的FreeSansBold24pt数字够大一米外能看清。日期和星期用小一号的字体放在下方。整个表盘布局模仿卡西欧的经典风格上方显示时间中间显示温湿度下方显示蓝牙连接状态和电池电量。3.3 蓝牙通知提醒与HID实现蓝牙部分我用了BLE HID方案把ESP32模拟成一个蓝牙键盘手机连接后收到通知时ESP32会收到按键事件然后触发屏幕显示提醒。具体实现是ESP32作为BLE HID设备广播手机配对后在手机端设置里开启“通知访问权限”把通知转发到ESP32。ESP32收到通知后在屏幕上弹出一个提示框显示“新消息”并振动一下振动马达接在GPIO1上通过MOS管驱动。这里有个坑ESP32-C3的BLE和WiFi不能同时开只能二选一。所以我的逻辑是开机先连WiFi对时对时完成后关闭WiFi再启动BLE。这样时间准了蓝牙通知也能用。如果你需要同时用WiFi和蓝牙得换ESP32-S3它支持双模共存。振动马达我用的是1027扁平马达额定电压3V电流约80mA。GPIO1通过2N7002驱动栅极串一个100Ω电阻源极接地漏极接马达负极马达正极接3.3V马达两端反并联一个1N4148二极管做续流防止关断时反向电动势打坏MOS管。这个电路我实测了上百次开关没出过问题。3.4 温湿度采集与屏幕布局温湿度传感器我用的是SHT31I2C接口精度±2%RH和±0.3°C比DHT11靠谱得多。接线很简单VCC接3.3VGND接地SDA接GPIO8SCL接GPIO9。注意GPIO9同时被按键占用所以我把按键改到了GPIO10和GPIO11避免冲突。I2C地址是0x44代码里用Adafruit_SHT31 sht31 Adafruit_SHT31();初始化每5秒读一次读到的温度和湿度显示在屏幕中间区域。屏幕布局我调整了好几版最终定下来的是顶部区域时间大字体居中显示中部左侧温度带°C符号中部右侧湿度带%符号底部左侧蓝牙图标连接时显示实心未连接显示空心底部右侧电池图标根据电压显示电量格数电池电压采集用ESP32-C3的ADC接一个100kΩ和100kΩ的分压电阻把电池电压降到一半再进ADC。ADC参考电压是3.3V12位分辨率所以电压计算公式是Vbat (ADC值 / 4095) * 3.3 * 2实测ADC读数有±50mV的波动我在代码里做了滑动平均滤波取最近10次读数的平均值显示就稳定了。4. 常见问题与排查技巧实录4.1 屏幕不亮或花屏的排查思路屏幕问题是最常见的我遇到过好几次。排查顺序如下先查背光用万用表测BLK引脚电压如果是0V说明背光控制没生效。检查GPIO3是否配置为输出MOS管是否焊反。再查SPI通信用逻辑分析仪抓SCL和SDA波形如果没有波形说明SPI初始化失败。检查User_Setup.h里的引脚定义是否和实际接线一致。最后查复位时序ST7789的RES引脚需要先拉低再拉高延时至少10ms。如果复位不对屏幕会一直白屏或花屏。我在代码里加了digitalWrite(RES, LOW); delay(10); digitalWrite(RES, HIGH); delay(120);问题解决。花屏还有一种可能是SPI频率太高降到20MHz试试。如果颜色反了在User_Setup.h里把TFT_RGB_ORDER改成TFT_BGR。4.2 蓝牙连接不稳定或频繁断开的处理BLE连接不稳定通常有三个原因天线布局、电源噪声、广播间隔。ESP32-C3的板载天线对周围金属很敏感我把主板放在电池正上方时蓝牙信号明显变差后来把主板移到表壳顶部天线朝外信号就稳了。电源噪声方面我在ME6211输出端并了一个100μF钽电容和一个0.1μF陶瓷电容滤掉高频纹波蓝牙断连次数从每天十几次降到几乎为零。广播间隔我设的是500ms太快费电太慢手机发现不了。连接参数里把slave latency设成0connection interval设成30ms响应速度够快功耗也能接受。4.3 电池续航短与充电异常的解决续航短一般是屏幕背光太亮或蓝牙一直广播。我的做法是屏幕默认30秒无操作自动熄屏按键唤醒蓝牙在无连接时进入低功耗广播模式连接后正常。实测这样设置后续航从4小时提升到7小时。充电异常最常见的是TP4056发热严重。如果充电电流设得太大TP4056会烫手甚至触发过热保护。我把RPROG从1.2kΩ换成2.2kΩ后充电电流降到545mA温度控制在50°C以内。另外TP4056的B和B-到电池的线要尽量短线太长会导致充电电压跌落充不满。4.4 常见问题速查表现象可能原因解决方法屏幕白屏复位时序不对检查RES引脚延时屏幕花屏SPI频率过高降到20MHz颜色反色RGB顺序错误改TFT_RGB_ORDER蓝牙频繁断连天线被遮挡调整主板位置续航短背光常亮加自动熄屏逻辑充电发热充电电流过大换大RPROG电阻按键无响应中断冲突检查引脚占用时间不准RTC漂移每天NTP对时一次独家避坑ESP32-C3的GPIO9是BOOT引脚上电时如果被拉低会进入下载模式。我把按键接在GPIO9上时每次按着按键开机手表就进不了正常程序。后来把按键改到GPIO10和GPIO11问题消失。如果你非要用GPIO9记得在按键和引脚之间串一个10kΩ电阻并且不要在上电时按住。5. 外壳装配与佩戴体验优化5.1 3D打印后盖的模型调整后盖模型我改了五版才定型。第一版太厚戴在手上像块砖第二版太薄电池鼓包后盖会裂第三版卡扣太紧拆一次断一次。最终版的壁厚是1.2mm内部留了0.5mm的余量给电池和主板卡扣用悬臂梁结构拆装十几次都没断。打印参数层高0.16mm填充20%打印温度240°C热床80°C速度50mm/s。PETG打印出来表面有点拉丝用打火机快速燎一下就去掉了。表带接口我保留了原装的弹簧杆但原装表带太硬戴久了手腕不舒服。我换了一条22mm宽的硅胶表带柔软透气颜色选了黑色和表壳搭配。表带连接处用3D打印的转接件把弹簧杆固定在打印件上再用M2螺丝锁紧。5.2 佩戴舒适度与散热处理ESP32和屏幕工作时会发热尤其是蓝牙广播时主板背面温度能到45°C左右。直接贴着手腕会不舒服我在主板和表壳之间垫了一层0.5mm厚的导热硅胶垫把热量导到表壳背面再通过表壳散出去。实测佩戴时表壳背面温度在38°C左右可以接受。重量方面整块手表含电池和表带约52克比原装卡西欧重了20克但戴习惯了没什么感觉。如果你追求轻量化可以把电池换成200mAh的能减重5克左右。5.3 日常使用中的小技巧充电用5V 1A的充电头不要用快充头TP4056不支持快充协议快充头可能不输出。防水不防水洗手、下雨天最好摘下来。清洁屏幕用眼镜布擦表壳用酒精棉片擦不要用丙酮会腐蚀PETG。固件升级我把OTA功能留着了连上WiFi后可以通过Arduino IDE的OTA功能无线烧录不用拆壳。这个项目从画图到装配花了大概三个周末中间踩了不少坑但做出来的效果挺满意。它不是什么高科技产品就是一块带蓝牙通知和温湿度显示的电子表但每次抬手看时间的时候都会觉得这块表比买来的有意思。后续我打算加一个计步功能用MPU6050做姿态解算再把屏幕换成触摸的这样交互会更方便。如果你也想做一块建议先从点亮屏幕开始一步步来别想着一次把所有功能都塞进去。