自学读本:跟着读、照着做,卡住就问 AI
你好,我是吴老师。
这份是给你自己读的——不用等我讲,你一段一段往下看,看到让你停下来的地方,就照着做一遍。看不懂的整段复制给 AI,加一句"请一次只解释一个概念,讲完问我一个小问题"。
读完之后,你应该能:说出 MP3 为什么比 WAV 小、解码在干什么;背出"一首歌从 SD 卡到扬声器"的 4 个环节;解释
audio.connecttoFS和audio.loop();让板子自动放歌、手指点歌。用时:60–90 分钟。准备:板子、SD 卡(里面拷了几首 .mp3)、数据线、Skill 已接入的 WorkBuddy。
一、录音机能存,能放一整首歌吗?
第 15 课的留言机存的是"我们自己录的声音"。那 SD 卡里别人给的一首歌(MP3),板子能放吗?
能。而且它不板子录的,是别人做好的文件——板子要把它读出来、变成声音、送进扬声器。
先看现象:SD 里放一首 MP3,板子上电自己就唱。
二、开机就唱歌
请使用课程的 esp32s3-touchboard-hardware-dev Skill,
把任意 .mp3 拷进 SD 卡,插到板子;烧录 assets/codes/demo01_play_song。
上电后告诉我板子在干什么。
板子自动放歌:屏幕显示歌名、"播放中"、进度条;RGB 灯随音乐呼吸。
| 现象 | 勾选 |
|---|---|
| 上电自动放第一首 | |
| 显示歌名和进度条 | |
| 按 BOOT 暂停,再按继续 | |
| RGB 播放中呼吸,暂停静置 | |
| 放完自动下一首 |
这一路声音经过哪 4 个地方?
| 环节 | 谁在干 | 学过 |
|---|---|---|
| 读文件 | SD_MMC | 14 课 |
| 解 码 | MP3 解码库 | 本课重点 |
| 送声音 | I2S | 13 课 |
| 出 声 | 扬声器(ES8311) | 11 课 |
留言机存的是"原始声音"(WAV,大而简单);MP3 是压缩过的——丢掉了耳朵听不出的部分,同样内容可能只有 WAV 的 1/10。代价:播放前要解码。
三、MP3 为什么要解码?——压缩与还原
一箱苹果要寄外地,直接寄箱子又大又贵;聪明做法是榨成汁寄一小瓶,到了兑水还原。
- SD 里是"浓缩汁"(MP3,小)
- 播放时的解码 = "兑水还原"(还原成声音点 PCM)
- 还原后走 I2S 送到扬声器
⚠️ 比喻有边界:压缩能变小、解码能还原;但 MP3 丢掉的部分不可逆,所以叫"有损压缩",听感差别不大但不等于 100% 原样。
一句:MP3 小,因为先被榨过汁;能放,因为板子会兑水还原(解码)。
四、两个代码名
Audio 是"音乐管家",把解码、喂 I2S 都包好了:
audio.connecttoFS(SD_MMC, "歌的路径"):把 SD 仓库里某个文件接进音乐管家,它自己开始解码。audio.loop():"继续干活"。歌很长内存很小,不能一次解完,只能每圈解一小段送一小段——边解码边播放。
为什么不能整首读完再放?一首歌几十 MB,内存装不下;只能像水龙头一样一边进一边出。
audio.loop()一停,歌就卡——传送带电机不能停。
五、让歌单能"点"(demo02)
请改烧录 assets/codes/demo02_jukebox(SD 里多放几首 MP3)。
屏幕列出歌单,用手指点任意一首,观察发生什么。
屏幕列出歌单:手指点歌名就放那首;底部:音量-、上一首、播放/暂停、下一首、音量+。
| 现象 | 勾选 |
|---|---|
| 点哪首放哪首 | |
| 上一首/下一首能来回切 | |
| 音量能大能小 | |
| 切歌时画面没卡、声音没断 |
为什么解码放歌和响应触摸两边都不耽误?audio.loop() 每圈只干一小会儿,剩下时间 CPU 还在跑触摸和画屏——分时共享。长任务要切片,别堵死别人。
六、改一个条件:让屏幕和声音抢时间
思想实验:如果每圈画屏花很久(比如整屏重画 50 遍才回来),声音会怎样?
| 我改了什么 | 我预测 | 实际/推论 |
|---|---|---|
| 画屏每圈占用很长时间 | 自己填(如"歌一顿一顿") | audio.loop() 被挤得没机会跑 |
解码和界面是"抢时间的室友":解码太猛界面就慢,界面太猛歌就卡。给解码留足时间片,界面只捡空隙更新——以后写任何"一边干活一边响应"的程序都会遇到。
七、放一首歌的完整链路
放一首歌(从 SD 卡到扬声器):
SD 卡里放着 MP3(压缩过的声音)
SD_MMC 把文件读出来
解码库把 MP3 还原成声音点(PCM)
audio.loop() 在主循环不停转,一小段一小段解码并送 I2S
I2S 送 ES8311 声卡 → 扬声器出声
剩余时间:画进度条、响应触摸、让 RGB 呼吸
暂停: audio.pauseResume();切歌: connecttoFS 换文件
一句记牢:读文件 → 解码 → 小段小段喂 I2S → 出声;解码和界面抢时间,谁也不能堵死谁。
八、故障排查:没声音怎么办
| 现象 | 观察还是推测? | 下一步 |
|---|---|---|
| 屏幕正常但没声音 | 观察 | 看顶部提示:SD 没找到 / 声卡没起来? |
| 一直"待机"不自动放 | 观察 | SD 里真有 .mp3 吗? |
| 放几秒就停/卡顿 | 观察 | 文件码率太高?换 44.1kHz 常见歌 |
| 触摸没反应 | 观察 | 坐标旋转/触摸库初始化顺序 |
| 有杂音 | 观察 | 换 USB 供电,音量别拉满 |
"没声音"是观察,"卡里没歌"是推测。先看屏幕提示再查文件。
九、过关检查
不看 AI,自己说:
- MP3 为什么比 WAV 小?解码在干什么?
- 一首歌从 SD 到扬声器经过哪 4 步?
audio.loop()为什么必须在主循环里一直转?- 为什么不能整首读完再放?
- "解码和画屏抢时间"怎么安排?
- 想加"随机播放"要动哪部分?
十、还能玩什么
| 方向 | 想法 | 继续想 |
|---|---|---|
| 带灯效的音乐盒 | RGB 随音量呼吸 | 灯怎么听懂音乐?要读音量吗 |
| 语音点歌台 | 说话"放第 3 首"就放 | 接麦克风 + 语音识别 |
| 故事盒 | 改放 WAV 录音/故事 | WAV 不用解码? |
| 我的播放列表 | 加翻页、随机 | 超过 64 首怎么滚动 |
预告:第 3 章收尾。第 4 章(17 课起)板子要连 WiFi、出门上网了。