在开始本文内容之前,老周先纠正一个错误。在上一篇中,提到过 Arduino 开发板的 Vin 引脚,文中老周说这个供电口的输入电压不能高于 5.5V。这里有错,被卖家给的使用说明忽悠了,上 Arduino 官网看了一下说明和原理图,Vin 引脚的有效电压是 7 - 12V,和DC输入口一样;输入电压不能高于 5.5V 的是 5V 引脚。5V 引脚既可以为元器件供电(输出),也可以向这个引脚输入 5V 电压为开发板供电。
=========================================================================================================
本篇文章最后会完成一个很简单的实验,这个实验基本是电子实验中最经典的,被许多教程重复了几亿次。尽管是个老掉牙的实验,但该实验简单,而且有代表性。啥实验?就是标题上写着的,调节LED小灯的亮度。
当然了,不是你家里装的LED大灯泡,以开发板输出的功率,是不能点亮那种大灯泡的。咱们实验用的一般是发光二级管,如下面高清无码大图所示。
这个玩意儿很便宜,一两块钱能买到一堆,非常适合我们这种待脱贫人群的日常把玩。当你拿到这个玩意儿的时候,你可能会有一个疑问:这货有两个脚 ,没有标注正负极,我怎么区分呢?不知道你有没有仔细看,这货其实是国家三级残疾的,一条腿长,一条腿短,医学上叫啥来着,忘了。人家生产商是故意让它残疾,然后领养它的人就知道怎么照顾它了——长的那条腿是正极(阳极),短的是负极(阴极)。现在明白乎?
还有一种是四条腿的,分为“三长一短”和“三短一长”,咋理解?先看图。
这种叫 RGB 发光二极管,实际上和两个脚的是一样的,只是它分了蓝、绿、红三种颜色的光,然后三种光以不同亮度混合,可以组成各种颜色。“三长一短”就是 R G B 三个脚是正极,短的那个是负极,也就是说它们共一个负极,叫共阴;“三短一长”就是 R G B 三个脚是负极,长的那个是正极,即它们共用一个正极,叫共阳。
发灯二极管不同的颜色所需电压有差异,一般是 2.0 - 2.2 V,电压上下有波动没关系,烧不了,但是过高了就会烧。经老周实测,二极管如果不接电阻直接供 5V 就很危险,发热严重,3.3 V 情况相对好一点。但是,电阻肯定要加的,保险一点嘛,当然也不用加 1k 那么恐怖,200 Ω 左右就可以了。
你可以选可调电阻,这样比较灵活,就像这种,也很便宜。
这种电阻顶部有个螺丝,用“一”字螺丝刀旋转可以调节电阻。这种便宜,所以没有可视屏幕,可以用万用表来测电阻。你会发现电阻上面有三个脚,老周画了一个模拟图。
中间的 C 点类似个滑块,通过顶部的旋转螺丝,AC,CB两段的电阻会改变。假设这个电阻的最大阻值为 200 Ω,那么:
1、A、B 两端相接,其阻值就是固定的 200 Ω;
2、A、C 两端相接,可旋转螺丝来调节电阻大小,假如调节为 50 Ω;
3、B、C 两端相接,也可以通过旋转螺丝来调节阻值;
4、A-C 与 B-C 两段的电阻之和等于最大阻值,所以:若 A-C为160Ω,那么 B-C 段阻值为 200-160 = 40Ω。
以上计算为理论数据,使用万用表检测,会存在几欧姆的误差。
接下来咱们要了解一个概念—— PWM,全称为 Pulse Width Modulation,可译为“可调制脉冲”。在前面的烂文中,老周提过,GPIO 通信时输出两个状态信号,还记得不?哦,猜对了,就是高电平和低电平。好,现在你想一下,如果一个 GPIO 接口以一定的频率不断地输出电平信号,会发生什么?是不是会产生如下图所示的波形?
其中,突起来的就是高电平,与横轴重合的是低电平,由于通信接口只使用两个电平信号,于是发生的波形就成了方波。
方波的周期,也就是一秒钟内有多少个周期,就是我们常说的频率,单位是 Hz。例如,某脉冲方波的频率为 50 Hz,即一秒钟内循环50次,那么,每个周期的时长为 1 / 50 = 0.02 秒,合 20 毫秒。
既然脉冲中一个周期内可以输出高电平或低电平,那么,高电平与低电平两者所占用的时间,就形成另一个名词——占空比。用一句话解释,就是:高电平持续的时间占整个周期的百分比。
沿用上文的举例,若周期是 20 毫秒,如果高电平持续的时间为10毫秒,那么占空比 = 10/20 = 50%;如果高电平持续的时间为 15 毫秒,那么占空比 = 15/20 = 75%,低电平占用的时间比就是 25%。但占空比的定义是关注高电平的持续时间。
咱们这一次调节发光二极管亮度的实验就是用到 PWM。当然,调节电压或电阻也能改变亮度,不过开发板自身可不能改变电压和电阻,可以用一些稳压模块来调节。
为什么脉冲可以改变灯的亮度呢?回想一下,前面咱们聊过,对开发板而言,高电平的电压是 3.3V,低电平是 0V。接到二极管正、负两脚上的电压如果相等,由于没有电势差,不产生电流,灯就熄灭;反之,存在电势差,有电流通过,灯就亮。
情形1:二极管的正极接 GPIO 口,负极接 GND (接地,始终是低电平,相对 0V 电势)。此时,如果GPIO口输出高电平,与 GND 之间存在对0V的电势差,二极管发光;反过来,如果GPIO口输出低电平,那么,0V与GND的0V位于同一参考值上,没有电势差,二极管不亮。
情形2:二极管的正极接 3.3V(供电接口始终输出高电平),负极接GPIO口。如果GPIO口输出低电平,就相当于GND的作用了,有电流通过,灯亮;如果GPIO口输出高电平,也是 3.3V,与供电口的相对电平相同,没有电势差,无电流通过,灯灭。
现在入重点了,高电平灯亮,低电平灯灭,那么高、低电平交替输出呢?也就是高 - 低 - 高 - 低 - 高 - 低……那灯就会一亮一灭,也就是在闪。但是,由于灯从亮到灭的过程会有很短的个延时,如果这延时足够短,人的眼睛就看不到灯的闪烁(不知道猫眼能不能看到),视觉延迟导致反应不过来,就没感觉了。所以,用PWM调亮度时,频率不要太低,50 - 60 Hz 明显看到闪烁;选 100-200 Hz 比较好,频率太高了效果也不好,频率高到比灯熄灭的延时还短的话,就等于灯是一直有充足的电流可用,这样它就不会暗下来了,调节亮度就没效果了。
上面说的都是基本理论,下面咱们动手干活。
先要看看在树莓派上怎么配置 PWM 功能。配置文件依然是 /boot 目录下的那个 config.txt。下面是文档说明:Name: pwm
Info: Configures a single PWM channel Legal pin,function combinations for each channel: PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1) PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1) N.B.: 1) Pin 18 is the only one available on all platforms, and it is the one used by the I2S audio interface. Pins 12 and 13 might be better choices on an A+, B+ or Pi2. 2) The onboard analogue audio output uses both PWM channels. 3) So be careful mixing audio and PWM. 4) Currently the clock must have been enabled and configured by other means. Load: dtoverlay=pwm,<param>=<val> Params: pin Output pin (default 18) - see table func Pin function (default 2 = Alt5) - see above clock PWM clock frequency (informational)
这些文档最大的缺点是说得不清不楚,让你雾里看花,水中捞月。不过,根据文档的描述,树莓派有两路 PWM 引脚,所以以下这段很关键。
Legal pin,function combinations for each channel: PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0) 52,5(Alt1) PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)
树莓派有 GPIO 0 到 GPIO 27,所以:
Legal pin,function combinations for each channel: PWM0: 12,4(Alt0) 18,2(Alt5) PWM1: 13,4(Alt0) 19,2(Alt5)
第一路 PWM 是引脚 GPIO 12 和 GPIO 18,板上的序号是 32、12;
第二路 PWM 是引脚 GPIO 13 和 GPIO 19,板上的序号是 33、35。
此处只需要调节一个灯,所以开启第一路 PWM 就可以。
说一下这些参数的含义,12,4(Alt0),表示使用 GPIO 12,后面的4要按说明来配置,此处就是数值 4 表示 Alt0。前面的文章中提过,为了扩展 GPIO 的功能,会定义引脚的重用(或叫复用),即你指定不同的 Alt 就会启用对应的功能。
老周手上这块 4B,用 GPIO 12 无法产生 PWM,串联万用表检测不到电流,只有 GPIO 18 能用。其他版本不知,因为老周没有买齐所有树莓派版本。所以大家可以多试试,反正第一路 PWM 只有 GPIO 12 和 GPIO 18 两个口,不行就换一个。
使用 Linux 自带的 Nano 应用打开 config.txt 文件。
cd /boot sudo nano config.txt
记得加 sudo ,作用就不说了。
然后加上:
dtoverlay=pwm,pin=18,func=2
GPIO 18 启用 PWM 的 Alt 是 Alt5,所以 func 参数的值是2(参考刚刚上面说的),因为这个是所有树莓派版本默认支持的配置,故可以省略参数。
dtoverlay=pwm
按 Ctrl + X,退出,nano 提示是否保存,输入 Y,搞定。
下一步看看.NET 相关 API。
命名空间:System.Device.Pwm。
类:PwmChannel。
这是个抽象类,内部会根据平台实现不同类型,为了统一调用,公开一个静态方法——Create,定义如下:
static PwmChannel Create(int chip, int channel, int frequency = 400, double dutyCyclePercentage = 0.5);
chip 参数常为 0,即第一块控制芯片,channel 是第几路PWM通道,树莓派有两路,所以此参数可以用 0 或 1。本次咱们用的是第一路,所以值是 0。frequency 是频率,默认400 Hz。dutyCyclePercentage 是占空比,0.0 到 1.0,表示 0% 到 100%,默认 0.5(50%)。
调用这个静态方法后,得到一个 PwmChannel 实例,调用实例对象的 Start 方法就可以开始发生脉冲方波了,调用 Stop 方法停止脉冲。另外,Frequency 属性改变频率,DutyCycle 属性改变占空比,这两个属性都可以在 PWM 运作期间直接修改,不必重新 Start。
而咱们这次的调光实验就是通过改变占空比来实现的。占空比为 0%,始终是低电平,灯灭;占空比是 100% ,始终输出高电平,灯最亮;而亮度的改变就在 0% - 100% 之间的值。
代码灰常简单,老周直接上,你能看懂的。
PwmChannel pwmch = PwmChannel.Create(0, 0, 100, 0.0); // 开始PWM pwmch.Start(); int x = 5; while(x-- > 0) { for (int i = 0; i < 100; i++) { pwmch.DutyCycle = i * 0.01d; Thread.Sleep(20); } for (int i = 100; i > 0; i--) { pwmch.DutyCycle = i * 0.01d; Thread.Sleep(20); } } pwmch.Stop(); pwmch.Dispose();
DutyCycle 属性的有效值是 0.0 - 1.0,所以整型的百分比乘以 0.01,让它变成有效值。
接线方法:二极管的长脚(正)接 GPIO 18 引脚,短脚(负)接 GND(有很多个,随便挑一个),在 GPIO18 和二极管正极之间串联一个 200 欧姆的电阻。
最后,发布、上传,运行,效果类似于呼吸灯。
示例的代码链接,请用电钻扎这里。
调节小灯的亮度只是 PWM 的其中一个用途,该技术还有很多玩法。比如可以控制舵机的旋转角度,控制小风扇的转速,控制玩具喇叭唱歌(频率不同可以产生不同的音高)…… 下一篇烂文老周将介绍如何用 PWM 让小喇叭高歌一曲过大年。