开始之前:小明第三次来
你好,我是吴老师。
小明又来了。 前两次他带来的是"老忘带书"和"背单词老忘"。
这次他的麻烦,听起来跟前两个不太一样:
请你扮演一个四年级的小学生,名字叫小明。
你有一个麻烦:一坐下来写作业就想玩,一玩就停不下来,
作业老是拖到很晚。妈妈盯着的时候你能坐住,她一走你又开始玩了。
(别的你也不知道 —— 你就是个普通小学生,没想过怎么解决。)
规则:
1. 你说话要像一个真的四年级学生:句子短,想到什么说什么
2. 一次只说一点,别一口气把情况全说完了 —— 等对方问你
3. 对方问你什么,你就老实回答什么
4. 你不知道"该做什么工具",你只知道自己有这个麻烦
现在开始:先打个招呼,然后说说你的麻烦。
说完就停下来,等对方提问。
把这段发给电脑上的 AI。从现在起,它就是小明。
一、⚠️ 这个麻烦,比前两个难
前两个麻烦,问几轮就能问清楚。这个不一样。
💡 因为小明说的"我一玩就停不下来"不是原因,是结果。
你要找的是:他为什么停不下来?
而且有意思的是 —— 小明自己多半知道原因,只是不会主动说。
二、像侦探一样问他
这几问最值钱:
| 该问 | 想挖出什么 |
|---|---|
| "你一般能坐住多久?" | 是十秒就烦,还是二十分钟才烦?答案完全不一样 |
| "走神的时候,你一般在想什么?" | 是想玩?还是这题不会做?这是两件事 |
| ⭐ "妈妈在的时候,有什么不一样?" | 他真的需要"被盯着",还是需要别的? |
| "你写完作业之后,会干什么?" | 如果他"写完也没得玩",那拖着就是划算的 |
| ❌ 别问 | 为什么 |
|---|---|
| "你是不是要个定时器?" | 你把答案塞给他了 —— 他会说"对对对",做出来才发现没用 |
| "你要什么功能?" | 他要是知道,就不用找你了 |
⭐ 第三问最关键。
追下去往往会发现:小明需要的不是"有人盯他",是**"有个东西告诉他'你正在做对的事'"**。
妈妈在的时候他坐得住 —— 因为有人在看着他、认可他。 她一走,这个"看着"就没了。
三、你到底问出了什么
| 要回答 | 从小明的话里 |
|---|---|
| 他真正的麻烦 | 不是"没有闹钟",是看不到自己在进步,所以坐不住 |
| 什么时候用 | 每次开始写作业的那一刻 |
| 怎么算做成了 | 能连续坐住 20 分钟,而且自己知道自己坐住了 |
⭐ 看出来了吗?
如果直接做个"倒计时 25 分钟",他还是会中途摸鱼 —— 因为时间在走,他看不见。
💡 这一条会直接落到技术点上:得让进度看得见。 记住它,第五节要用。
本课一句话:计时器不是"数秒数",而是"用现在时刻减去开始时刻"。 板子没有一个"感觉到时间"的器官,它只是拿一个会走的数,和另一个会走的数做减法。
四、先让板子当"番茄钟"
先别听我讲,让板子演示一遍。
请使用课程的 esp32s3-touchboard-hardware-dev Skill,
烧录本课配套程序 assets/codes/demo01_tomato_clock:
板子屏幕显示一个番茄钟,按一下"开始",进入 25 分钟专注倒计时;
到点板子"叮"一声提醒你休息;再按一次进入 5 分钟休息。
屏幕会显示还剩多少分钟、今天专注了多久。
烧录前把中文字库复制好(见 README)。烧录后告诉我:
按"开始"以后,屏幕上的数字是怎么变化的?
几秒后,屏幕上出现一个番茄钟:一个大大的圈,里面写着"25:00"(还剩 25 分钟)。下方有个"开始"按钮。你点一下,数字开始倒着走:24:59、24:58……走到 00:00,板子"叮"一声,然后屏幕变成"该休息了 ✨ 5:00"。
五、拆开看:计时器到底在"数"什么?
现在关键的来了。很多人以为计时器是"一秒一秒地数",其实不是。
板子是这么算的(伪代码,不用背):
还剩多少时间 = 目标时长 - (现在时刻 - 开始时刻)
举个例子:你按"开始"的那一瞬间,板子记下一个数 开始时刻 = 10000(这个数代表"从开机到现在过了多少毫秒")。
过了一秒,现在时刻变成了 11000。那么:
还剩 = 25分钟 - (11000 - 10000)
= 25分钟 - 1秒
= 24分59秒
看到没?板子从来没有"数秒",它一直做的是"减法":用 当前时刻 减去 开始时刻,得到"过去了多久",再用 目标时长 减去它,得到"还剩多少"。
⚠️ 给比喻划边界:说计时器像"沙漏",但沙漏真的在漏沙子;板子的"沙漏"是个假沙漏——它会算"过去了多少",但沙子是"现在时刻 - 开始时刻"这个减法算出来的,不是真的在漏。正因为它不是真漏,所以它不会错、不会停、也不会莫名变快——除非主控卡住了。
六、⭐ "现在几点了"这个数,从哪来?
上面那个"当前时刻",是 millis() 这个函数给的——它从板子开机那一刻开始,每秒加一千,是个一直往前走的大型计数器。这个靠主控自己数,不依赖任何外部时钟。
但是!它有一个致命弱点:它只记"开机到现在过去了多久",它不知道"现在到底是上午 9 点还是晚上 9 点"。也就是说,它的"现在"是从 0 开始的相对时间,不是"日历上几点几分"。
那要显示"现在几点"怎么办?两种办法:
| 办法 | 怎么拿"现在几点" | 优点 | 缺点 |
|---|---|---|---|
主控自己数(millis) | 从开机开始数,能算"过去了多久" | 简单、不需要网 | 不知道"几月几号几点",断电清零 |
| 联网对时(NTP) | 问一个网络时钟服务器"现在几点?" | 知道真实日期时间 | 需要联网,断电要重问 |
本板没有独立的电池时钟芯片(RTC)。所以它没有"永远准确的时间"——要么靠主控数(断电就清零),要么联网问一次(断电再连网重新问)。这是本板的一个真实边界,也是真实设备几乎都用来联网对时的原因。
七、到点提醒:"叮"一声是怎么发生的?
计时器到 00:00,板子怎么知道该"叮"了?
其实就是一个条件判断:
每一帧(比如每 20 毫秒):
现在时刻 = millis()
还剩 = 目标时长 - (现在时刻 - 开始时刻)
如果 还剩 <= 0: ← 到点了!
播放"叮"的一声
切换到"该休息了"画面
"到点了"不是板子"感觉"到的,是它一遍遍判断"还剩是不是 ≤ 0"判断出来的。 就像你盯着时钟看它走到 12 点,板子盯着"还剩"这个数,一看它归零就触发提醒。
提醒的方式也很讲究。板子有三个"输出"可以用来提醒你:声音(第 11 课,喇叭)、灯(第 1 课,RGB)、屏幕(画面)。你可以选一种、也可以三种一起来——能让你"看见/听见"就行。
八、从"计时器"到"番茄钟":再加两个规则
光会倒计时还不够。番茄钟真正聪明的地方,是两个规则:
- 专注段 / 休息段交替:25 分钟专注 → 5 分钟休息 → 25 分钟专注 → …… 循环。
- 记录:今天专注了几个番茄。每次完成一个专注段,计数 +1。
这个"记录"就是状态——和背单词课的"掌握度"、电子宠物的"饥饿度"一样,是一个会被时间或操作改变的数。
规则(一段番茄):
专注 25 分钟:
完成 → "叮" → 记录 +1 个番茄 → 进入休息 5 分钟
休息到点 → "叮" → 回到专注 25 分钟
你看,番茄钟就是个状态机:专注 / 休息 / 记录,三个状态换来换去。你在第 30 课(贪吃蛇)已经见过状态机了。
⭐ 别忘了你采访出来的那句话:他真正缺的是"看得见的进步"。
所以光有数字是不够的("还剩 12 分钟"他看不出来走了多少)—— 演示里那个一圈一圈填满的大圆,才是真正解决他问题的东西。
技术要求是"能算出还剩多少",产品需求是"让他看得见"。两件事。
九、⭐ 交付给小明
装好之后,回头告诉他你做了什么:
我做好了一个工具。它长这样:
____(把屏幕上的样子说给他听)
每次你开始写作业就点上,那个圈会慢慢填满。
你觉得能帮上你吗?
认真听他怎么说:
小明:嗯……可是圈填满之前,我还是会偷偷玩一下。 小明:还有,我怎么知道我今天做了几个?
⭐ 第一句说明:一个工具解决不了所有问题。 它能让他"更愿意坐住",但按不按下开始键,还是他自己的事。 这不是失败 —— 好的工具是帮人变好一点,不是替人活着。
第二句正好指向第八节那个"记录"(记忆番茄数)—— 但注意: 它只存在内存里,一断电就没了。想让它记住,得存 TF 卡(第 14 课)。
十、分析:这个番茄钟用了哪些技术?
同样不让 AI 深挖代码,你要能说清"零件表":
| 技术 / 概念 | 在这里干什么 | 你之前在哪学过 |
|---|---|---|
millis() 计时 | "现在时刻 - 开始时刻",核心计时 | 第 2/6 课 |
| 倒计时 | "目标时长 - (现在 - 开始)" | 本课新增 |
| 条件判断(到点) | 还剩 <= 0 就触发提醒 | 第 2 课(if) |
| NTP 对时 | 联网问"现在几点",显示真实时间 | 第 19 课 |
| 状态机 | 专注 / 休息 / 记录 三种状态切换 | 第 30 课(贪吃蛇) |
| 声音 / 灯 | 到点"叮"提醒(输出) | 第 11 课 / 第 1 课 |
| 背景音乐可选 | 休息时可放轻音乐 | 第 16 课 |
⚠️ 重要边界:
millis()计时不受断电影响吗? 会受影响!millis()从开机开始数,断电就清零重来。所以"今天专注了几个番茄"如果只存在内存里,断电就没了——这和背单词课的问题一模一样。想让"今天专注了几个"断电不忘,也要存进 TF 卡(第 14 课)。
⚠️ 另一个边界:要"现在几点",就不能只靠
millis()。millis()只知道"开机到现在多久",不知道"日期几点"。要显示日历时间,得联网 NTP 对时——这正是第 19 课讲的"板子出门问云端"。
一句话总结:番茄钟 = 用 millis() 做减法计时 + 用条件判断"到点" + 用状态机管理专注/休息/记录 + 用声音/灯/屏幕提醒。"计时"本质是"现在 - 开始"的减法,"到点"本质是"还剩 ≤ 0"的判断。
十一、改一个条件,看它怎么变
| 我想改 | 该动哪部分 | 我预测会发生什么 |
|---|---|---|
| 专注改成 50 分钟 | 专注时长那个数 | 倒计时变长,提醒变晚 |
| 休息改成 10 分钟 | 休息时长那个数 | 休息变长 |
| 到点用"闪灯"提醒 | 提醒方式 | 不响了,改闪 RGB 灯 |
| 加上"记录今天做了几个番茄" | 状态记录 | 屏幕显示计数 |
| 改成"到点放首歌" | 提醒 + 声音 | 到点放音乐 |
先预测,再验证。 你会发现:改的都是"数据"(时长、提醒方式、要不要记录)和"规则"(几分钟一换、怎么提醒),而"计时"这件事本身(减法和判断到点)一点没变。
十二、如果它没按你想的来
| 现象 | 先查什么 |
|---|---|
| 数字不走 | millis() 用对了吗?是不是没用"当前时刻-开始时刻"? |
| 到点不"叮" | 声音链路对吗?音量够吗?(第 11 课) |
| 到点不提醒 | 还剩<=0 的判断写对了吗?有没有在每帧都检查? |
| "现在几点"不准 | 靠 millis() 只能知相对时间;要日历时间得联网 NTP 对时 |
| 断电后"今天专注了几个"没了 | 存了内存——要持久得存 TF 卡 |
记住:millis() 是"过去了多久",不是"现在几点";它们不是一回事。
十三、下课前,把"计时和提醒"讲给我听
先别看 AI 的回答,自己说一遍:
- ⭐ 小明说的"我一玩就停不下来",是原因还是结果?真正的原因是什么?
- 计时器真的是"一秒一秒数"吗?板子到底在做什么减法?
millis()给出的是"现在几点"还是"开机到现在多久"?它有什么局限?- "到点了"是板子"感觉"到的,还是"判断"出来的?怎么判断?
- 本板有没有 RTC 时钟芯片?要显示"现在几点"该怎么办?
- 番茄钟的"专注/休息/记录"是什么?算不算状态机?
- "今天专注了几"为什么断电就没了?想记住该怎么存?
今天请留下三样东西:你调过的专注/休息时长、你设计的提醒方式(声音/灯/屏幕选一个)、以及一句"毫秒计时和日历时间"的区别。
十四、最后留给你:把"时间"变成你的伙伴
这一课你可能觉得"就一个计时器,有啥特别"。但想深一点:
理解"时间"这个资源,是工程师和普通人的分水岭。
| 你学到的 | 本质 | 能用来做什么 |
|---|---|---|
millis() 计时 | 用减法测"过去了多久" | 动画、游戏、延迟、节拍 |
| 到点判断 | 还剩<=0 触发 | 提醒、闹钟、超时处理 |
| 状态机 | 几个状态换来换去 | 任何有开始/过程/结束的程序 |
| NTP 对时 | 联网问"现在几点" | 显示瞬间时间、定时任务 |
这些不只是"做个番茄钟",它们是所有"和时间打交道"的程序共同的底子——你后面做闹钟、倒计时、定时提醒、甚至智能家居,都用得上。
第七章「学习助手」到这里就完了。 回头看:34 课用数据组织一天、35 课用提示词让 AI 说话、36 课用数据+规则背单词、37 课用计时+状态管时间——我们一共让板子做了四件"帮你"的事。下一章(休闲娱乐)我们要反过来,让板子陪你看、听、玩。
教师备课备注(不作为课堂口播)
课程定位
- ⭐ 2026-09-24 改版:本课加了「产品经理」范式(连同 34 / 36 / 46 / 47)。
结构:小明来求助 → 采访 → 挖真需求 → 做 → 交付 → 听反馈。
- 本课的真需求反差:他说的"我一玩就停不下来"是结果不是原因; 追到根上常常是"看不到自己在进步"(妈妈在时坐得住,因为有人在认可他)。
- ⚠️ 这一条必须回接技术点:正因为他"看不见",所以光有倒计时数字不够, 要有演示里那个一圈圈填满的大圆。采访与技术这条线断了就白改。
- 交付时小明说"圈填满之前我还是会偷偷玩一下" —— 这是有意设计的: 要让老师点破"好工具是帮人变好一点,不是替人活着", 避免学生把"工具没根治问题"当成失败。
- 第七章「学习助手」收尾课,也是时间类软件的核心课。技术落点:
millis()做减法计时、条件判断"到点"、状态机管理专注/休息、NTP 对时、用声音/灯/屏幕提醒。 - 核心认知:计时不是"数秒数",而是"当前时刻 - 开始时刻"。
millis()给的是"开机到现在多久"(相对时间),不是"现在几点"(日历时间)——这是本课最重要的区分。 - 与第 14 课、第 36 课呼应:内存 vs TF 卡("今天专注了几"断电就没了)。与第 19 课呼应:要日历时间必须联网 NTP 对时。
- 时间边界(真难点):本板无独立 RTC 电池时钟芯片,时间只能主控计时(断电清零)或联网对时(断电重对)。这决定"现在几点"不可靠、要联网。
本课新增的核心知识点
- 计时本质:
还剩 = 目标 - (现在 - 开始),减法不是数数。 millis()的局限:相对时间(开机到现在),不是日历时间;断电清零。- 到点条件判断:
还剩 <= 0就触发提醒——不是"感觉"到的,是"判断"出来的。 - 状态机:专注 / 休息 / 记录 三种状态切换(复用第 30 课贪吃蛇的状态机思想)。
- NTP 对时:要显示日历时间须联网问"现在几点"(第 19 课)。
- 提醒方式:声音(喇叭)/ 灯(RGB)/ 屏幕三种输出,可组合。
必须避免的错误
- 不要说"板子感觉到时间到了"——它是条件判断出来的。
- 不要把
millis()和"现在几点"混为一谈。millis()是相对时长,不是日历时间;要日历时间须 NTP。 - 不要说"本板时间很准"。无 RTC,断电需重新对时,时间可能不准——这是真实边界,要让学生知道。
- 不要引入外部时钟模块(DS3231 等)——本板没有,且讲"无 RTC 的对时方案"是重点。
执行约束
- FQBN:
esp32:esp32:esp32s3:FlashSize=16M,PartitionScheme=app3M_fat9M_16MB,CDCOnBoot=cdc,PSRAM=opi - 依赖:
TFT_eSPI、FT6336;若要响铃用 ES8311/I2S(第 11 课);ESP32Time/time.h;font/ChineseFont16.h。 - 屏幕排线、触摸引脚同 34 课;功放 GPIO1 低有效;音量注意保护听力,先从小声开始。
- dmeo01(计时版)不需要联网;demo02(NTP 对时版)需要 WiFi + 能上外网。
- 中文显示:
drawUtf8()+font/ChineseFont16.h;本课不需要云 API 密钥。
课堂执行要点
- 顺序建议:demo01(现象:番茄钟倒计时 + 到点叮)→ 计时本质拆解 →
millis()vs 日历时间 → 到点判断 → 状态机 → 改一个条件 → 下课前复述。若想讲"现在几点"再上 demo02(NTP 对时)。 - 灵魂追问 ①:"计时器真的在数秒吗?它在做哪个减法?"——引出"现在还
目标 - (现在-开始)"。 - 灵魂追问 ②:"板子知道现在几点吗?"——引出
millis()相对时间 vs NTP 日历时间 + 无 RTC 的边界。 - 观察表先预测后实测。
- 到点提醒先小声演示,注意保护听力。
待办与遗留
demo01_tomato_clock(计时版)、demo02(NTP 对时版,可选)源码已写(含中文字库),尚未实板验证。吴老师实板验收重点:① 倒计时是否准确;② 到点"叮"(声音链路 + 音量);③ 状态机(专注/休息切换)是否正确;④ 声音提醒是否保护听力(从小声)。- 若设计"今天专注了几存 TF 卡",需接第 14 课 TF 卡,作为拓展(本课主 demo 先用内存版,点破边界)。
- NTP 对时(demo02)待实板联网验证;若教室无网,用主控
millis相对计时也可完成主线。