项目概述
什么是番茄钟?
        番茄钟是一种时间管理方法,全称是“番茄工作法”,由弗朗西斯科·西里洛在1980年代创立。简单说,它的核心流程就像这样:专注工作 25 分钟(这25分钟叫“一个番茄”)> 休息 5 分钟。> 每完成 4 个“番茄”后,进行一次 15分钟的较长休息。
        基于 ESP32 的桌面番茄钟,集成ST7789 TFT 彩屏(240×240)和 TM1637 数码管,支持双屏同步倒计时显示、休息动画播放、断电记忆保存、可自定义工作时长。

项目文件结构:

PomodoroYueXin/
├── PomodoroYueXin/
│   ├── PomodoroYueXin.ino     # 主程序
│   ├── REST_anim.h            # 动画帧索引表
│   ├── REST_0.h ~ REST_13.h   # 14 帧 RGB565 动画数据
│   ├── WORK.h                 # 专注模式背景图
├── REST.gif                   # 休息动画源文件
├── WORK.png                   # 专注模式背景图源文件
├── convert.cs                 # GIF 转 RGB565 转换器
└──convert_png.cs              # PNG 转 RGB565 转换器

项目亮点

  • 双屏同步:TFT 彩屏显示状态与动画,TM1637 数码管同步倒计时
  • 断电记忆:关机后自动保存当前状态、倒计时时间、工作周期、自定义时长
  • 番茄工作法:25 分钟专注 → 5 分钟短休 × 3 次 → 15 分钟长休 → 循环
  • 最后 10 秒提示:专注模式最后 10 秒蜂鸣器急促滴答提醒
  • 快捷操作:短按/长按/组合键实现重置、调整、恢复出厂

项目难点及解决方案

难点 解决方案
闪存容量有限(约 3MB) 动画步进=2(14 帧),每帧 ~112KB,合计 ~1.54MB + 背景图 ~115KB + 代码 ~100KB,总 ~1.75MB,留有余量
双屏同步刷新 TM1637 用硬件 I²C 模拟,TFT 用 SPI,两者独立,loop 中非阻塞轮询
动画不遮挡文字 pushImage 只推送 y=24~216 区域(偏移 24×240),上下各留 24px 给文字
断电记忆版本兼容 NVS 存储使用版本号(ver=2),loadNVS() 检查版本,避免旧数据解析错误
按键消抖与长短按区分 200ms 消抖 + 1000ms 长按阈值 + longHandled 标志防止短按误触

一、硬件系统部分

1.1 硬件清单

硬件 数量 说明
零知派ESP32开发板 1 主控,3MB 可用闪存
零知派ESP32扩展板 1 自带专属插口和按键
ST7789 TFT 彩屏(240×240) 1 主显示屏幕
TM1637 四位数码管模块 1 倒计时数字显示
无源蜂鸣器 1 响铃提醒
杜邦线 若干 接线
数据线 1 烧录代码,给ESP32上电

1.2 接线方案

ESP32 引脚 连接目标
GPIO16 TM1637 CLK
GPIO17 TM1637 DIO
3.3V TM1637 VCC
GND TM1637 GND
GPIO2 蜂鸣器正极
GND 蜂鸣器负极

1.3 硬件连接图

1.4 实物连接图


二、软件架构设计

2.1 系统初始化

setup() 执行流程:

上电
  └→ 串口初始化
  └→ 配置按键 GPIO(INPUT_PULLUP)
  └→ 配置蜂鸣器 GPIO
  └→ bootAnimation()
       ├→ TM1637 亮度 7,显示 88:88 冒号闪烁(2.5 秒)
       └→ TFT 显示 "YueXinMiao / Pomodoro"
  └→ loadNVS()
       └→ 从 NVS 恢复断电前状态(含版本检查)
  └→ showTime(remainingSeconds)  → TM1637 显示当前剩余时间
  └→ showWorkUI() / showRestUI() → TFT 显示对应界面
  └→ 如运行中,设置 lastTick = millis()

改动bootAnimation() 中 tft.setRotation() 设置屏幕旋转方向,可设置为 0,1,2,3

2.2 主循环逻辑

loop() 每轮执行以下任务(非阻塞轮询):

loop()
  ├── 工厂重置检测(仅调整模式,S2+S3 长按 3 秒)
  ├── handleModeButton()     ← S3:模式切换 / 调整减
  ├── handleStartPause()     ← S2:开始暂停 / 调整加
  ├── handleReset()          ← S1:重置 / 进入退出调整
  ├── 倒计时递减(每秒)
  │     ├→ 归零时 beepOn() + advanceState()
  │     └→ 每 15 秒自动保存 NVS
  ├── 最后 10 秒急促提示音(专注模式)
  ├── 蜂鸣器 1 秒后自动关闭
  ├── TM1637 冒号闪烁(速度按剩余时间变化)
  ├── 调整模式数字闪烁(500ms 周期)
  └── 休息动画帧推进


三、代码拆分讲解

3.1 引脚与全局变量

#define CLK_PIN     16   // TM1637 时钟线
#define DIO_PIN     17   // TM1637 数据线
#define BUZZER_PIN  2    // 蜂鸣器
#define MODE_PIN    27   // S3
#define START_PIN   14   // S2
#define RESET_PIN   12   // S1

状态枚举 enum State { WORK, SHORT_REST, LONG_REST } 定义三种工作模式。

关键全局变量:

  • remainingSeconds — 当前倒计时剩余秒数
  • workCycleCount — 已完成专注数(0~3),满足 4 次进入长休息
  • adjustMode / adjustSeconds — 调整模式及其分/秒位切换
  • isRunning — 倒计时是否运行中

3.2 NVS 断电记忆

saveNVS() / loadNVS() 使用 Preferences 库存储到 NVS 分区:

存储内容:
  ver=2       (版本号)
  state       (当前状态枚举值)
  remain      (剩余秒数)
  workT       (自定义专注时长)
  shortT      (自定义短休息时长)
  longT       (自定义长休息时长)
  cycle       (当前专注周期数)
  run         (是否运行中)

loadNVS() 中检查 ver >= 2 后才恢复,避免旧版格式数据错误。

3.3 界面绘制

专注模式 showWorkUI()

  • 全屏推入 img_WORK(200×200 居中于 240×240 黑底)
  • 顶部 “WORK”(红色,字号 2)
  • 底部 “Pomodoro X/4”(黄色,字号 1)

休息模式 showRestUI()

  • 清屏黑色
  • 顶部 “S_REST” / “L_REST”(绿色,字号 2)
  • 底部专注计数(黄色,字号 1)
  • 中间区域留给动画

动画播放 stepAnimation()

  • 使用 pushImage(0, 24, 240, 192, &REST_frames[i][24*240]) 只推送 y=24~216 区域
  • 每帧按 REST_delays[] 指定延时切换
  • 14 帧循环播放

调整模式 showAdjustUI()

  • 标题 “ADJ-WORK” / “ADJ-S_REST” / “ADJ-L_REST”
  • 5 号字时分显示,被调单位(分或秒)500ms 闪烁隐藏
  • 操作提示:S2:+ / S3:- / S1:unit / Hold S1:exit / Hold S2+S3:reset

3.4 按键处理逻辑

三个按键各自独立处理函数,每个函数内部区分"调整模式"和"正常模式"两套逻辑:

按键 正常模式操作 调整模式操作
S1(GPIO12) 短按=重置计时;长按1秒=进入调整模式 短按=切换分/秒位;长按1秒=退出调整
S2(GPIO14) 短按=开始/暂停;蜂鸣时按=关闭响铃 短按=加 1 分钟或 1 秒
S3(GPIO27) 短按=切换到下一阶段 短按=减 1 分钟或 1 秒

恢复出厂设置调整模式下同时按住 S2+S3 保持 3 秒,恢复所有默认值并清除 NVS。

按键逻辑使用 bothHeld() 检测 S2+S3 同时按下,避免误触。

3.5 倒计时与双屏同步

  • 每秒 remainingSeconds--,归零时 onTimerEnd() 响铃 + 自动切换状态
  • TM1637 每次更新时同步显示 remainingSeconds 的 MMSS 格式
  • TFT 在状态切换时调用 showWorkUI() / showRestUI() 重绘
  • 冒号闪烁速度随剩余时间变化:
    • 专注模式最后 10 秒:100ms 快速闪
    • 专注模式最后 5 分钟:250ms 中速闪
    • 其余:600ms 慢速闪

3.6 蜂鸣器

  • 倒计时结束时:beepOn() 输出 1kHz PWM,1 秒后自动关闭
  • 专注模式最后 10 秒:每 500ms 输出 2kHz 短促音(15ms)

四、操作过程及数据展示

4.1 操作步骤

  • 硬件连接:正确连接所有模块。

  • 编译与上传:在零知派中选择开发板“ESP32 ”,正确选择端口,编译并上传代码。

4.2 使用说明

初次使用

  1. 上电 → 开机动画(TFT 显示标题,TM1637 88:88 闪烁 2.5 秒)
  2. 默认进入专注模式(25:00),倒计时等待启动
  3. 按 S2 开始倒计时

日常使用

S2(短按)  → 开始/暂停倒计时
S3(短按)  → 切换阶段:专注→短休→(循环4次)→长休→专注
S1(短按)  → 重置当前阶段的计时

自定义时长

S1(长按1秒)→ 进入调整模式
S2(短按)  → 加 1 分钟(或加 1 秒)
S3(短按)  → 减 1 分钟(或减 1 秒)
S1(短按)  → 切换分钟/秒钟(被调单位闪烁)
S1(长按1秒)→ 退出调整

恢复出厂设置

在调整模式下:
按住 S2 + S3 保持 3 秒 → TFT 显示 "Factory Reset" → 自动回到专注模式

断电记忆

  • 运行中或暂停中直接断电,下次开机自动恢复断点
  • 倒计时每 15 秒自动保存一次

4.3 演示视频

零知派ESP32–基于TM1637数码管模块制作番茄钟


五、技术原理

5.1 工作原理

  • TFT 显示(TFT_eSPI 库):通过 SPI 接口驱动 ST7789,240×240 分辨率,RGB565 颜色格式
    • pushImage() 直接推送预转换的 16 位像素数组到 GRAM
    • 动画帧预处理为 const uint16_t PROGMEM 数组,存放在闪存中
  • 数码管(TM1637Display 库):I²C 协议模拟驱动 TM1637 芯片
    • showNumberDecEx() 显示 4 位数字 + 冒号(0x40 位控制)
  • 断电记忆(Preferences 库):调用 ESP32 的 NVS API,写入 NVS 分区
    • 每次状态变化(剩余时间、调整时长、运行状态)都会触发保存
    • 保存间隔 15 秒减少擦写次数
  • 按键输入(GPIO INPUT_PULLUP):三个按键均为低电平触发
    • 软件 200ms 消抖 + 1000ms 长按阈值

5.2 工作模式配置

番茄工作法规则

专注(25分钟)→ 短休息(5分钟)→ 专注 → 短休息 → 专注 → 短休息 → 专注 → 长休息(15 分钟)
→ 专注 → ...(第 4 次专注结束后)→ 长休息(15 分钟)→ 专注 → ...

模式切换逻辑advanceState() 函数):

WORK → workCycleCount++
         ├── 满 4 次 → LONG_REST(清零计数)
         └── 未满 4 次 → SHORT_REST
SHORT_REST → WORK
LONG_REST → WORK

  • 注意力集中系数(MAX_WORK_CYCLE=4):每完成 4 个专注周期插入一次长休息
  • 专注计数在进入长休息时自动归零,在短休息时保持累加

各模式默认时长
长休息 = SHORT_REST + LONG_REST = 15分钟

模式 默认时长 NVS 键名
WORK 25 分钟 workT
SHORT_REST 5 分钟 shortT
LONG_REST 10 分钟 longT

六、常见问题指引

Q1:编译后闪存不够怎么办?

检查分区设置:工具 → Partition Scheme → 选择 No OTA (Large APP)。如果仍然不够,可在 convert.cs 中将 step 改为 3 或 4 减少帧数。

Q2:屏幕方向不对怎么办?

在 bootAnimation() 中修改 tft.setRotation() 参数:

  • 0:USB 口朝下
  • 1:USB 口朝右
  • 2:USB 口朝上
  • 3:USB 口朝左

Q3:如何更换休息模式动画?

  1. 将新的 GIF 文件命名为 REST.gif 放入 PomodoroYueXin 目录
  2. 编译运行 convert.cs 重新生成帧数据
  3. 如帧数变化,需同步修改 REST_anim.h 中的 REST_frame_count 和 REST_delays[]
  4. 如果改为其他文件名,需同步修改 convert.cs 中的路径

Q4:如何更换专注模式背景图?

  1. 准备 240×240 的 PNG,命名为 WORK.png 放入 PomodoroYueXin 目录
  2. 编译运行 convert_png.cs 重新生成 WORK.h

Q5:TM1637 显示不正常?

  • 检查 CLK(GPIO16)和 DIO(GPIO17)接线
  • 供电电压应为 3.3V

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐