自学读本:跟着读、照着做,卡住就问 AI
你好,我是吴老师。这份是给你自己读的——看到让你停下来的地方,就照着做一遍。
前九课,屏幕有了颜色、能画点线圆方、能自己动、能听懂手指、还能显示中文。
可你有没有想过——照片怎么办?
你手机里那些照片,是怎么跑到这块小屏幕上的?它们不是画出来的,也不是写出来的,是拍出来的。一张照片,就是几万甚至几十万个颜色点,整整齐齐排在一起。
今天我们就把照片装进板子:插一张 SD 卡,读一张图,显示到屏幕上。
一、先说句让你安心的话:图片,还是像素点
你可能觉得"照片"很高级、很神秘。但它和我们已经学过的,是同一回事。
回想第 5 课:屏幕上每个点,都要告诉板子它是什么颜色。一张照片,不过是把这件事做到极致——把几十万个点的颜色,全部按位置记下来。
所以今天没有新概念,只补两件事:
- 这些点存在哪——在 SD 卡的一个文件里;
- 怎么被读出来——照片通常被"压缩"过,要先"解压缩"才能显示。
打个比方:照片像一张巨大的马赛克拼图。第 5 课我们手动画几个点;照片是工厂预先拼好、几万个小方块一次性寄给你,你只要按编号贴到屏幕上。
比喻要修正:马赛克每块颜色是你定的;照片每块颜色是相机测出来的,你只负责"贴",不负责"选"。
二、文件、路径、目录:板子怎么找到一张图
SD 卡对板子,像个小仓库。里面能放很多文件,用"路径"指路。
比如卡里 photo 文件夹里有张 cat.jpg,完整路径就是:
/photo/cat.jpg
开头的 / 是"仓库最外面那层",photo 是文件夹,cat.jpg 是文件。
板子要显示它,第一步就是顺着这条路找到它。路写错了(多一个斜杠、大小写不对),板子就睁眼说瞎话:"找不到。"
打个比方:路径像你家地址。"广州市天河区 xx 路 xx 号",错一个字快递员就送不到。给板子的路径也一样,一个字母都不能错。
比喻要修正:快递员会自己找;板子不会"猜",路径不对就直接放弃,连"大概附近"都不试。
三、为什么照片要"解压缩"才能看
这里有个关键点,也是今天最容易卡住的。
一张 240×320 的图,每个点用 2 字节(RGB565,第 3 课学过)记颜色,原始大小是:
240 × 320 × 2 = 153,600 字节 ≈ 150 KB
但你在电脑里看到的 cat.jpg,往往只有 十几 KB。
差了大约 十倍。
为什么?因为 JPG 是压缩格式:把"相邻很像的颜色"合并记录,省掉大量重复。代价是——板子不能直接把 JPG 丢给屏幕,得先"解压缩",把那 150 KB 还原出来,才能一个点一个点地显示。这个过程叫解码,本板用 TJpg_Decoder 来干。
打个比方:原始图像是"每本书逐字抄一遍";JPG 是"第 3 页到第 10 页都和第 3 页一样,就不抄了,只记一句'同上'"。板子读 JPG 时,得先把那些"同上"还原成原文才能读。
比喻要修正:书你可以跳着读;解码必须完整还原,漏一块屏幕就花掉一块。
四、本板的规矩:先告诉它针脚,再开门
读 SD 卡,有个必须做、却容易被忘的动作:先告诉板子 SD 卡用的哪几根针脚。
本板 SD 卡走 SDIO,针脚是固定的:
SD_MMC.setPins(38, 40, 39, 41, 48, 47);
顺序是 CLK, CMD, D0, D1, D2, D3。别套用普通 SPI SD 模块的针脚,那一套在这块板上不对,会读不到卡。
然后才是 SD_MMC.begin() 开门。顺序反了或针脚错了,后面全白搭。
整个流程是这样的(配图):
今天只讲两个名字:
SD_MMC(管 SD 卡开关和读文件)和TJpg_Decoder(管 JPG 解码)。别的先不管。
五、解码要多久?又回到第 7 课了
我要故意把你拉回第 7 课。
第 7 课算过:整屏重画每秒 30 次,数据量顶到 SPI 的带宽。今天解码一张图,其实也是"往屏幕送一大堆点"。
解码一张图要多久? 看图片大小。一张刚好铺满屏幕的 240×320 JPG,解码通常要 几百毫秒。
这意味着:
- 翻一张照片,等几百毫秒——单看一张还行;
- 做"自动相册",一秒翻一张,解码的几百毫秒会让切换明显卡顿。
这就回到第 7 课那句话:卡不卡,看你在预算里干了多少活。
打个比方:解码一张图,像把一整箱书从仓库搬到桌上。搬一次还行;要你一秒钟搬好几次,你就累趴下了——板子也是。
比喻要修正:书搬完就放那儿;照片解码完还要"贴"到屏幕,搬运 + 张贴都算在预算里。
而且——视频,说白了就是连续播放的图片帧。手机里一段视频,本质是每秒 20~30 张图在轮播。所以今天这课,也是给"以后做视频"打地基。
六、动手做:你的第一本电子相册
挑一个做:
作品 A · 主题电子相册
在 SD 卡建 photo 文件夹,丢 3~5 张 JPG,板子开机后每隔几秒自动翻一张。比如"我的宠物""旅行日记"。
作品 B · 分类相册
建两个文件夹 photo/family/ 和 photo/trip/,用 BOOT 键切换"现在看哪一类",每类自动轮播。
难点不在"显示一张",在于怎么让板子知道卡里有哪些文件、按顺序翻。这要用到"列目录"小技巧——和前面按路径找单个文件,是同一套 SD 操作的两面。
七、自检:先猜,再烧
今天最值钱的验证,是亲手量一量"解码要多久"。先猜,再烧进去用串口看真实数字:
| 你做的事 | 你的预测 | 板子实测(串口毫秒数) |
|---|---|---|
| 用一张很小的图(80×80) | (猜:很快?) | (烧进去看) |
| 用一张铺满屏幕的图(240×320) | (猜:一样?) | (烧进去看) |
不写 setPins 直接 begin() | (猜:能读?) | (烧进去看) |
重点:小图和大图的解码时间差很多。亲眼看到这个差,你就真正懂了"为什么相册会卡"。
八、最后留给你
今天只是"让板子看照片"的第一步。几个方向挑一个折腾:
| 方向 | 你可以做什么 |
|---|---|
| 家庭电子相框 | 插上 SD 卡,桌上摆一台永远在翻照片的小相框 |
| 拍立得 | 接摄像头,拍一张立刻显示(接后面的摄像头课) |
| 带说明的相册 | 每张照片下面用第 9 课的中文,写一句说明 |
| 滑动切换 | 用第 8 课的触摸,手指左右滑切换上一张/下一张 |
附:给 AI 的提示词(直接复制)
我要用 ESP32-S3 触摸屏板从 SD 卡显示一张 JPG,板子用 TJpg_Decoder 库。
请写一段 Arduino 代码:
1. 先 SD_MMC.setPins(38, 40, 39, 41, 48, 47) 设好针脚,再 SD_MMC.begin();
2. 设置 TJpg_Decoder 回调,把解码出的图像块 pushImage 到 TFT;
3. 解码并显示 SD 卡根目录的 /cat.jpg;
4. 在串口打印解码用了多少毫秒。