课程导入

仅仅通过简单的数字信号输出,只能让输出的数据在0和1间切换,来关闭或打开灯光。并不能真正做到任意控制灯光的亮度,更不用说制作出更高级的效果了。为了实现更丰富的效果,需要使用模拟信号来进行输出,从而控制灯的亮度。

知识锦囊

就像上节课提到的, Pico 作为一种微控制器,并不能真正的直接理解模拟信号。模拟信号必须由 Pico 上搭载的模拟数字转换器(ADC , Analog to Digital Converter)转化为数字信号,才能被 Pico 理解。
同样,Pico 也不能直接发出模拟信号来控制模拟电路,它必将通过某种手段将自身发出的数字信号转化为模拟信号。而 Pico 本身并没有能将数字信号转化为模拟信号的“数字模拟转换器(DAC , Digital to Analog Converter)”,所以当 Pico 需要向外输出模拟信号时,就需要使用另一种方法—— PWM 脉冲宽度调制,来对模拟电路进行控制。

PWM

PWM 是英文 Pulse Width Modulation(脉冲宽度调制)的简写。其中脉冲是指脉冲信号,是微控制器内的晶体管周期性的不断开合所发出的数字信号。因为是由只有开和闭两种状态的晶体管所发出的信号,所以信号也只会在高电平和低电平间切换。
PWM 脉冲信号主要由三个成分组成:周期,占空比和频率。
如下图所示,周期(T)即是脉冲信号经历一次高电平状态(T1)和一次低电平状态(T2)所用的总时间,即 周期(T)=T1 + T2,而占空比则表示在一个周期中,信号处于高电平的时间与周期的比例,即:占空比 = 周期(T)/ T1。
频率则表示 PWM 每秒完成的周期数(1000 Hz即为每秒完成1000个周期),周期越短,相对的频率也就越高。
第7课 电路中的模拟信号(2)—— PWM 的使用 - 图1
所谓脉冲宽度调制就是对脉冲信号的占空比按照需求进行调制,而不改变脉冲信号的其他参数,从而将数字信号伪装成恒定电压的模拟信号。
那么脉冲宽度调制具体是如何实现的呢?以操控 LED 灯的亮度为例,当我们向 LED 灯输入 PWM 信号时, LED 灯实际接收到了一段不断在高低电平间切换的数字信号,该段数字信号会使 LED 灯不断的被打开和关闭。
而当打开和关闭的频率足够快,即 PWM 的频率足够高时,灯光的闪烁就无法被人眼所识别了。
这时我们只需要在周期不变的情况下,改变LED被点亮的时间与被关闭时间的比值,即调整占空比,就可以改变 LED 灯的亮度。
带入数字你可以更好的理解这一概念,如果在1毫秒内, LED 灯有0.5毫秒被开启,0.5毫秒被关闭,那么由于频率过快,你并不会感觉到灯光在闪烁,你只能感觉到灯光的亮度降低到了其在一直开启状态下的一半,而当这一数值被变为在1毫秒内, LED 灯有0.1毫秒被开启,0.9毫秒被关闭时,灯在你眼中的亮度就只有原来的十分之一了。
pico插图-06.png
要对占空比进行操作,就需要使用到算术运算符。

算术运算符

算术运算符顾名思义就是进行数学运算的运算符,我们通常使用的“+”“-”“*”“/”等都属于算术运算符。通过使用算术运算符,我们可以对程序中的变量或其他对象进行数学运算,从而改变它们的数值。
常用的算术运算符有以下几种,当a = 1,b = 2时:

运算符 描述 实例
+ 加 - 两个对象相加 a + b 输出结果 3
- 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -1
* 乘 - 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 2
/ 除 - x除以y b / a 输出结果 2
% 取模 - 返回除法的余数 b % a 输出结果 0
// 取整除 - 返回商的整数部分(
向下取整
>>> 9//2
4
>>> -9//2
-5

实践操作

项目一:使用旋转电位计控制LED灯亮度

我们先来看看如何使用 PWM 信号来进行模拟信号的输出,使用旋转电位计的返回值来控制 LED 灯的亮度。

硬件连接

在该项目中,我们所需要使用的硬件有:

  • 树莓派 Pico
  • 树莓派 Pico 拓展板
  • Grove - LED 灯
  • Grove - 旋转电位计

插接好 Pico 和拓展板,使用 Grove 数据线将 LED 灯连接到 D18 接口,将旋转电位计连接到 A0 接口。
页面_7.png

编写程序

与 Pin 相同,将引脚设置为 PWM 模式的函数也在 machine 库中:

  1. from machine import Pin,ADC,PWM

我们需要使用 PWM 来设置相关引脚,虽然 Pico 的每一个引脚都可以被设置为 PWM 引脚,但某些引脚却不能同时被设为 PWM 模式。这是因为 Pico 上的脉冲宽度调制器是被划分成了8个部分,每个部分拥有A和B两个输出,而 Pico 却拥有26个引脚,这导致 Pico 上的一些引脚会共用同一个部分的脉冲宽度调制器。所以当你需要设置多个 PWM 引脚时,需要注意避免引脚的设置发生冲突。
image.png
当然,在该程序中我们不用考虑这个问题,因为我们要做的仅仅是设置一个 PWM 引脚而已:

  1. ROTARY_ANGLE_SENSOR = ADC(0)
  2. LED_PWM = PWM(Pin(18))

设置好引脚后,使用 freq() 函数将 PWM 信号的频率设置为500:

  1. LED_PWM.freq(500)

选择合适的频率十分重要:如果频率很低,则 LED 灯在通电和断电时会导致 LED 灯的闪烁肉眼可见,时断时续;如果频率很高,则会导致 LED 灯开关来不及正常开合,影响稳定性。

在程序中,我们使用 read_u16() 来读取旋转电位计的返回值,使用 duty_u16() 来向 LED 灯输出模拟值。由于二者值的范围皆为0-65535,所以我们可以直接使用旋转电位计的返回值来控制 LED 灯的亮度。
在循环中,我们首先将旋转电位计输入的模拟值保存到变量 val 中,再将 LED 灯 PWM 信号的占空比设置为变量 val ,即可完成项目,完整的示例程序如下:

  1. from machine import Pin,ADC,PWM
  2. ROTARY_ANGLE_SENSOR = ADC(0)
  3. LED_PWM = PWM(Pin(18))
  4. LED_PWM.freq(500)
  5. while True:
  6. val = ROTARY_ANGLE_SENSOR.read_u16()
  7. LED_PWM.duty_u16(val)

image.png
使用 USB 数据线将 Pico 连接到电脑,点击运行按钮将程序保存到任意位置,转动旋转电位计,你就能看到程序的实际运行效果。
旋转电位计控制LED灯亮度.mp4
image.png
image.png

项目二:呼吸灯

该项目我们要实现呼吸灯效果,LED灯由暗到明,再从明到暗。

硬件连接

在该项目中,我们所需要使用的硬件有:

  • 树莓派 Pico
  • 树莓派 Pico 拓展板
  • Grove - LED 灯

页面_8.png
将 LED 灯连接在D18接口。

编写程序

要想实现呼吸灯效果,我们需要使用算术运算符对 PWM 信号的占空比直接进行操作。
首先声明我们所需要用到的库中函数,并设置好引脚。

  1. from machine import Pin,PWM
  2. import utime
  3. LED_PWM=PWM(Pin(18))

设置好引脚后,使用 freq() 函数将 PWM 信号的频率设置为500:

  1. LED_PWM.freq(500)

接下来就让我们着手实现呼吸灯效果,通过分析可以发现,呼吸灯效果其实是由两部分组成,第一部分是 LED 灯从黯淡状态逐渐亮起,当亮度到达最高时进度第二部分。在第二部分中,LED灯亮度开始衰减,直至熄灭。重复这两个部分,就能实现呼吸灯效果。
可以使用两个 while 循环语句来分别实现这两个部分的效果,首先设置一个变量 val 方便我们调整 PWM 信号的占空比。在程序的一开始,先将val设置为0:

  1. val = 0

接着先来实现第一部分, LED 灯逐渐亮起:

  1. while val<65535:
  2. val=val+50
  3. utime.sleep_ms(1)
  4. LED_PWM.duty_u16(val)

在该程序中,我们将 val 的值每隔一毫秒增加50,直到其大于65535,并使用 duty_u16 函数利用该值来调整 PWM 信号的占空比。
当val的值被增加到大于65535时,就会跳出第一个 while 循环,进入下一个 while 循环,同理,要使灯光逐渐暗淡,我们需要 val 的值在小于0之前不断减小 :

  1. while val>0:
  2. val=val-50
  3. utime.sleep_ms(1)
  4. LED_PWM.duty_u16(val)

再使用 while True 使两部分程序不断循环运行,呼吸灯的效果就完成了。

  1. import utime
  2. from machine import Pin,PWM
  3. LED_PWM=PWM(Pin(18))
  4. val=0
  5. LED_PWM.freq(500)
  6. while True:
  7. while val<65535:
  8. val=val+50
  9. utime.sleep_ms(1)
  10. LED_PWM.duty_u16(val)
  11. while val>0:
  12. val=val-50
  13. utime.sleep_ms(1)
  14. LED_PWM.duty_u16(val)

image.png
使用 USB 数据线将 Pico 连接到电脑,点击运行按钮将程序保存到任意位置,你就能看到程序的实际运行效果。
呼吸灯.mp4
image.png

思维拓展

除了 LED 灯以外,你还知道哪些电子模块是需要用 PWM 信号来控制吗?
蜂鸣器:
第7课 电路中的模拟信号(2)—— PWM 的使用 - 图11
舵机:
第7课 电路中的模拟信号(2)—— PWM 的使用 - 图12