文章目录
- [从数字世界到物理引擎:用 PWM 撕开 0 和 1 的结界](#从数字世界到物理引擎:用 PWM 撕开 0 和 1 的结界)
-
- [第一章:PWM 的两大灵魂旋钮](#第一章:PWM 的两大灵魂旋钮)
-
- [旋钮 1:周期与频率(决定"音调高低"或"电机转速")](#旋钮 1:周期与频率(决定“音调高低”或“电机转速”))
- [旋钮 2:占空比(决定"音量大小"或"灯光明暗")](#旋钮 2:占空比(决定“音量大小”或“灯光明暗”))
- 第二章:芯片内部的"定时炸弹"工厂
-
- [1. 总司令部:`PWMCR` (控制寄存器)](#1. 总司令部:
PWMCR(控制寄存器)) - [2. 频率定制机:`PWMPR` (周期寄存器 Period)](#2. 频率定制机:
PWMPR(周期寄存器 Period)) - [3. 能量分配器:`PWMSAR` (采样寄存器 Sample)](#3. 能量分配器:
PWMSAR(采样寄存器 Sample))
- [1. 总司令部:`PWMCR` (控制寄存器)](#1. 总司令部:
- 第三章:一行代码见证奇迹
- 结语:控制真实的物理世界
从数字世界到物理引擎:用 PWM 撕开 0 和 1 的结界
在嵌入式开发的新手村里,我们学到的第一个神技叫 GPIO 操作:往数据寄存器里写 1,引脚输出 3.3V(亮);写 0,引脚输出 0V(灭)。
数字世界极其冰冷且绝对,非黑即白。但现实物理世界是极其丰富的:灯光有明暗渐变,电机有转速快慢,蜂鸣器有哆来咪发唆的音调高低。
如果芯片的引脚只能输出 3.3V 和 0V,我们该如何输出一个"1.5V"的电压?或者让蜂鸣器发出不同频率的声音?
今天,我们就来彻底扒开这层名为 PWM(Pulse Width Modulation,脉冲宽度调制) 的底层黑魔法。你会发现,它本质上是对人类感官和物理学的一次"高级欺骗"。
第一章:PWM 的两大灵魂旋钮
不要去背什么干巴巴的定义,我们直接把物理世界和代码绑定。想象你正在跑步,PWM 就是控制你跑步姿势的两个核心维度:
旋钮 1:周期与频率(决定"音调高低"或"电机转速")
- 物理现实 :周期(Period, T T T)是指波形完整跳动一次所需要的时间。频率(Frequency, f f f)是指一秒钟内能跳动多少次。它们是同一个事物的两面,公式是永恒的: f = 1 T f = \frac{1}{T} f=T1。
- 跑步比喻 :频率就是你的**"步频"**。
- 低频(比如 500Hz):一秒钟迈 2 步,步伐从容。"咚------咚------咚------",传导到蜂鸣器上,就是低沉的嘟嘟声。
- 高频(比如 2000Hz):一秒钟狂倒腾 8 步,双腿像马达。"滴滴滴滴!",传导到蜂鸣器上,就是极其尖锐的警报声。
- 结论:在代码里改变"周期寄存器"的值,你就能演奏出整个八度音阶!
旋钮 2:占空比(决定"音量大小"或"灯光明暗")
- 物理现实 :在一个完整的周期内,高电平(通电)持续的时间比例。注意,电压的最高点永远是 3.3V,我们改不了高度,只能改变高电平的"宽度"。
- 跑步比喻 :占空比就是你**"单脚触地的时间比例"**。
- 完美的 50% 占空比 :一半时间发力踩地(通电),一半时间腾空飞跃(断电)。这是最舒展的姿态。对于无源蜂鸣器里的金属膜来说,它有完全相等的时间被吸下和弹回,振幅最大,声音最响亮。
- 极端的 95% 占空比 :你 95% 的时间脚底板都死死贴在地上摩擦,只有 5% 的时间稍微抬一下脚。金属膜被死死吸在底座上,像被"掐住了脖子"在抖动,振幅极小,声音反而发闷、微弱。
- 结论:在代码里改变"采样寄存器"的值,你就能控制输出能量的总量,实现灯光的呼吸渐变!
第二章:芯片内部的"定时炸弹"工厂
在 NXP i.MX6ULL 这样的工业级 ARM 芯片中,PWM 是一个独立的硬件部门。一旦配置好,它不需要 CPU 去干预,自己就能在后台疯狂输出极其精准的波形。
要让这台机器运转,你需要掌控它的三个核心寄存器:
1. 总司令部:PWMCR (控制寄存器)
这里是 PWM 的电闸和变速箱。你需要在这里干两件事:
- 开启使能 :往最后一位写
1,启动波形输出。 - 设置预分频(Prescaler) :芯片的主频太快了(比如 66MHz),如果你直接用这个速度,波形一瞬间就跑完了。预分频器就像一个"减速齿轮",比如你写个
64,它就把芯片的心跳放慢 64 倍,再喂给 PWM 模块,方便我们计算出人类能听到的频率。
2. 频率定制机:PWMPR (周期寄存器 Period)
这是一个计数器。假设经过减速后,PWM 每秒钟能数 100 万个数。
- 如果你往
PWMPR里填入1000,PWM 数到 1000 就会重置一个周期。那它的频率就是 1000000 / 1000 = 1000 Hz 1000000 / 1000 = 1000\text{Hz} 1000000/1000=1000Hz。 - 改动这个数字,就是在改动音调。
3. 能量分配器:PWMSAR (采样寄存器 Sample)
这个寄存器的值必须比 PWMPR 小。
它决定了在一个周期内,数到哪个数字时,把电平从 3.3V 拉低到 0V。
- 如果周期寄存器是
1000,你往PWMSAR里填入500,那前 500 个数是高电平,后 500 个数是低电平。恭喜你,得到了完美的 50% 占空比!
第三章:一行代码见证奇迹
不要死记硬背十六进制,我们来看一段真正的工程级推导代码。假设我们要输出一个特定的频率,并且保持最大音量(50% 占空比):
c
// 假设经过减速齿轮后,时钟频率是 1MHz
unsigned int period_value = 2000; // 我们设定周期为 2000
// 1. 设置周期(决定音调)
// 注意:硬件逻辑通常是从 0 开始数,所以实际填入要减 2(具体看手册定义)
PWM2_PWMPR = (period_value - 2) & 0xFFFF;
// 2. 设置占空比(决定音量)
// 我们要最响亮的声音,所以直接把周期值除以 2(即 50%)
unsigned int duty = 50;
unsigned int sample_value = period_value * duty / 100;
PWM2_PWMSAR = sample_value & 0xFFFF;
// 3. 扣动扳机(启动波形)
PWM2_PWMCR |= 1;
当这几行代码运行的瞬间,CPU 的任务就结束了。剩下的,就是硬件底层的 PWM 控制器像一个不知疲倦的鼓手一样,以纳秒级的精确度,持续向外界喷射着携带能量的方波。
结语:控制真实的物理世界
从 GPIO 的绝对 0 和 1,到 PWM 的"欺骗艺术",我们终于打破了数字系统的壁垒,开始真正介入连续的物理世界。
下次当你听到电动车加速时的蜂鸣音、看到呼吸灯的明暗交替、或者操纵无人机起飞时,你可以心生自豪:在那底下,只不过是几行向 PWMPR 和 PWMSAR 疯狂写入数据的 C 语言代码罢了!