过去一个月,我把手里一块吃灰的墨水屏拆了出来,认认真真做了一款能戴出门的智能手表:Arduino 环境编程,低功耗内核驱动,官方标称和实测续航都奔着 30 天去。它支持自定义表盘,也能接蓝牙和 Wi-Fi,实时天气、番茄闹钟、指南针这些实用功能一个不少,而且整套方案完全开源。
为什么做这件事?市面上大牌智能手表我戴过不少,最大的痛点不是功能少,而是续航和封闭。每天晚上摘下来充电、睡眠监测只给一个笼统分数、表盘壁纸想换却发现商店里全是付费款。你不能真正改动它,它也不真正属于你。而这颗 Arduino 墨水屏手表给了我完全的控制权:想画什么表盘自己画,想加什么传感器自己焊,续航按周算而不是按天算。这篇文章就把从硬件选型、软件架构到功耗调优、踩坑排错的全过程摊开讲,适合有一定 Arduino 基础、想跳进智能穿戴坑的朋友参考。
1. 这类墨水屏手表,到底在解决什么痛点
1.1 传统智能手表的续航与生态困境
现在的主流智能手表,功能确实强大:心率、血氧、GPS、NFC、消息推送、支付,几乎是一个戴在手腕上的手机。但代价同样明显——几乎所有彩屏手表都逃不开一天一充甚至半天一充的宿命。我身边不少朋友戴到后来,干脆把常亮屏幕关了、消息推送也关了,只留一个抬手看时间的功能,手表彻底退化成一块看时间的电子表。
问题在于"屏幕"本身。AMOLED 和 LCD 都是主动发光器件,只要亮着就在持续消耗电流。哪怕是息屏显示(AOD),屏幕也无法完全断电,整机待机功耗很难压到 1mA 以下。再加上连续心率监测、GPS 常驻、蜂窝网络待机,续航就成了无解的数学题。
封闭生态又是另一重烦恼。你可以换表盘,但只能从官方商店里选;你可以装应用,但权限和 API 都被框死。想做一个"下午 3 点提醒我吃维生素"的专属小组件,系统根本不给你入口。这种不可定制性,对喜欢折腾的开发者来说就是原罪。
1.2 墨水屏方案的独特体验
电子墨水屏是反射式显示,靠环境光折射成像,本身几乎不耗电,只有刷新瞬间才需要电流。这一点和纸质的体验非常接近,强光下反而越看越清楚。黑色墨水屏在静态显示时整机可以做到微安级别的待机电流,这给"长续航"提供了最底层的物理基础。
当然,它也有明显的局限:黑白画面、刷新速度慢、没有流畅动画。但对于手表这种以"看时间、看天气、看提醒"为核心的设备来说,这些都是可以接受的代价。我用下来的感受是:低刷新率反而逼着表盘设计回归简洁和信息优先,配合 200x200 分辨率,观感很像一块精致的复古电子表,风格很抓眼球。
1.3 开源与 Arduino 生态的门槛意义
Arduino 最大的价值不是性能,而是把嵌入式开发的门槛降到了一种近乎"拿起就能写"的程度。丰富的库、成熟的社区、统一的封装,让从没碰过低功耗开发的人也能在几天内点亮屏幕。开源的硬件文件又可以随意改 PCB 和外壳,不必从头画板子。
这种"开源 + Arduino"的组合,让原本只存在于代工厂里的智能手表,变成了普通开发者桌上的一个周末项目。你不用懂射频天线设计,不用啃几千页芯片手册,只要会接线、能写一点 C++,就能拥有一款完全属于自己的手表。对想入门嵌入式的人来说,这个项目比 Arduino 官方教程里的 LED 闪烁有吸引力得多。
2. 硬件架构与选型:兼顾续航、体积与可玩性
2.1 主控选择:低功耗蓝牙方案还是双模芯片
整机选型的第一关键就是主控,它直接决定功耗上限、无线能力和开发体验。市面上这类 DIY 墨水屏手表常见两条路线:
- 路线 A:低功耗 BLE 主控 + 外挂 Wi-Fi 模块。典型是 nRF52 系列芯片,蓝牙功耗极低、深度睡眠能做到微安级别,Arduino 支持也很完善;Wi-Fi 单独用一个模块(比如 ESP 系列 AT 指令模块),平时彻底断电,只在同步天气或校时时临时上电。
- 路线 B:直接使用 ESP32 这类双模芯片。一颗片子同时搞定蓝牙和 Wi-Fi,电路简单、开发资料海量,但芯片基础功耗比专用 BLE 芯片高不少,深度睡眠要做到极低需要费更多功夫,30 天续航会显得勉强。
我最终采用了路线 A:主控用 nRF52840 这颗低功耗芯片,外挂一颗 Wi-Fi 模块,用一颗 GPIO 控制模块的供电。这样做的直接收益是待机能压到几微安,同时蓝牙连接功耗也只有毫安级,换来了可观的续航余量。代价是电路上多几个器件,固件里多一层"Wi-Fi 模块开/关"的状态管理,但整体完全可控。
如果你不想处理两颗芯片的配合,或者对 30 天续航没有硬性要求,用 ESP32 系列直接做也完全成立,后面我在功耗章节会专门说两条路线的差异。
2.2 墨水屏选型与驱动接口
墨水屏的尺寸和颜色直接影响观感和功耗。我用的是 1.54 英寸黑白墨水屏,分辨率 200x200,SPI 接口,SSD1681 驱动 IC。这个尺寸放在表盘上比例协调,像素密度够用,驱动库也非常成熟。
为什么不用三色屏(黑白红)?三色屏刷新需要多帧数据,刷新速度更慢,残影问题更明显,驱动也更复杂。在一款以"续航和简单可靠"为核心的手表上,黑白屏的体验反而是最优解。黑白模式下静态显示功耗为零,刷新一次约 20-30mA 电流、持续 1-2 秒,这个数据在后面功耗模型中很关键。
墨水屏走 SPI,手表主控有硬件 SPI 接口就直接复用。注意把 CS、DC、RST、BUSY 分别接到固定的 GPIO 上,方便驱动库配置。
2.3 传感器与电源系统
手表需要指南针,我选了一颗低功耗 I2C 磁力计(型号选 QMC5883L 这类常见芯片即可,成本和采购都很方便)。它平时功耗只有 0.1mA 左右,但我在设计上还是给它单独走了一路 GPIO 供电,只有进入指南针界面时才打开,彻底避免待机漏电。
电源部分,电池用了 300mAh 聚合物锂电池,充电管理模块是常见的 TP4054,带 Type-C 充电口。这里有个建议:加一颗 I2C 电量计芯片(比如 MAX17048 或同等级器件)而不是只靠电压估算电量,手表 UI 里的"电量百分比"才能准确。RTC 我用外部 32.768kHz 晶体配合主控内部 RTC 做本地时钟,专用外部 RTC 芯片功耗极低、精度也更好,在此之上做闹钟唤醒机制最可靠。
2.4 你还需要的其他物料
- 表壳与表带:3D 打印外壳 + 22mm 标准表带,外壳内部预留天线伸出位置
- 按键:至少两颗物理按键(确认/返回),我用的是轻触微动开关
- 蜂鸣器或振动马达:番茄钟提醒用,小振子马达功耗 100mA 左右,只在提醒瞬间开启
- 备用电池座:纽扣电池给 RTC 单独供电,主电池取下时时间不丢
这些物料拼起来,整体成本可以控制在百元上下,这也是开源方案最能打动人的地方。
3. 软件实现:从点亮屏幕到跑通完整功能
3.1 开发环境与 Arduino 库配置
开发环境是最常见的 Arduino IDE,给主控安装对应的 Arduino 核心包后,就可以像写普通开发板程序一样写固件。墨水屏驱动直接用社区里现成的库,比如 GxEPD2 系列,它把不同尺寸、不同驱动 IC 的屏幕都封装统一了,只需要在初始化时指定屏幕型号和引脚。
我的工程结构分三层:
- 硬件抽象层:封装屏幕、RTC、传感器、Wi-Fi 模块的初始化与读写
- 应用逻辑层:状态机管理手表处于"表盘界面/菜单界面/功能界面"
- UI 渲染层:统一负责绘制表盘、菜单、天气图标、指南针箭头
这样分层的好处是后期加功能、换屏幕型号都只要动对应层,不用把杂七杂八的代码堆在 loop 里。
3.2 表盘自定义机制的实现思路
自定义表盘是很多人入坑的第一动机。我的做法是定义一套简单的"表盘描述结构":每种表盘是一个绘制回调函数,系统在刷新表盘时调用它,把时间、日期、天气、电量等数据画到显示缓冲区。
struct WatchFace { const char *name; void (*draw)(DrawingContext *ctx); }; void drawClassicFace(DrawingContext *ctx) { ctx->clearScreen(WHITE); ctx->drawTime(hour, minute); ctx->drawDate(day, month); ctx->drawBatteryPercent(batteryPercent); if (weatherAvailable) { ctx->drawWeatherIcon(weatherCode); ctx->drawTemperature(temperature); } } void drawMinimalFace(DrawingContext *ctx) { ctx->clearScreen(WHITE); ctx->drawLargeTime(hour, minute); }用户可以在手表菜单里切换当前表盘,也可以把新的绘制函数写进数组里重新编译。想要做表盘市场也很简单:把绘制函数做成可下载的代码模块,按名字注册到系统即可。这种回调机制虽然朴素,但足够完成 90% 的自定义需求。
3.3 菜单与按键交互逻辑
手表只有两颗按键,交互逻辑必须简单直接。我的状态机大概是这样的:
- 表盘界面:短按确认键进入菜单,短按返回键切换到下一张表盘
- 菜单界面:上/下选择功能项,按确认进入
- 功能界面:返回键退出
菜单项包括:天气、番茄钟、指南针、设置、表盘选择。进入功能模块后再配合"长按/短按"组合操作。注意墨水屏反应慢,按键反馈不能靠屏幕实时重绘,我做了"按下时蜂鸣器轻响 + 屏幕整页更新"的机制,手感上基本可用。
3.4 首次点亮屏幕的几个关键细节
- 电压匹配:墨水屏一般工作在 3.3V,主控和屏幕供电务必统一,否则刷新时会出现花屏
- BUSY 引脚一定要接:墨水屏刷一帧需要时间,BUSY 信号告诉主控"现在不能再发指令",如果省略这个引脚,时序错乱会导致残影和乱码
- 刷新方式区分:全屏刷新(full refresh)适合切换表盘、大模式变化;局部刷新(partial refresh)适合只更新时间数字,局部刷新耗电小,但连续使用会产生残影
我建议首次跑通时,先画一个纯色块并连续刷新 50 次,如果画面稳定无残影,再进行下一步功能开发。
4. 四大功能的工程化落地
4.1 蓝牙连接与数据同步:手表如何与手机联动
蓝牙是这颗主控的主场。nRF52 系列自带的 BLE 协议栈稳定性不错,在 Arduino 环境下也提供了 BLE 库,直接以 GATT 方式暴露服务即可。我创建的服务包含三个特征:
- 手表数据特征:上报电量、日期、当前表盘编号
- 手机命令特征:下发校时指令、天气同步请求、番茄钟配置
- 推送通知特征:接收手机通知内容,显示为一条短文本
配对方式采用"无配对 + 固定服务 UUID",简单来说就是手表端开启广播后,手机会在专有 App 或串口调试工具里看到设备,连接后服务就会自动出现。这个方案省去配对码流程,开发效率高;代价是隐私性弱一些。如果做成产品,建议补上配对绑定和安全认证。
我在手机上先用现成的 BLE 调试工具开发协议,等消息格式稳定后再考虑做 App。蓝牙推送对功耗的消耗并不大,一次小数据包的发送电流也就几毫安,关键是不要频繁让手表保持监听状态——手表平时处于深度睡眠,仅在有事件需要同步时才被唤醒打开蓝牙。
4.2 实时天气:API 拉取与本地缓存策略
天气功能依赖 Wi-Fi 模块联网拉取数据。我的实现流程是:
- 主控定时唤醒 Wi-Fi 模块(默认每 6 小时一次)
- 通过 AT 指令连接热点、发起 HTTP GET 请求
- 获取 JSON 数据,用轻量 JSON 解析库提取温度、湿度、天气代码
- 把结果缓存到本地,再进入深度睡眠
这里有个关键设计:手表不会每次唤醒都联网,而是把上次成功抓到的天气数据缓存起来,刷新表盘时先画缓存,如果数据超过 3 小时再触发新一轮同步。这样即使网络失败,表盘上也不会出现空白天气区域。
天气图标我在墨水里自己画了几组基础图形:晴、多云、阴、雨、雪、雾,用简单位图数组表示。图标不要画得太复杂,200x200 分辨率下 32x32 像素的简单形状最清晰。
4.3 番茄闹钟:低功耗定时与通知机制
番茄闹钟本质是一个带状态的定时器。我设计了三段流程:
- 空闲:默认状态,不做计时
- 专注:默认 25 分钟倒计时
- 休息:默认 5 分钟倒计时
手表进入番茄计时后,主控完全可以在深度睡眠下等待,因为外部 RTC 会在设定的计时结束时产生闹钟中断,唤醒主控去触发振动提醒。这样整个番茄钟期间整机功耗极低,几乎不额外耗电。
定时到点后,我让振动马达振动 3 秒,屏幕上弹出提示文字 "Focus Done"。这个功能虽然简单,但是特别容易做成"用完就忘",你可以在 UI 上把最近 7 天的番茄完成数显示成一个简单统计条,变成一个小成就感来源。
4.4 指南针:磁场传感器与校准
指南针功能使用磁力计芯片读取三轴磁场数据,计算方向角度后画出指向箭头。理论上只要读取 X/Y 轴数据并带入 atan2 公式就能得到方位角,实际落地却有三个坑:
- 周围铁磁性物体干扰:表带扣、表壳螺丝、甚至主板上走线都会偏移读数,必须在固定硬件环境下校准
- 倾斜补偿:简单 atan2 只适合水平持表,戴在手腕上必然有倾斜角,需要引入加速度计数据做角度补偿
- 硬铁校准:我写了一段校准程序,让用户在手表面朝 8 个方向旋转一圈,采集最大最小值生成偏移量,把偏移量存到 Flash,之后再绘制方位角才有参考意义
我要提醒你:指南针这种功能非常考验"细节感知",如果只做一个原始读数显示,你会觉得怎么转都偏得厉害。我在 UI 里加了"校准中"提示状态,并让用户明确知道磁场环境的影响,这个体验才能真正用起来。
5. 30 天续航的实战调优
5.1 墨水屏功耗模型
续航优化的本质是把每一毫安时都用明白。我先给出墨水屏自身在这款手表上的典型工作电流:
| 场景 | 电流 | 持续时间 | 说明 |
|---|---|---|---|
| 静态显示 | 0mA | 无限 | 墨水屏静态不耗电 |
| 全屏刷新 | 20-30mA | 1-2秒 | 切换表盘、重绘大内容时 |
| 局部刷新 | 8-15mA | 0.5-1秒 | 仅更新时间/日期数字 |
| 深度睡眠 | 5-10uA | 多数时间 | 主控低功耗模式 + RTC 跑时 |
可以看到,墨水屏的优势极其明显:它不像液晶屏有一个"背光持续耗电"的问题,静态显示完全不花钱。整个系统的耗电大头在无线模块和刷新动作,所以优化的方向就是减少刷新次数、缩短无线模块的开启时间。
5.2 睡眠架构与任务调度
我设计的日常佩戴场景大致是这样的:
- 表盘界面是默认状态,主控深度睡眠,RTC 每 1 分钟产生一次唤醒中断,主控快速读取时间并绘制一次局部刷新后立刻睡回去
- 每 6 小时额外触发一次 Wi-Fi 模块上电同步天气
- 手表收到蓝牙推送事件时,由 BLE 模块发起唤醒
这套架构意味着主控大多数时间处于微安级睡眠,只有每分钟 0.6 秒左右的"表盘绘制窗口"处于活动状态。局部刷新消耗很小,真正大头是每 6 小时一次的 Wi-Fi 同步。我把 Wi-Fi 模块的供电管脚单独控制,平时它是完全断电的,同步时上电、联网、拉数据、断电,全程控制在 10 秒内。
5.3 实测功耗数据与续航换算
我这里做一个典型的折算,假设电池容量 300mAh:
| 耗电来源 | 单次耗电 | 每天次数 | 日耗电量 |
|---|---|---|---|
| 表盘局部刷新 | 约 0.003mAh | 每分钟 1 次、全天 1440 次 | 约 4.3mAh |
| 表盘全屏刷新 | 约 0.01mAh | 切换表盘/菜单 20 次 | 约 0.2mAh |
| Wi-Fi 天气同步 | 约 0.1-0.2mAh | 4 次(每 6 小时 1 次) | 约 0.6mAh |
| 蓝牙推送/校时 | 约 0.01-0.05mAh | 少量 | 约 0.2mAh |
| 深度睡眠静态 | 约 0.005-0.01mA | 24 小时 | 约 0.2mAh |
合计日耗电量大约在 5.5mAh 上下。这样算下来,300mAh 电池的理论续航为 300 / 5.5 ≈ 54 天。实际测试中我测得的日耗约 8-10mAh,主要误差来自每次局部刷新时间偏长、偶尔菜单操作频繁、以及个别外设漏电。最终实测定在 28-35 天之间,标题里写 30 天完全站得住。
如果你用的是 ESP32 双模方案,基础待机电流可能就有几十微安到几百微安,加上 Wi-Fi 功能耦合在同一颗芯片上,每天多耗 2-3mAh,续航会缩水到两星期左右。所以真要追 30 天这个数字,低功耗 BLE 主控加独立 Wi-Fi 模块的组合几乎是最省心的答案。
5.4 软件层面的低功耗细节
除了硬件上的断电控制,固件里还有几个容易漏掉的点:
- 所有未使用的 GPIO 都设置成输出低电平,避免浮空引脚造成的漏电
- 外设时钟在进入睡眠前全部关闭,只保留 RTC 时钟源
- 磁力计、屏幕、电量计等 I2C 器件都要有单独的使能引脚,睡眠前下电
- 局部刷新频率别超过每分钟 1 次,刷新越快耗电越多,而且会加剧残影
我调试功耗时习惯用串口打印关键事件点,再配合微安级电流表观察整机电流波形。你会发现"看似睡了,实际某个外设还醒着"的情况非常常见。
6. 踩坑记录与排错经验
6.1 墨水屏刷新残影与偶发花屏
这是我遇到最多的一个问题。墨水屏在局部刷新后会在旧画面基础上叠加像素,长时间不清屏就会有一层淡淡的残影。我在一开始为了省电,几乎只用局部刷新,结果两天后表盘数字旁边出现了一块块灰斑,非常难看。
解决方法是约定一条规则:连续局部刷新 30 次后,强制做一次全屏刷新来清理残影;每次切换表盘必须全屏刷新。另外我还发现,屏幕驱动电压不稳时也容易出现闪现的全屏乱码,这种情况多半是电源路径上电池电压太低或 SPI 走线太长,排查时可以加一颗大一点的电源滤波电容。
6.2 天线与外壳对蓝牙、Wi-Fi 的影响
蓝牙信号弱、Wi-Fi 连不上,很多时候不是芯片选得不好,而是天线被"捂住"了。第一版 3D 打印外壳我为了合身,把整个 PCB 包得严严实实,蓝牙穿墙壁时连接速度明显变慢。后来发现主控的蓝牙天线区域周围被外壳和表带扣遮挡,相当于在手机信号测试里用手握住了天线。
调整方式很直接:PCB 上天线区域不能铺铜、不要走线,外壳在这个位置留出开槽或让天线微微露出。Wi-Fi 模块则尽量靠近外壳开孔处,并保证连接天线区域周围没有金属件。改完外壳重测,蓝牙的信号直线距离从几米提升到十几米。
6.3 休眠功耗死活降不下来
调试几天后整机待机电流仍然有 1mA 左右,排查了很久才发现是磁力计芯片还在工作。它虽然是 I2C 接口,但芯片内部没有自动断电功能,我虽然在睡眠前没有主动操作它,它却因为有电源而保持运行。把 sensor 的供电切换到 GPIO 控制后,待机电流直接从 1mA 跌到了 20uA 以下。
这个坑几乎是所有低功耗项目都会遇到的:你以为关闭了芯片的"工作模式",实际上芯片可能还在偷偷跑内部时钟或测量电路。最稳妥的省电方式永远是"物理断电"——用 GPIO 控制外设电源脚,而不是只依赖软件开关。
6.4 表盘渲染速度慢、切换卡顿
墨水屏 1-2 秒的刷新速度无法通过软件优化改变,但体验上可以做调整。最初我每次从菜单返回表盘都会全屏刷新,导致操作感很笨重。后来我把"返回表盘"改成局部刷新,只更新时间、天气等变化区域,保留背景框架,切换速度明显提升。
同时要留意 SPI 通信速率。墨水屏驱动 IC 支持一定的 SPI 速率上限,超出了虽然不会报错,但可能出现偶发刷新错误。我在实际调试中把 SPI 频率锁定在 4MHz 左右,兼顾速度和稳定性。
7. 我的个人体会与后续扩展
这个项目做完之后,我对智能穿戴设备的理解变了很多。以前觉得手表就是要"什么都干、随时在线",做完这款墨水屏手表才发现,真正的刚需可能只是看时间、看天气、接收几条重要提醒,而这些东西用一块反射屏就足够了。30 天长续航带来的安心感,比一天一充的多彩动画实在得多。
我建议第一次尝试的人不要一开始就把所有功能都堆上。先做亮屏、画表盘、跑 RTC 这三个基础点,再逐步引入蓝牙、Wi-Fi、传感器。每一步都验证功耗和功能正常后再继续,你会发现在低功耗嵌入式开发这条路上,踩坑是常态,但每个坑都能学到东西。
后续如果想继续扩展,可以参考几个方向:加入三轴加速度计实现计步和抬腕亮屏、把天气数据源换成更精细的分钟级降雨预报、给表盘渲染加一层简单的 Lua 脚本引擎、甚至做一个小型表盘商店让社区提交自己画的设计。这个项目的天花板不低,而起点就在你桌上那套 Arduino 和墨水屏上。