通过前面课程的学习,我们掌握了Arduino引脚中的数字输出功能,后续课程中将会经常用到数字输出功能。本节内容将完成不一样的点灯程序。
在之前的LED点灯课程学习中,我们都只是控制了LED的亮灭,要么就是全亮(最亮),要么就是灭(直接不亮),这样的控制方式,我们叫做开关量控制,或者说数字控制(1和0)。在我们的实际生活中,更多的时候通过开关控制是不能达到我们想要的效果的。最简单的教室里的灯光,在傍晚时候,开灯呢又觉得没必要,或者过亮了,不开灯能又觉得有些许的暗,看书写作业会觉得伤眼睛。能不能有一种办法去实现灯光亮度的控制?这就是我们今天需要学习的内容。

【任务导航】

1.认识呼吸灯
2.掌握Arduino的PWM功能
3.掌握Arduino的模拟输出功能
4.掌握while()循环语句
5.掌握Mixly编程中的相关知识。

【知识加油站】

在之前的学习中我们知道了数字接口在数字输出模式下,写1的时候,在对应的引脚上表现出来的电压是5V,写0的时候表现出来的是0V,我们控制LED的亮灭就是控制引脚上电压在5V和0V之间变化。在5V的时候LED是全亮(最亮),在0V的时候是全灭。如果我们能控制这个5V的电压降低一点,比如降低到3V,这样是不是就能实现LED的亮度的不同了?但是问题来了,数字引脚在输出模式下并不能控制这个电压的变化。
大家是否还记得,在之前介绍Arduino主板的引脚功能的时候我们说过,D口表示的是数字接口,A口表示的是模拟口。D口只认识0和1,而模拟接口它可以把0-5V的电压分成1023份。我们能不能通过A口去实现控制电压的变化?很遗憾的告诉你,不可以。因为A口只能把在A口对应引脚上的电压识别为1024份,而不能输出1024份的电压控制。换句话说,A口只能是把输入的电压转化为1024份,而不能输出。当A口在输出模式下,同样只能是0或者1。详细的学习我们将会在后续课程中讲到。那是不是没有办法了呢?
不知道你还记不记得一个词:PWM。在Arduino引脚介绍时说过,在数字引脚中有些特殊的引脚具有PWM功能。Arduino的这个功能就是我们今天解决问题的关键。

1.呼吸灯

呼吸灯,顾名思义,就是灯光在微电脑控制之下完成由亮到暗的逐渐变化,感觉像是在呼吸。广泛应用于手机之上,现在各大手机厂商都把此功能作为了标配。比如你的手机有未接来电,未查收的短信等等,当手机里面有未处理的通知时,呼吸灯就会由暗到亮的变化,像呼吸一样那么有节奏,起到一个通知提醒的作用。

2.PWM

脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在测量、通信、功率控制与变换的许多领域,它可以将数字信号转化为模拟信号。

3.Arduino的模拟输出

在Arduino NANO主板中,只有数字接口上的6个针脚支持PWM功能,即3、5、6、9、10和11。PWM的输出值为0~255,LED发光模块接到这几个引脚上面,就可以控制LED的亮度,不会只有单纯的点亮和熄灭两种控制状态。
关于Arduino模拟输出功能的使用,在Arduino官方核心库中已经写好了一个专门针对这一功能的函数analogWrite()。analogWrite(pin,val)函数可以从一个引脚输出模拟值(PWM)。可用于让LED 以不同的亮度点亮或驱动电机以不同的速度旋转。analogWrite()输出结束后,该引脚将产生一个固定频率的方波信号,直到下次调用 analogWrite()(或在同一引脚调用 digitalRead()或 digitalWrite())。PWM 信号的频率大约是 490 Hz。在Arduino UNO控制器中,5号引脚和6号引脚的PWM频率为980Hz,在Mega控制器中,4号引脚和13号引脚的PWM频率为980Hz。在使用 analogWrite()前,不需要调用 pinMode()来设置引脚为输出引脚。
analogWrite()函数与模拟引脚、analogRead()函数没有直接关系, analogWrite()函数操作的是特殊数字引脚部分,功能是输出固定频率的不同占空比的PWM信号。(具体介绍请查看Arduino语法手册16.3章节)
语法结构:analogWrite(pin,value);
参数:pin:用于输出PWM信号的引脚,注意,不是模拟输入引脚,UNO和NANO主板只有数字口的3、5、6、9、10、11六个引脚具有此功能。
value:占空比:一个0-255之间的整数,0(完全关闭),255(完全打开)。

4.while()循环语句

while()循环会无限的循环,直到小括号内的判断语句变为假。在循环部分的语句中必须要有能改变判断语句的程序,要不然 while 循环将永远不会结束。可以在你的代码中改变判断的条件,比如递增的变量,或者是一个外部条件,比如传感器的返回值。
语法结构:

  1. while(表达式){
  2. //执行语句块
  3. }

参数:
表达式:为真或为假的一个计算结果
其中表达式称为循环条件,语句块称为循环体。while语句的意思是:先计算表达式的值,当值为真(非0)时,执行循环体语句;执行完循环体语句后再次计算表达式的值,如果为真,继续执行循环体……这个过程会一直重复,直到表达式的值为假(0)才退出循环。其执行过程如下图所示。(具体介绍请查看Arduino语法手册2.5章节)
第四节 LED亮度控制 - 图1
图2.4.1 while语句的程序流程图

【自己动手】

任务1:LED单一亮度控制

1.任务要求
通过analogWrite()函数,按自己意愿设置一个LED的亮度值,上传程序验证并观察实验现象。

2.所需器材
Arduino NANO主板(含扩展板),USB数据线,LED发光二极管,杜邦线2根。
把Arduino主板和扩展板对应插好,通过两根杜邦线把LED发光二极管连接到扩展板。在电路连接时注意区分LED的阳极和阴极,LED阳极需要接到扩展板D3接口,阴极接到扩展板GND接口。
在设置亮度时候,每次设置的亮度间隔大一些,比如第一次设置亮度为10,第二次设置亮度为100,第三次亮度为200,。如果亮度设置的间隔小了人眼不一定能分辨出来。

3.参考程序

  1. void setup() {
  2. //不需要设置D3引脚的工作模式,此处空着
  3. }
  4. void loop() {
  5. analogWrite(3,100); //设置D3位PWM输出,占空比为100
  6. }

Mixly单一占空比输出.png
以上程序是实现控制LED亮度为100。

任务2:LED多亮度控制

1.任务要求
通过analogWrite()函数,在一个程序中设置LED的三个亮度值,上传程序验证。三个亮度分别是10、100、200。

2.所需器材
同任务1。
在设置亮度时候,每一个亮度值建议显示2-3秒钟,方便人眼观察实验现象。

3.参考程序

  1. void setup() {
  2. //不需要设置D3引脚的工作模式,此处空着
  3. void setup() {
  4. //不需要设置D3引脚的工作模式,此处空着
  5. }
  6. void loop() {
  7. analogWrite(3,10); //设置D3位PWM输出,占空比为10
  8. delay(3000); //让LED以10的亮度点亮3秒
  9. analogWrite(3,100); //设置D3位PWM输出,占空比为100
  10. delay(3000);
  11. analogWrite(3,200); //设置D3位PWM输出,占空比为200
  12. delay(3000);
  13. }

Mixly输出3个不同大小的占空比.png

任务3:LED亮度连续控制

1.任务要求
通过analogWrite()函数,在一个程序中设置LED的亮度值连续的变化,实现呼吸灯渐强效果,上传程序验证。亮度值变化的间隔为5个亮度。

2.所需器材
同任务1。
在设置亮度时候,每一个亮度值显示5-20ms时间,已得到最佳的显示效果,根据显示效果自行调整显示时间和亮度值间隔。

3.参考程序

  1. byte i=0; //创建一个变量存储亮度值,并赋初值为0
  2. void setup() {
  3. //不需要设置D3引脚的工作模式,此处空着
  4. }
  5. void loop() {
  6. if(i<255){
  7. analogWrite(3,i); //设置D3位PWM输出,占空比为10
  8. delay(10); //让LEd以10的亮度点亮10ms
  9. i=i+5; //每次让亮度值加5后再保存
  10. }
  11. i=0;
  12. }

image.png

任务4:LED呼吸灯

1.任务要求
通过analogWrite()函数,在一个程序中设置LED的亮度值连续渐强再连续渐弱,实现标准呼吸灯效果,上传程序验证。亮度值变化的间隔为1个亮度。

2.所需器材
同任务1。
在设置亮度时候,每一个亮度值显示5-20ms时间,已得到最佳的显示效果,根据显示效果自行调整显示时间和亮度值间隔。

3.参考程序

  1. byte i=0; //创建一个变量存储亮度值,并赋初值为0
  2. void setup() {
  3. //不需要设置D3引脚的工作模式,此处空着
  4. }
  5. void loop() {
  6. while(i<255){ //亮度值小于255之前一直循环,直到达到255的亮度退出循环
  7. analogWrite(3,i); //设置D3位PWM输出
  8. delay(5); //让LED以i的亮度点亮5ms
  9. i++; //每次让亮度值加1后再保存
  10. }
  11. delay(200); //以最亮保持200ms
  12. while(i>0){ //亮度值大于0之前一直循环,直到达到0的亮度退出循环
  13. analogWrite(3,i); //设置D3位PWM输出
  14. delay(5); //让LED以i的亮度点亮5ms
  15. i--; //每次让亮度值减1后再保存
  16. }
  17. delay(200); //以0的亮度保持200ms
  18. }

Mixly连续输出实现呼吸灯.png

任务5:RGB_LED实现24位真彩颜色呼吸灯

1.任务要求
通过analogWrite()函数,编程实现RGB_LED灯的24位颜色显示及多彩呼吸灯效果,上传程序验证。

2.所需器材
Arduino NANO主板(含扩展板),RGB_LED发光二极管模块1块,杜邦线4根。
RGB_LED模块是共阴连接方式,所以在电路连接时RGB_LED模块上的R、G、B三个引脚分别连接到扩展板的D3、D5、D6,RGB_LED模块的GND连接到扩展板的GND接口。
在编程时,需要在D3、D5、D6三个引脚上输出PWM信号去控制RGB_LED 模块实现显示。

3.参考程序

  1. byte i=0; //创建一个变量存储亮度值,并赋初值为0
  2. void setup() {
  3. // PWM输出时,不需要设置为输出模式,此处空着
  4. }
  5. void loop() {
  6. while(i<200){ //白色的200个亮度值渐亮
  7. analogWrite(3,i);
  8. analogWrite(5,i);
  9. analogWrite(6,i);
  10. delay(4);
  11. i++;
  12. }
  13. delay(200);
  14. while(i>0){ //白色的200个亮度值渐暗
  15. analogWrite(3,i);
  16. analogWrite(5,i);
  17. analogWrite(6,i);
  18. delay(4);
  19. i--;
  20. }
  21. delay(200);
  22. while(i<255){ // 蓝色渐亮
  23. analogWrite(3,i);
  24. delay(10);
  25. i++;
  26. }
  27. while(i>0){ //蓝色渐暗
  28. analogWrite(3,i);
  29. delay(10);
  30. i--;
  31. }
  32. delay(200);
  33. while(i<255){ // 绿色渐亮
  34. analogWrite(5,i);
  35. delay(10);
  36. i++;
  37. }
  38. while(i>0){ //绿色渐暗
  39. analogWrite(5,i);
  40. delay(10);
  41. i--;
  42. }
  43. while(i<255){ // 红色渐亮
  44. analogWrite(6,i);
  45. delay(10);
  46. i++;
  47. }
  48. while(i>0){ //红色渐暗
  49. analogWrite(6,i);
  50. delay(10);
  51. i--;
  52. }
  53. }

Mixly PWM 输出控制RGB实现呼吸灯效果1.png
Mixly PWM 输出控制RGB实现呼吸灯效果2.png

【拓展学习】

1.PWM

PWM,脉宽调制:即通过一系列脉冲的宽带来调制(或控制)来等效得到所需要的波形(包括形状和幅值),如下图所示,咱们可以通过很多脉冲来恢复得到正弦波形。这也可以从高中所学积分的面积等效的原理解释。比如第1个脉冲所围的面积,等于第一个脉冲前由正弦波形围成的面积。通过改变方波的占空比,就可以改变等效的输出电压波形。试想一下,如果每个脉冲的宽度相等,则所等效的波形为一条直线,即为直流电压信号。PWM调制广泛应用与电机调速和阀门控制中。比如现在的电动车就是通PWM调速的。
第四节 LED亮度控制 - 图8
图2.4.2 PWM波形合成正弦波

2.数字信号和模拟信号

数字信号:是指幅度取值离散的,其值被限制在有限域范围内,如二进制码就是一种离散信号。其特点是抗干扰能力强,易于数字信号处理。现在很多信号基本上都是数字信号,如手机信号,计算机处理信息等等。
模拟信号:是指其信号波形是连续变化的,咱们可以在任意的瞬间取值。由于模拟信号易受干扰影响,不容易处理,一般都是先将模拟信号离散成数字信号,以便处理。两者的区别如下图所示:
第四节 LED亮度控制 - 图9
图2.4.3 模拟信号和数字信号
其实我们Arduino输出的PWM信号是数字信号,只是通过调整数字信号的占空比,已实现在LED上表现为模拟电压的变化,实现LED亮度的调节。我们学过的正弦波信号就属于模拟信号。

3.RGB真彩色

真彩色是指图像中的每个像素值都分成红、绿、蓝三个基色分量,每个基色分量直接决定其基色的强度,这样产生的色彩称为真彩色。计算机表示颜色也是用二进制。16位色的发色总数是65536色,也就是2的16次方;24位色被称为真彩色,它可以达到人眼分辨的极限,发色数是1677万多色,也就是2的24次方。
RGB颜色是红绿蓝光按照不同的比例混合而成的,他们的取值分别都是从0-255,一共256级。因此按照排列组合原理,这三种256等级的光线可以组合成256x256x256=16777216种颜色,通常也被称为1600万色或千万色。那为什么又称为24位色呢?因为这个数是2的24次方的的值。为什么老是用2的次方数来表示呢?这是因为计算机是2进制的,因此在表达色彩数量和其他一些数量的时候,都是用2的次方数来表示。这个24位色还有一种奇怪的称呼叫做8位通道色,这里的通道实际上就是指的红绿蓝这三种光线各自的亮度范围,通过之前我们的学习知道,这个亮度范围是256级(0-255),256是2的8次方,用二进制数表示就是8个1(111111111B),称为8通道色。
在有些地方可能你会看到说16位色是真彩色,这是因为人眼分辨的问题,16位色所包含的颜色已经超出了人间可见的全部色彩。16位色和24位色相比,在数据存储和数据运算上都减小了很多,所以很多时候大家都会用16位色来表示真彩色。
第四节 LED亮度控制 - 图10
图2.4.4 RGB_LED灯具光谱分布图

【思考与讨论】

1.能否用按键控制LED的亮度?想想该如何实现?
2.如何实现LED亮度的自动调节?
3.想一想还能制作哪些LED的灯光效果?