AI脑洞板
完整教案
自学课件
第 11 课 · 共 11/51 课

让板子开口 扬声器怎样把数字变成声音

课时
待定
器材
ESP32-S3 触摸屏板 + USB 线
前置知识
无
配套代码
见项目 demo 目录

你好,我是吴老师。

这份是给你自己读的——不用等我讲,你一段一段往下看,看到让你停下来的地方,就照着做一遍。看不懂的整段复制给 AI,加一句"请一次只解释一个概念,讲完问我一个小问题"。

读完之后,你应该能:说出扬声器发声的完整链条;解释"播放声音 = 按固定节奏送数字";说出 DAC 和采样率是干什么的;亲手把 440Hz 的声音改成 880Hz,并预测听感变化;说清"边播边动"为什么要把长任务切成小块。

用时:60–90 分钟。准备:板子、数据线、已经接入板卡 Skill 的 WorkBuddy。


一、从"看见"到"听见"

前八课,我们让板子做了很多事:灯变色、屏幕画画、动画跑起来。它们全都有一个共同点——都是让你看的。

今天做一件新事:让板子发出声音。

先想一个问题:板子上没有嘴巴,它怎么"说话"?

答案看起来简单:有喇叭。但这只是第一层。第二层问题才是真的:喇叭凭什么发出"滴——"的一声?

再往深一层:板子里没有声音,只有 0 和 1。你让 AI"播放一个声音",那些 0 和 1 是怎么变成你耳朵里听到的声音的?

今天这节课的目标很小:让板子响一声"滴",然后你改一个数值,让音调变高变低。

你会发现,声音一点都不神秘——它只是"被送得很快的数字"。

二、先让它响起来

请使用课程的 esp32s3-touchboard-hardware-dev Skill,
让板子通过扬声器播放一个 440Hz 的"滴"声,持续 0.8 秒,
音量用中等偏低的音量,播完就停。
播放前先检查板卡的音频芯片(ES8311)和功放初始化方式。
帮我新建程序并烧录。

烧录完,先别急着调来调去。把你听到的写下来:

✏️ 可以直接在表格里填写
我听到的现象勾选
一声清晰的"滴"
声音很轻
完全没有声音
有咔哒杂音

三、声音是什么:一面看不见的鼓

声音不是"东西",是振动。

想象一面鼓:你推一下鼓面,它往下凹;弹回来时挤压前面的空气;空气再推下一层空气。这一层推一层的波动传到耳朵,撞上耳膜,你就"听到"了。

喇叭就是一面"电动的鼓":电压快速变化,纸盆就跟着快速振动,把空气推出一层层波。

名字通俗说法决定什么
频率纸盆一秒来回推几次音调(推得快 = 声音尖)
振幅推得多用力响度(推得狠 = 声音大)
波形推的节奏长什么样音色(钢琴 vs 小提琴)

频率单位是 Hz,意思是"每秒多少次"。440Hz = 每秒推 440 次。

你肯定玩过这个实验:拨橡皮筋,绷得越紧,声音越尖——那就是频率变了。

亲手转一转这三个旋钮——边拖边听,看看耳朵听到的和眼睛看到的怎么对上:

⚠️ 比喻有边界:喇叭不是简单"推空气"。它里面有个线圈,靠电流在磁场里受力推动纸盆。这门课不钻这个,你记住链条就行:电压变 → 纸盆动 → 空气推 → 耳朵听。

四、板子里没有声音,只有数字

纸盆需要"快速变化的电压"才动。ESP32-S3 只会算数字,怎么造出会变化的电压?

靠一个小东西:DAC(数模转换器)。它只干一件事——把一个数字变成对应的电压。

数字大 → 电压高;数字小 → 电压低。

于是播放声音变成了一件简单的事:

按固定节奏送数字 → DAC 把数字变成电压 → 电压推纸盆 → 声音出来。

这块板上,DAC 不在 ESP32 里,而在另一颗芯片 ES8311 里。它叫音频"编解码芯片"(codec)。今天只用它一半的本事(DAC,把数字变电压);第 12 课我们会用到它另一半(ADC,把电压变数字)。

五、采样率:每秒送几个数字

"按固定节奏"——多快?这个速度叫采样率。

16000Hz(16kHz)采样率 = 每秒送 16000 个数字。

快与慢,先拿耳朵量一量

先猜一猜,再实验。同一批 440Hz 的数字,用三种速度送出去,听起来会怎样?

✏️ 可以直接在表格里填写
我改了什么我预测实际听到
A 正常送(每秒 16000 个)
B 每个数字送两遍(送得慢了)
C 隔一个送一个(送得快了)

把这段发给 AI:

请做一个对照实验,用同一批 440Hz 的声音数据,三种送法各播一遍:
A 正常送;
B 每个数字连送两遍;
C 每隔一个数字送一个。
每种之间停 1 秒供我对比,循环两遍。其余什么都不改。帮我烧录。

你会听到:A 正常,B 变沉,C 变尖。

💡 第一个重要发现:同一批数字,送得快音调就高,送得慢音调就低。 数字一个都没改,只是送的速度变了。

但请注意一个细节:时长也跟着变了

再听一遍,这回别只听音高,注意每个音持续了多久:

送法音调时长
A 正常送正常正常
B 每个送两遍变低变长(拉成两倍)
C 隔一取一变高变短(缩成一半)

音调和时长,永远一起变。 这不是巧合——B 就是"这盘磁带放慢一倍",C 就是"放快一倍"。老式录音机快没电时,歌声会又沉又慢,就是这个道理。

想深一层:那能不能"音调变低、但时长不变"?

先自己想,再往下看。

如果你手里只有一个办法——改变送数字的速度——那做不到,因为音调和时长被绑死了:慢下来,两个一起变。

那真实世界里的音频软件是怎么做到的?(比如把一首歌升调但速度不变、或者变声器把你的声音变粗但语速不变。)

这需要一个更聪明的算法,它的思路大致是:

  • 把声音切成一小段一小段(比如每段 20 毫秒);
  • 挪动这些小段之间的位置——要让声音变长,就重复一些段;要让声音变短,就丢掉一些段;
  • 但每一小段内部的波形保持原样不动。

这样时长变了,而每段内部的振动快慢没变——音调就保住了。

这个算法今天不用你写,你只要知道一件事: "变调"和"变速"本来是绑在一起的,想要拆开它们,就得动脑筋。

而这正是本课的名字"让板子开口"背后真正的功夫——板子只会送数字, 但怎么送、送什么,全是人想出来的。

采样率到底是什么

聊完"送得快慢",我们再回到采样率。它其实是另一个问题:

采样率 = 每秒为这段声音记录多少个点。 它决定的是——这段录音最高能还原到多高的音。

为什么?因为一个波至少要两个点才能画出来(一个表示"上去",一个表示"下来")。所以:

能还原的最高音 ≈ 采样率 ÷ 2

16000Hz 采样 → 最高能还原 8000Hz 的音
 8000Hz 采样 → 最高只能还原 4000Hz 的音

人的说话声,主要能量在 3000Hz 以下。所以 16kHz 采样够用——电话、语音助手常用它,是为省数据、又够听清,不是因为音调。

⚠️ 这里最容易搞混,一句话分清:

你动的旋钮变的是什么
送数字的快慢音调(快=尖)—— 上面 A/B/C 实验玩的就是它
采样率的高低能还原多高(上限 = 采样率 ÷ 2)、以及音质

一句话记住:"送数字的快慢"是播放这一端的事,"采样率"是记录那一端的事。 两个是分开的旋钮,别混成一个。

自己拖一拖采样率——点越来越稀的时候,还原出来的波还像原来那个音吗?

拖到最左边会发生什么? 波"变形"了——不再是你原来那个音。 这就是采样率不够的后果:录回来的东西变了样。

再感受一遍那句话:拖滑杆的时候,音调本身一次都没变(我们没动播放速度), 变的只是"这段录音最高能还原到多高的音"。采样率 ≠ 音调。

六、一条完整的声音流水线

把学过的东西连起来:

你生成数字(正弦波采样)
    ↓  把数字装进缓冲区
按节奏送出(采样率,比如 16000/秒)
    ↓
ES8311 的 DAC:数字 → 电压
    ↓
功放放大电压
    ↓
扬声器纸盆振动
    ↓
空气一层层推
    ↓
你的耳朵

一条完整的声音流水线:生成数字 → 缓冲区 → 按节奏送 → DAC → 功放 → 扬声器

用中文伪代码写同一件事:

准备"滴"声(440Hz,0.8 秒):
    一共 0.8 × 16000 = 12800 个数字
    第 i 个数字 = 正弦波在 i/16000 秒那一刻的高度
播放:
    把这些数字按 16000 个/秒的节奏送出去

正弦波那行公式看不懂没关系,它只是"算出一个会上下起伏的数列"。真正要记住的是:数字攒好,按节奏送出,声音就有。

七、动手:拖一根滑杆,听音调滑上去

到这一步,你已经听过 440Hz 和 880Hz 两个音了。

但改一次频率就要重烧一次程序,一次只能听两个点——太慢了,而且你会以为音调是从"这个音"跳到"那个音"。

现在我们换个玩法:给板子装一根滑杆,手指按住它左右拖,频率跟着手指走。拖的时候你会听到一个连续变化的声音。

先把这段发给 AI:

请做一块"频率滑杆":屏幕中间画一根横向滑杆,
手指按住它左右拖动,就改变正在播放的正弦波频率。
频率范围 220 到 880 Hz,屏幕上要实时显示当前的频率数字;
滑杆下方画一个波形图,把这个频率的波形画出来。
一边拖着一边要有声音,不能卡顿。
请用中文注释,烧录前核对端口。

这题有一个隐藏难点,先想一想:如果程序是"把整段声音全算好、播完才返回", 那你拖着手指的时候,板子根本没空去看你的手指——声音会卡、滑杆也会卡。 想想第 8 课学的触摸,和这节课的播放,它们怎么才能同时干活?

(提示:想一想下一节要讲的"把长任务切成小块"。)

烧录后做三件事,边做边记:

✏️ 可以直接在表格里填写
我做的我听到的我看到的
从最左边慢慢拖到最右边(音调怎么变?)波形怎么变?
停在中间,记住这个声音
再拖到最右边,和中间比

停一下,看两个地方:

  1. 耳朵:那句话你听出来了吗——音调不是"跳"的,是"滑"的。手指在滑杆上挪一点点,音调就变一点点。这才是音调的真相。
  2. 眼睛:盯着下面的波形。频率越高,波形越密(同样宽度里,波的数量越多)。

💡 这两个是同一件事:耳朵听到的"尖",就是眼睛看到的"密"。 频率就是"一秒振动几次",振动次数多了,画出来自然就密。

顺便验证一个数字

前面的表格里说过:880 是 440 的两倍,听起来高一个八度。

现在你能验证它了——先拖到 440 停住,记住那个音;再拖到 880。

如果你家里有钢琴、电子琴或者音乐 App,按一下中音 Do(C)和高音 Do,对比一下: 是不是"同一个音,只是高了一层"?

这就是八度:频率翻倍 = 高八度。音乐里的音高就是频率,不神秘。

八、动手:把《两只老虎》"翻译"成频率表

单音会了、滑杆玩过了。现在做一件真正像"编曲"的事:把一首歌,变成一张频率表。

先看一个慢镜头。你哼两句《两只老虎》:

两 只 老 虎 ,
两 只 老 虎 ,
跑 得 快 ~ ,

你有没有注意到——有些字唱得长,有些字唱得短?"虎"字短促,而"快~"要拖长。所以一首歌里有两个东西在变:

变的对应什么
音高低频率(Hz)—— 上一节滑杆拖出来的那个
音长短时长(毫秒)—— 这个音唱多久

旋律 = 一个一个的"频率 + 时长",排成一队。

第一步:先把工具箱摆出来

要"翻译"一首歌,得先有对照表。下面这三张表是你的原料,不是答案——照着查就行。

工具箱 ①:音符 → 频率

音符唱名频率
Do1262 Hz
Re2294 Hz
Mi3330 Hz
Fa4349 Hz
Sol5392 Hz
La6440 Hz

工具箱 ②:《两只老虎》前四句的曲谱——每个字唱哪个音、哪个字要拖长

两 只 老 虎   →   Do  Re  Mi  Do     (四个字一样长)
两 只 老 虎   →   Do  Re  Mi  Do     (四个字一样长)
跑 得 快 ~    →   Mi  Fa  Sol        ("快~"要拖长!)
跑 得 快 ~    →   Mi  Fa  Sol        ("快~"要拖长!)

工具箱 ③:时长用"份"来数

什么样的字算几份举例
短字1 份两、只、老、虎、跑、得
拖长的字4 份快~

所以"快~"听起来比别的字长得多——数一数就知道长几倍。

第二步:把三张表拼起来(这步是你的活)

音高照着曲谱抄就行。但"1 份到底等于多少毫秒",得你来定——这就是你的编曲。

先自己填,再发给 AI:

✏️ 可以直接在表格里填写
第几个字唱什么频率 Hz几份时长(毫秒)
1两2621
2只1
3老1
4虎1
5~8(和 1~4 一模一样,自己抄)
9跑1
10得1
11快~4
12~14(和 9~11 一模一样)

第 1 行我替你填好了,照着形式往下补。

然后发给 AI:

请让板子按顺序播放《两只老虎》的前四句,一共 14 个音:
两 只 老 虎,两 只 老 虎,跑 得 快~,跑 得 快~
(音高是 Do Re Mi Do / Do Re Mi Do / Mi Fa Sol / Mi Fa Sol)
一个「短字」算 ___ 毫秒,那个拖长的「快~」算 ___ 倍(参考 4 倍)。
音与音之间不留空,音量中等偏低。帮我烧录。

先别急着问 AI 要"正确的《两只老虎》"——你自己定的那个速度才叫编曲。 填得跟原曲不一样、听起来怪,那正好说明你听出来了差别,下一轮再改。 "我改了什么、听起来怎么变了",比"标准答案"值钱。

想好了再点开:我们填的那一版

**这不是标准答案。**我们把"1 份"定成 250 毫秒,于是:

字频率 Hz几份时长
两 / 只 / 老 / 虎262 / 294 / 330 / 2621250
两 / 只 / 老 / 虎262 / 294 / 330 / 2621250
跑 / 得330 / 3491250
快~39241000
跑 / 得330 / 3491250
快~39241000

速度是你的选择:250 改成 150,整首歌会变快(像快板);改成 500,就慢吞吞的(像哀乐)。 其余都不用动。

⚠️ 一个容易踩的坑:如果你把前两个音都填成 262Hz, 板子会连着播两个一模一样的音,听起来像一个长音,你会以为程序坏了。 遇到这种情况先检查你的表,别急着改代码。

最后一句提醒:抄来的旋律不是你的作品,你选出来的频率和节奏才是。 做完这一节,你就亲手把一首歌翻译成了板子能读懂的数字——第 16 课的音乐盒, 用的就是这同一个套路。

九、作品二:两只老虎(旋律 + 画面)

第八节你做的是"只有声音"。现在把它升级成一个能给人看的完整作品:

循环播放《两只老虎》,屏幕上两只小老虎跟着眨眼睛,按 BOOT 能暂停。

这一节和前面最大的不同是:声音和画面要同时进行。

先自己想一个问题:如果程序"播放一个音,等它放完,再播下一个音"——那播放的时候,屏幕还能眨眼吗?

答案是不能。因为播放的代码一直占着 CPU,画面根本没机会更新。这就是为什么之前的 audioPlaySine() 播完才返回。

所以作品二藏着一个新技术:边播边动。

先看现象,再研究它是怎么做到的。把这段发给 AI:

请使用课程的 esp32s3-touchboard-hardware-dev Skill,
让板子通过扬声器循环播放《两只老虎》的旋律,
同时在屏幕上画出两只卡通老虎(蓝天草地背景),老虎的眼睛定时眨一下。
短按 BOOT 键可以暂停/继续播放。
音高用正弦波实时生成,不要用蜂鸣器、不要读 TF 卡。
播放前先检查板卡的音频芯片(ES8311)和功放初始化方式。帮我新建程序并烧录。

烧录后观察三件事,填在下面:

✏️ 可以直接在表格里填写
我观察的现象
旋律对不对
老虎眨眼和音乐同时发生吗
按 BOOT 会怎样

为什么这次能"边播边动"

回到第五节的流水线:播放 = 按节奏送数字。

之前的写法是"把整段旋律的数字全算好,一次性送完,才返回"。作品二换了思路:

每次只算一小段(160 个立体声帧),送出去,马上返回去干别的。

下一轮 loop 再来算下一小段。只要每一小段都及时接上,声音就是连续的;而两次"送数字"之间,CPU 是空闲的——眨眼动画就挤在这个空隙里画。

看下面两条时间轴——红条是 CPU 忙着送声音,黑缝是它空着。小人儿只有在黑缝里才眨得动眼。

换成"大块"试试:块越大,缝越少,眨眼次数就掉下来了。 这就是"把长任务切成小块"的全部意义——不是让 CPU 变快,是给它留出空隙。

顺便回想上一节的 demo06 滑杆:它拖起来为什么不卡?用的是同一个办法。

用一个比喻:不是"一口气把话说完才做别的事",而是"说一个词,趁换气的间隙瞄一眼屏幕"。

写法特点适合
阻塞式(audioPlaySine)简单,播完才返回单音、门铃这种短音
非阻塞(作品二用的)每次只送一小块就返回旋律 + 动画、游戏音效等要同屏的场景

💡 这是本课第二个重要发现:让声音和画面同时工作,关键不是"同时做两件事",而是"把长任务切成小块,块与块之间留出空隙"。 你以后做游戏(第 29–33 课)时,音效和画面并存靠的就是这个思路。

旋律是怎么记下来的

《两只老虎》的谱子,在程序里存成了一张表:

每个音 = (唱第几个音, 唱多长)

{1,1} = do 唱一个八分音符
{5,4} = sol 唱四个八分音符(也就是二分音符,听起来长一倍)

前面数字是"第几个音":1~6 分别对应 do re mi fa sol la。后面数字是时长,单位是"八分音符"。

所以 4 就代表"这个音顶四个八分音符那么长"。你听《两只老虎》里"跑得快~"那个"快"字拖得长,就是长时值。

改谱子不需要动程序逻辑——只改这张表就行。试试看:

请把旋律换成别的儿歌(比如 ___,你自己挑一首),
每个音的时长按 ___ 毫秒算一个「短字」,
屏幕上的画面保持不变,其余都不改。帮我烧录。

旋律只有 6 个音够不够用?想想你挑的这首歌需要哪几个音,如果超出 do~la,你要改哪里?

画面部分

老虎是用基本图形拼出来的:圆形当脑袋、半圆当耳朵、椭圆当肚皮,眼睛是两个小黑点。

眨眼 = 每过一段时间,把黑点擦掉,换成一条横线,再等一小会儿变回黑点。

想想这和第六课(让画面动起来)有什么关系——是不是同一个套路:擦掉旧的,画上新的。

最后一个挑战:

请让老虎跟着节奏动起来:
每播完一个音符,老虎的身体轻轻跳一下。
旋律和画面其他部分都不改。帮我烧录。

这道题的关键是:画面怎么知道"刚播完一个音符"? 提示——程序里得有个变量记着这件事。

十、故障排查:没声音怎么办

按顺序自查,别乱试:

现象先检查
完全没有声音串口有没有报 ES8311 初始化失败?功放使能了吗?
声音很小音量数值调高(只要不刺耳)
咔哒杂音缓冲区清零了吗?播放完等送完再退出?
播一半断大缓冲区要用 PSRAM,别开在栈上

把现象如实告诉 AI,一次让它教你查一件事。

十一、自检小测

先自己想,再点开对答案。

1. 扬声器为什么会动?按顺序说一遍。

电压变 → 纸盆动 → 空气被推 → 耳朵听到。

喇叭是一面"电动的鼓":电流通过线圈,在磁场里受力,推着纸盆快速振动, 把空气一层一层推出去。

2. "播放声音"在程序里到底是什么操作?

按固定节奏,把一串数字送出去。

数字送给 ES8311 里的 DAC,DAC 把每个数字变成对应的电压, 电压推纸盆——声音就出来了。

一句话:播放 = 按节奏送数字。

3. DAC 是干什么的?在这块板上它住在哪颗芯片里?

DAC = 数模转换器,只做一件事:把一个数字变成对应的电压。 数字大 → 电压高;数字小 → 电压低。

它不在 ESP32 里面,而是住在音频芯片 ES8311 里(ES8311 叫"编解码芯片")。

4. "送数字的快慢"和"采样率",这两个旋钮各决定什么?

这是本课最容易混的地方,一句话分清:

旋钮决定属于哪一端
送数字的快慢音调(快=尖,慢=沉)。时长会跟着一起变播放这一端("变速")
采样率能还原多高的音(上限 = 采样率 ÷ 2)、音质记录这一端

动画里 A/B/C 三种送法玩的是第一个:数字没改,只是送得快慢变了,音调就变了。 而"能不能只变调不变速"——用这个办法做不到,音调和时长是绑在一起的。

5. 频率 440 和 880,你听到的差别是什么?

880 听起来比 440 高一个八度(就是 do 到高音 do 的关系)。

因为 880 正好是 440 的两倍——频率翻倍 = 高八度,音乐里的音高就是频率。

拖滑杆的时候你应该听出来了:音调是**"滑"**上去的,不是一格一格跳的。

6. 你编的旋律里,每个音用了几个数字?怎么验证播对了?

每个音的采样个数 = 时长(秒)× 采样率。

比如 0.4 秒的音:0.4 × 16000 = 6400 个数字。

怎么验证:把屏上显示的音名(do/re/mi…)和耳朵听到的对照—— 对上就是对了。更严格的话,用第 11 课滑杆拖到那个频率,比一比音高是不是一样。

十二、还能玩什么

方向想法继续想
摩斯电码练习器短音 0.1s、长音 0.3s长短边界谁来定?
倒计时蜂鸣最后 5 秒每秒"滴",最后拉长声音和屏幕怎么分工?
门铃按 BOOT 响"叮咚"两声间隔多久才像门铃?
小乐器用第 8 课触摸当琴键触摸坐标怎么变成频率?

想做"板子听懂我说话"?那要把声音收进来——第 12 课,麦克风在等你。

第 11 课 · 第一次发声

第 11 课 · 第一次发声

让板子通过扬声器播放一声 440Hz 的「滴」,持续 0.8 秒。

11扬声器发声正弦波
第 11 课 · 采样率实验

第 11 课 · 采样率实验

同一段 440Hz 数据三种送法:正常、每个送两遍、隔一取一,听音调怎么变(还会发现时长跟着变)。

11采样率实验音调
第 11 课 · 两只老虎

第 11 课 · 两只老虎

把《两只老虎》翻译成一张「频率 + 时长」表,板子照着唱出来,屏幕同步显示唱到哪个字。

11扬声器旋律两只老虎乐谱
第 11 课 · 门铃

第 11 课 · 门铃

按一下 BOOT,板子响一声「叮咚」,屏幕记下按了几次。

11门铃BOOT按键
第 11 课 · 两只老虎(作品二)

第 11 课 · 两只老虎(作品二)

把旋律、画面、按钮连起来:循环播放《两只老虎》,屏幕上两只老虎定时眨眼,BOOT 键暂停/继续。

11两只老虎旋律动画作品
第 11 课 · 频率滑杆

第 11 课 · 频率滑杆

手指拖屏幕上的滑杆,音调跟着连续滑上去,下方波形同步变密。

11扬声器滑杆触摸波形