现在我们开始尝试用代码控制一个真正的硬件设备。

第一个例子:让Arduino开发板上的一个LED小灯周期性的打开、关闭。
第二个例子:让LED灯亮度逐渐的变亮变暗。

3.1 LED灯的开关

3.1.1 原理介绍

Arduino开发板上,都会有两个LED指示灯。不同的开发板,LED指示灯的位置、颜色略有不同。

  1. 电源指示灯。当开发板连接上电源(或者通过USB线供电)后,用来指示电源是否接通。这个LED灯旁边肯定有一个“On”标记;

  2. 测试用指示灯。这是一个用来做内部测试的指示灯,也正是本示例要使用到的指示灯。在这个LED灯旁看到个‘L’标记;
    第3节 第一次硬件控制 - 图1

前面的章节中,我们介绍了Arduino开发板提供了3类引脚。其中数字引脚D13就控制着这个测试用指示灯。因此我们只需要在代码中控制好这个引脚就好了。
没有可外接的LED模块时,就用D13引脚来做测试。

3.1.2 代码设计

通过菜单栏创建一个叫做led.ino的文件,启动这个示例。

  1. 任何引脚在使用之前,都要在setup()中对它进行初始化,首先告知这个引脚用来输出-OUTPUT,还是用来输入-INPUT。这里的输入输出对象,是相对于开发板而言的。现在L灯,相当于是连接在D13号针脚上的一个外接硬件,灯的开关由D13号引脚上的电压决定,所以要将该D13针脚作为输出-OUTPUT。 ```cpp //定义引脚的编号,这里使用的是数字引脚13。 int LED_PIN = 13;

void setup() { //设置该引脚类型为输出 pinMode(LED_PIN, OUTPUT); }

  1. 2.
  2. 通过`digitalWrite()`函数,让指示灯变亮一秒,然后变暗一秒,如此往复,
  3. ```cpp
  4. void loop()
  5. {
  6. //将该引脚设置成高电平,也就是通电,打开指示灯
  7. digitalWrite(LED_PIN, HIGH);
  8. //延时1秒(即1000毫秒),在这1秒钟,LED灯状态不变,即点亮状态
  9. delay(1000);
  10. //将该引脚设置成低电平,也就是断电,关闭指示灯
  11. digitalWrite(LED_PIN, LOW);
  12. //延时1秒(即1000毫秒),在这1秒钟,LED灯状态不变,即熄灭状态
  13. delay(1000);
  14. }


loop()执行之后,会被循环再次执行,我们设计的效果就是LED灯一秒亮、一秒暗的不停循环。
delay(1000)表示这里要停顿1000毫秒。
digitalWrite()函数专门用来为数字引脚设置高低电平,这里的高低电平我们用了HIGHLOW分别表示。

  1. //将该引脚设置成高电平
  2. digitalWrite(LED_PIN, HIGH);
  3. //将该引脚设置成低电平
  4. digitalWrite(LED_PIN, LOW);


高低电平的说法是数字信号领域中的。它并不是说高电平的电压是1v,低电平的电压是0v,完全可以把1v的电压定义成低电平,5v的电压定义成高电平。而且在真实的物理世界中,不可能存在绝对的1v和5v,电压可能会围绕着1v或者5v有少许的波动,但着并不影响我们对高低电平的判断。
第3节 第一次硬件控制 - 图2
模拟信号就比较符合物理世界的真相,并不是非此即彼,会有很多连续变化的数值。Arduino的模拟引脚就用来处理这样的数据。
第3节 第一次硬件控制 - 图3
在Arduio开发板中,数字引脚会标注为D,模拟引脚会标注为A
第3节 第一次硬件控制 - 图4

3.1.3 结果观察

将工程编译部署到开发板上,就能看到D13连接到LED指示灯,一秒亮、一秒暗的不停闪烁。

3.2 LED灯明暗调节

3.2.1 原理介绍

数字引脚只能输出高电平HIGH或低电平LOW两种,但是通过脉冲宽度调制(Pulse Width Modulation简称PWM)就能让数字端口模拟输出多级的电压(通常是0级~255级,0级代表没有,255级代表最高电压)。

数字引脚上的电压,可以看成是一个个脉冲方波,当引脚一直处于高电平的时候,输出为V,

第3节 第一次硬件控制 - 图5

当引脚电压的脉冲方波周期中,有50%的时间中处于高电平的时候,平均输出就为V/2;

第3节 第一次硬件控制 - 图6

当引脚电压的脉冲方波周期中,有33.3%的时间中处于高电平的时候,平均输出就为V/3;

第3节 第一次硬件控制 - 图7

以此类推。

*更官方的表述请参考官网

Arduino开发板提供的数字引脚中,有的引脚就具备了PWM的能力:能够设置这些数字引脚的电压输出级数。具有PWM功能的引脚,在开发板上有专门的标注,前面会有一个波浪线〰️

第3节 第一次硬件控制 - 图8

  1. int LED_PIN = 13;
  2. pinMode(LED_PIN, OUTPUT);
  3. ......
  4. //设置成输出10级电压,电压强度从0~255
  5. analogWrite(LED_PIN, 10);

这里面,我们使用了analogWrite()函数,向D13引脚写入了第10级的亮度。

通过官网给出的规格,可以看出Arduino MEGA开发板的D13引脚,是具备PWM功能的。所以我们可以让测试指示灯渐变明暗。

不过Arduino UNO开发板上的D13引脚并不具备PWM功能,因此要在它上面进行灯光强弱调整的实验,必须要在其他的引脚上,外接一个LED灯硬件。这部分内容,我们稍后会介绍。

3.2.2 代码设计

改造led.ino文件,实现UNO或者MEGA开发板的PWM的功能。

  1. setup()中对它进行初始化,告知这个引脚用来输出-OUTPUT,或者用来输入-INPUT。这里是要初始化D13引脚(MEGA板的L灯可以实现PWM),让它作为输出。 ```cpp //定义引脚的编号,这里使用的是数字引脚13 int LED_PIN = 13;

void setup() { //设置该引脚为输出 pinMode(LED_PIN, OUTPUT); }

  1. 2.
  2. 通过`analogWrite()`函数,让指示灯逐级变亮,然后逐级变暗,如此往复,
  3. ```cpp
  4. void loop()
  5. {
  6. //将该引脚从0级逐步设置到255级,指示灯逐渐变亮
  7. for(int level = 0; level < 256; level++)
  8. {
  9. analogWrite(LED_PIN, level);
  10. //延时100毫秒,LED灯状态不变
  11. delay(10);
  12. }
  13. //将该引脚从255级逐步设置到0级,指示灯逐渐变暗
  14. for(int level = 255; level >= 0; level--)
  15. {
  16. analogWrite(LED_PIN, level);
  17. //延时100毫秒,LED灯状态不变
  18. delay(10);
  19. }
  20. }


loop()执行之后,会被循环再次执行,我们设计的效果就是LED灯逐渐变亮,再逐渐变暗。
这里使用了analogWrite()函数向数字引脚设置电压0级~255级中的任何一级,

  1. //将该PWM引脚设置成0~255级中的任何一级
  2. analogWrite(LED_PIN, level);


可见analogWrite()函数并不像它的名字那样只是模拟引脚的专利,它对支持PWM的引脚同样适用。而且可以发现相对于digitalWrite()只能设置高低电平,analogWrite()可以设置更广泛的数值。不过请注意,这个数值并不是电压的大小,而是经过转化后的整数,具体设置成多大的电压,我们开发人员不用操心,只需要知道0最小,255最大。

3.2.3 结果观察

将工程编译部署到开发板上,就能看到MEGA开发板上,D13连接的LED指示灯一会儿亮一会儿暗,逐渐变化。

3.3 其他LED灯的使用

除了使用MEGA开发板的D13引脚,我们也可以使用任何其他带PWM功能的数字引脚。例如Arduino MEGA开发板的D2~D13 D44 D46;Arduino UNO开发板的3 5 6 9 10 11。将LED灯接到这些引脚上面,就能同样的实现对LED灯的控制。

3.3.1 LED模块

LED模块可能是单色的:只能发出一种颜色的光,这种模块有3个引脚,标注字符S的是控制灯光强度的引脚、VCC或者+是电源引脚、GND或者G是接地引脚,例如单色LED灯模块,

第3节 第一次硬件控制 - 图9

LED灯也可能支持3种基础颜色-红绿蓝,这种模块有4个引脚,例如三色LED灯模块,

  1. 标注字符R的是控制红色灯光强度的引脚;
  2. 字符G的是控制绿色灯光强度的引脚;
  3. 字符B的是控制蓝色灯光强度的引脚;
  4. GND是接地引脚,

第3节 第一次硬件控制 - 图10

3.3.2 连接模块

这里我们先用单色的LED灯模块举例。

MEGA开发板,2-13引脚都支持PWM,随便选一个都可以。

第3节 第一次硬件控制 - 图11

UNO开发板,3,5,6,9,10,11引脚支持PWM,可以在开发板上看到引脚数字边上有个’~’。

第3节 第一次硬件控制 - 图12

这里我们选择D9引脚来连接LED灯。

LED灯的S引脚连接到MEGA(或者UNO)D9引脚;VCC接到MEGA(或者UNO)5V引脚;GND接到MEGA((或者UNO)GND引脚。

早期的开发板,为了防止电压不稳定击穿电子器件,需要连接个电阻。
现在的开发板,只在接马达时才需要增加电阻,惯常的做法是增加一块扩展板。

在实际的硬件连接当中,我们通常用扩展板来连接LED模块和开发板。

第3节 第一次硬件控制 - 图13

这里我们使用传感器扩展板,

第3节 第一次硬件控制 - 图14

可以看到扩展板上已经印制出了每个引脚的含义,

对于数字引脚扩展槽来说,
GND或者G:接地引脚
VCC或者V:供电引脚
D或者S:被扩展出的引脚,其下方的数字代表该引脚的编号

第3节 第一次硬件控制 - 图15

对于模拟引脚扩展槽来说,
GND或者G:接地引脚
V或者+:供电引脚,
S或者D:被扩展出的引脚,其下方的数字代表该引脚的编号

第3节 第一次硬件控制 - 图16

所以,对于这里的情况,我们选择标注了9的数字引脚扩展插槽。

扩展板引脚 连接 单色LED灯模块引脚
9组V <—->
9组G <—-> G
9组S <—-> S

第3节 第一次硬件控制 - 图17

如果使用UNO的扩展板,它可能是下面这个样子,

第3节 第一次硬件控制 - 图18

虽然不同开发板使用的扩展板长相各不相同,但它们上面标注的信息都是一致的

3.3.3 修改代码

因为这次我们使用了D9引脚,所以需要修改前面使用的D13引脚为D9,

  1. //定义引脚的编号,这里使用的是数字引脚9
  2. int LED_PIN = 9;
  3. void setup()
  4. {
  5. //设置该引脚为输出
  6. pinMode(LED_PIN, OUTPUT);
  7. }
  8. void loop()
  9. {
  10. //将该引脚从0级逐步设置到255级,指示灯逐渐变亮
  11. for(int level = 0; level < 256; level++)
  12. {
  13. analogWrite(LED_PIN, level);
  14. //延时100毫秒,LED灯状态不变
  15. delay(10);
  16. }
  17. //将该引脚从255级逐步设置到0级,指示灯逐渐变暗
  18. for(int level = 255; level >= 0; level--)
  19. {
  20. analogWrite(LED_PIN, level);
  21. //延时100毫秒,LED灯状态不变
  22. delay(10);
  23. }
  24. }

3.3.4 结果观察

将工程编译部署到开发板上,就能看到D9连接到LED指示灯,一会儿亮一会儿暗的逐渐变化。

3.3.5 使用三色LED灯

使用三色的LED灯模块,与使用单色的LED灯模块一样。在硬件连接时,要同时把红R、绿G、蓝B三种颜色对应的引脚连接到PWM接口上。例如使用数字引脚D9、D10、D11,分别对应红、绿、蓝三种颜色,就要多使用几个扩展板的插槽,将对应的R G B引脚插在标注了9 10 11编号的数字扩展口上,

第3节 第一次硬件控制 - 图19

在代码中要初始化三个PWM接口。

  1. //定义引脚的编号,这里使用的是数字引脚D9、D10、D11,
  2. //分别对应红、绿、蓝三种颜色
  3. int RED_LED_PIN = 9;
  4. int GREEN_LED_PIN = 10;
  5. int BLUE_LED_PIN = 11;
  6. void setup()
  7. {
  8. //设置该引脚为输出
  9. pinMode(RED_LED_PIN, OUTPUT);
  10. pinMode(GREEN_LED_PIN, OUTPUT);
  11. pinMode(BLUE_LED_PIN, OUTPUT);
  12. }
  13. void loop()
  14. {
  15. //将该引脚从0级逐步设置到255级,指示灯逐渐变亮
  16. for(int level = 0; level < 256; level++)
  17. {
  18. analogWrite(RED_LED_PIN, level);
  19. analogWrite(GREEN_LED_PIN, level);
  20. analogWrite(BLUE_LED_PIN, level);
  21. //延时100毫秒,LED灯状态不变
  22. delay(10);
  23. }
  24. //将该引脚从255级逐步设置到0级,指示灯逐渐变暗
  25. for(int level = 255; level >= 0; level--)
  26. {
  27. analogWrite(RED_LED_PIN, level);
  28. analogWrite(GREEN_LED_PIN, level);
  29. analogWrite(BLUE_LED_PIN, level);
  30. //延时100毫秒,LED灯状态不变
  31. delay(10);
  32. }
  33. }

3.4 传感器引脚标注的约定

经过上面的操作,我们对开发版和元器件也有了初步的认识。大家可以发现,以后主要的工作就是使用连接线连接开发板(或者扩展板)和各种传感器器件。

传感器只需要连接3种引脚:电源正极、电源负极和数据线。

  • 电源正极引脚:通常会标注为+ VCC 这种字样;
  • 电源负极引脚:通常会标注为- GND 这种字样;
  • 数据引脚:大部分传感器只有一根数据引脚,读取或者设置数据,比如单色LED灯;不过有的传感器要使用较多的引脚设置数据,比如LED屏幕阵列;这些数据线引脚的标注,就可能大不相同了,有的标注S,有的标注D,或者其他的,不过只要仔细观察、区分出了电源正负极之后就都能正确找到。至于如何使用这些数据引脚,就要看你购买的产品说明了,它通常会详细的告诉你这些引脚的含义,如何读取或者设置。

上面案例中使用的三色LED灯,没有VCC,而是直接使用的R``G``B标注对应的引脚也是可以的,所以说,具体的使用方法最好还是看看产品配套的说明。