将-Arduino-连接到-Web-全-

龙哥盟 / 2024-10-06 / 原文

将 Arduino 连接到 Web(全)

原文:Connecting Arduino to the Web

协议:CC BY-NC-SA 4.0

一、Arduino,电路和元件

本章介绍 Arduino 的电子学。它将解释 Arduino 是如何设置的,以及电流是如何流经电路和组件的。到本章结束时,你将使用一些基本元件,并创建四个基本电路:模拟输入,模拟输出,数字输入和数字输出。

Arduino

Arduino 允许您创建自己的电子项目。它是一个开源硬件和软件的集合,允许您连接和控制其他组件来创建一个电路。自动植物浇水系统、披萨烤箱或遥控玩具车等项目都可以用 Arduino 制作。当您在项目中使用 Arduino 时,您需要执行以下操作:

  • 将组件连接到它。
  • 编写一个程序来控制这些组件。
  • 验证程序是否编写正确。
  • 将程序上传到 Arduino。

Arduino 需要通过 USB 端口连接到电脑,才能将程序上传到电脑。Arduinos 的程序叫做草图。一旦草图被上传,它就被存储在微控制器上,并一直保存到另一个草图被上传。新草图上传后,旧草图不再可用。

一旦草图被上传,你可以将 Arduino 从电脑上断开,如果它连接到另一个电源,程序仍然会运行。

Note

一旦草图被上传到 Arduino,它就不会以你所写的方式显示。您无法从 Arduino 中以可作为原始草图读取的形式取回草图,因此如果您想要保留它,请确保保存您的原始代码。

硬件烧坏

Arduino 板由许多组件组成,包括微控制器、数字和模拟引脚、电源引脚、电阻、二极管、电容和 LED。图 1-1 显示了一个 Arduino Uno。

A453258_1_En_1_Fig1_HTML.jpg

图 1-1

An Arduino Uno

微控制器具有中央处理单元(CPU);它存储上传的草图,并处理和指导命令。

数字和模拟引脚用于发送和接收数字和模拟数据。

Arduino 还有一个串行接口,允许 Arduino 通过串行端口向计算机发送数据;这就是我们在本书中向计算机发送数据和从计算机接收数据的方式。

电流

使用 Arduino,您可以创建一个电子电路,为连接到它的组件供电。由导电材料制成的电线连接着让电流通过的部件。

电是电子通过导电材料的运动。在导电材料中,电子可以很容易地在原子之间移动,但在非导电材料中却不能。

原子由质子、中子和电子组成。原子的中心是原子核、质子和中子;电子在外面。质子带正电荷,电子带负电荷。这两种电荷相互吸引。电子在围绕原子核的轨道上。在非导电材料如木头或瓷器中,电子很难移动;它们紧紧地束缚在原子上。在像铜和其他金属这样的导电材料中,电子与原子的结合非常松散,因此它们可以很容易地移动。这些电子在原子的外缘,被称为价电子。

电子在电路中从负极向正极移动。当电第一次被发现时,人们认为它是从正极到负极移动的,所以按照惯例,电子电路通常是从正极到负极,从正极到地(GND)。在本书的电路中,电流将向一个方向流动;这被称为直流电(DC),而在交流电(AC)中,方向每秒钟改变一定次数。

为了让导电材料中的电子开始移动,它们需要一个推力,这个推力就是电压。电压是电路中较高势能和较低势能之差。电子想从较高的势能流向较低的势能,从正极流向负极。

产生电压的方式有很多种。在电池中,它是由化学反应产生的。在电池的负极会产生电子的积聚。当连接到电池的正极时,负电子被吸引到正极,从较高的势能到较低的势能。这导致它们推动电线上的电子;电子沿着导线分流。

在电学中,电流是指每秒钟通过某一点的电子数量。电流是以安培为单位测量的。电路中的每一个元件都会消耗一部分电能,并将其转化为另一种形式的能量,如光或声音。电路上的元件使用电路中的所有能量。

电路也有电阻。电阻是电流流过的物质减慢电流的程度。阻力就像水流路上的障碍。电阻以欧姆为单位,使用符号ω。电总是选择最容易流动的方式,阻力最小的路径。图 1-2 解释了电压、电流和电阻之间的关系。

A453258_1_En_1_Fig2_HTML.png

图 1-2

An interpretation of voltage, current, and resistance

欧姆定律

物理学家和数学家乔治·西蒙·欧姆发现了电压、电流和电阻之间的关系;这个关系叫做欧姆定律。欧姆定律说电压等于安培乘以电阻,写成 V = I * R 其中 V 是伏特,I 是电流,R 是电阻。利用该公式,您还可以找到电阻 R = V / I,并找到电流 I = V / R,这些可以在图 1-3 中看到。

A453258_1_En_1_Fig3_HTML.jpg

图 1-3

Ohms law

电路上的元件使用电路中的部分能量,并将其转化为另一种形式的能量,如光或声。电路上的所有能量都需要被电路使用。如果所有的能量没有用完,它需要去某个地方,否则会导致过热或着火。例如,如果电路上有一个 LED,并且它接收了太多的能量,那么灯将会非常亮,并且可能会熄灭。根据欧姆定律,你可以计算电阻,而不是 V = I * R,你可以用 R = V / I 来计算电阻,电阻等于电压除以电流。

电阻

电阻器是电路的关键元件,因为它们限制电路上的电流量。电阻器对电流有一定的阻力。每个组件都有一个最大的电流量,用它可以安全使用的安培数来衡量。例如,如果一个元件可以承受最大 0.023 安培的电流,即 23 毫安,而您的电路接收的是 5V(伏特),则需要在电路中增加一个 220 欧姆的电阻,以便安全地使用 LED。电子元件将使用来自电路的一些功率;这被称为电压降,因此在计算电阻时可以考虑到这一点。图 1-4 显示了如何利用欧姆定律,在不同的电压和电流下计算的示例。

A453258_1_En_1_Fig4_HTML.png

图 1-4

The formulae to find the resistance needed for a circuit

当你得到一个元件时,它也应该有一个数据手册,可能是在线的。这将为您提供有关电压降和最大电流的信息。这将允许你计算出你的电路需要什么样的电阻。

电阻器的阻值以欧姆为单位;他们有一个颜色代码来显示价值。电阻值告诉你它将消耗多少电流。

电子电路图

电路图直观地描述了一个电路。有几组图标用来显示电子电路中的元件。在本书中,我不会使用电子电路图来展示项目中使用的电路,而是使用 Arduino 和组件的图像。图 1-5 给你一个电路图的概念。这是一个 LED 的电路图。

A453258_1_En_1_Fig5_HTML.jpg

图 1-5

A circuit diagram for an LED with a resistor

图 1-6 显示了一些可以在电路图中使用的图标。

A453258_1_En_1_Fig6_HTML.jpg

图 1-6

Some circuit diagram icons

Arduino 软体

Arduino 有自己的编程语言;它是一组 C 和 C++函数。Arduino 程序被称为草图,它们有一个. ion 扩展名。Arduino 有自己的集成开发环境(IDE ),它有一个编辑器和其他工具来帮助你编写和上传代码。

下载和设置 Arduino IDE

您可以在计算机上安装 Arduino IDE。Arduino IDE 可以在线获得,并且易于下载和安装;您可以遵循以下说明:

  1. 前往 https://www.arduino.cc/en/Main/Software
  2. “下载 Arduino IDE”部分包含 Mac 和 PC 的链接。

对于 MAC 电脑:

  1. 点按“Mac OS X 10.7 Lion 或更新版本”链接,然后选择“仅下载”或“贡献并下载”;两个按钮都在图片下方。
  2. 解压缩下载的文件。
  3. Arduino 图标将会出现,只需点击它即可打开 IDE。

对于 PC:

  1. 根据您在计算机上拥有的管理员权限,单击链接 Windows Installer 或 Windows ZIP 文件进行非管理员安装。选择“仅下载”或“贡献并下载”。
  2. 解压缩下载文件。
  3. 您应该能够打开带有图标的 IDE。

当您打开 IDE 时,应该会打开一个新的草图。图 1-7 是一个编辑窗口的例子。

A453258_1_En_1_Fig7_HTML.jpg

图 1-7

An Arduino IDE edit window

草图将包含两个功能,设置和循环。页面顶部有一个勾号图标。按下该按钮是为了验证您的代码是否编写正确。如果有任何问题,您会在控制台中看到一条红色消息。当您想要将草图上传到 Arduino 时,请单击箭头图标。控制台将显示与您的草图相关的消息。当草图被验证和上传后,它会显示你的代码和信息中的任何错误。

将 Arduino 连接到电脑

您需要一根 USB 2.0 型电缆来将 Arduino Uno 连接到您的电脑。USB 将用于向 Arduino 发送数据和从 Arduino 接收数据,以及为其供电。不同类型的 Arduinos 将使用不同类型的电缆。

双击图标打开 IDE 并用 USB 将 Arduino 连接到计算机后,您需要检查工具菜单,查看 Arduino Uno 是否作为主板列出,以及它连接到哪个端口。在菜单中进入工具/板,并检查板说“Arduino/genu ino Uno”;如果没有,从下拉菜单中选择 Uno。

港口

您将通过其中一个 USB 端口将 Arduino 连接到计算机;这些端口有一个编号,在 Arduino IDE 的工具菜单中,您需要检查端口下拉列表来选择端口。

查看“工具/端口”菜单,确保 USB 端口被选中。根据您将 Arduino 插入的 USB 端口以及您使用的是 Mac 还是 PC,它看起来会略有不同。在 Mac 上,它应该显示类似“dev/Cu . usbmodem 621(Arduino/genu ino Uno)”的内容。在个人电脑上,它会显示类似“COM4 (Arduino/Genuino Uno)”的信息

Write a Sketch

Arduino 有一个内置的 LED,所以最容易写的草图是一个控制它并使它闪烁的草图。这是大多数人会写的第一个草图,并且如此普遍,以至于你拥有的 Arduino 在你得到它的时候可能已经安装了它。

Arduino IDE 有许多示例草图,blink 就是其中之一。在 IDE 中,如果您转到文件/Examples/01。你会看到眨眼的草图。您可以从那里打开它,或者从清单 1-1 中的代码复制它。您需要在上传之前保存它。

void setup() {
  pinMode(13, OUTPUT);
}
void loop() {
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
}
Listing 1-1
blink.ino

代码解释

每当你打开一个新的草图,你总是会得到设置和循环功能。首次运行程序时,会调用一次 setup 函数。当 Arduino 通电时,loop 函数将继续循环并执行其中的命令。blink.ino 正在使用 Arduino 上的 LED 并控制它。该 LED 位于 Arduino 上的数字引脚 13,因此在设置中,您可以使用 pinMode 功能来说明引脚 13 正被用作输出,它将会亮起。

该环路具有 digitalWrite 功能,可告知引脚 13 是高电平还是低电平(开或关)。延迟功能将循环暂停一会儿;否则,一旦它完成了上一行,它就会运行到下一行代码。延迟以毫秒为单位。表 1-1 更详细地解释了 blink.ino。

表 1-1

blink.ino explained

| `void setup() {``pinMode(13, OUTPUT);` | 设置是一种功能。函数可以返回值,在这种语言中,当你写函数时,你需要声明它将返回什么。setup()和 loop()都不返回任何内容,所以 void 关键字放在它们前面。函数由函数名后跟括号组成。括号可以是空的,也可以包含参数。当调用函数时,参数被传递给函数。花括号括起了函数的代码。 | | `pinMode(13, OUTPUT);` | Arduino 库附带了许多您可以使用的功能。pinMode 是其中之一,digitalWrite 是另一个。当你使用一个函数时,它被称为调用一个函数。要调用一个函数,你要写函数名,后面跟着括号。如果函数需要参数,它们被放在括号内。如果不是,它们是空的。对函数的调用以分号结束。分号让程序编译器知道这是调用或命令的结尾。 |

您可以验证代码,检查它的语法是否正确,然后将它上传到 Arduino。要验证它,请按代码顶部的勾号箭头,要上传它,请单击箭头图标。这些都显示在图 1-7 中。

注意 Arduino IDE 对语法错误非常敏感,如果你忘记了一个“;”在一个命令的结尾,或者在应该是大写字母的时候写小写字母,你会得到一个错误。IDE 非常善于让您知道错误在哪里,并且通常很容易修复。

试验板

试验板用于电子产品的原型制作;这是一种无需焊接即可将组件连接到 Arduino 的方法。它由塑料制成,上面有一系列的孔,用于部件的插脚和电线。它们通常有两个条形孔,分别用于电源和接地。试验板内部是导电的金属条。电线和插脚与这些金属条连接形成电路。它们可以有不同的尺寸。图 1-8 显示了一个试验板。

A453258_1_En_1_Fig8_HTML.jpg

图 1-8

A Breadboard

电缆

Arduino 初学者工具包附带了许多电缆,您可以在大多数项目中使用这些电缆在 Arduino 和使用试验板的组件之间建立电路。有些元件的引脚很难安装到试验板上。在第十章中,当你制作游戏控制器时,你可能需要使用不同头的电缆。有三种类型的电缆:男性对男性,女性对男性,女性对女性。如图 1-9 所示。

A453258_1_En_1_Fig9_HTML.jpg

图 1-9

Cables

数字和模拟

在 Arduino 上,您可以使用数字输入、数字输出、模拟输入和模拟输出。数字输入或输出可以有两种状态,开或关(高或低)。当使用 5V 时,模拟输入或输出可以在 0 和 1023 之间。本章中的以下练习展示了数字输出和输入以及模拟输入和输出的示例。

Caution

连接组件时,必须拔掉 Arduino 的插头。当它连接到您的电脑时,会有电流通过,这可能会导致触电。如果一个组件的能量过大,它可能会爆裂或爆炸,所以如果发生这种情况,你不要太靠近。

Digital Output

用于数字输出的元件接收高电平信号表示开,接收低电平信号表示关。清单 1-1 中的代码使用数字输出。在本练习中,您将使用与清单 1-1 中相同的代码 blink.ino,它是一个连接到 Arduino 的 LED。为此,您需要:

  • 1 x 火神一号
  • 1 个 LED
  • 1 x 220 欧姆电阻器

部件如图 1-10 所示,部件的设置如图 1-11 所示。在连接组件之前,请确保您已将 Arduino 从计算机或任何电源上拔下。Arduino 的长腿是正的,短腿是负的。

A453258_1_En_1_Fig11_HTML.jpg

图 1-11

Setup for the components for the digital output exercise

A453258_1_En_1_Fig10_HTML.jpg

图 1-10

Components for the digital output exercise: 1. Breadboard, 2. LED, 3. 220 Ohm resistor, 4. Arduino Uno

用 USB 将 Arduino 插回电脑。如果你上传的最后一个程序是 blink.ino,那么你应该会看到 LED 在闪烁。如果没有,重新上传 blink.ino。

模拟输出

模拟输出和输入产生一系列按顺序上升和下降的数字。在 Arduino 上,一些数字引脚旁边有一个“~”符号。这些引脚用于模拟输出,并使用 PWM(脉宽调制)。

脉宽灯

PWM 用于通过数字引脚模拟模拟输出。数字信号可以是开或关的,它发送一个开的脉冲。PWM 通过改变脉冲的长度来模拟使用数字信号的模拟系统;现在是模拟 5V 和 0V 之间脉冲的“开启”时间。图 1-12 显示了模拟不同电压的脉冲宽度。

A453258_1_En_1_Fig12_HTML.jpg

图 1-12

Pulse width modulation Analog Output

由于模拟信号可以产生一系列的数字,所以你可以循序渐进。在本练习中,LED 将在关闭前慢慢变亮,然后再次变亮。本练习的组件与图 1-10 相同。确保 Arduino 被拔出,然后如图 1-13 所示设置组件。LED 连接到数字引脚 9,旁边有一个~。

A453258_1_En_1_Fig13_HTML.jpg

图 1-13

Setup for analog output

创建一个新的 ino 草图,我将其命名为 mine chapter_01_1.ino,并将清单 1-2 中的代码复制到其中。

int analogOutPin = 9;
int outputValue = 0;

void setup() {
  pinMode(analogOutPin, OUTPUT);
}

void loop() {
  if (outputValue >= 40){
     outputValue = 0;
  } else {
     outputValue = outputValue + 1;
  }
  analogWrite(analogOutPin, outputValue);
  delay(200);
}

Listing 1-2
chapter_01_1.ino

代码解释

为了让 LED 逐渐变亮,你需要给它一个在每次循环中增加的值。这段代码中有许多新的编程概念。如果您还没有完全理解它们,不要太担心,因为接下来的几章将更详细地介绍编程。表 1-2 更详细地解释了 chapter_01_1.ino 中的代码。

表 1-2

chapter_01_1.ino explained

| `int analogOutPin = 9;` | 引脚 9 将用于 LED 通常的做法是将这个数字存储在整个程序中使用的变量中。这使得在整个程序中更容易看到该号码所代表的含义,并且如果您决定使用不同的 pin 号码,也允许您在代码中更改一次 pin 号码。 | | `int outputValue = 0;` | 变量保存 LED 的值。 | | `if (outputValue >= 40){``outputValue = 0;``} else {``outputValue = outputValue + 1;` | if else 语句检查某事是否为真;如果是,它做一件事,如果不是,它做另一件事。在这种情况下,它检查变量 outPutValue 的值是否大于或等于 40;如果是,它使变量包含值 0,这关闭 LED,如果不是,它增加 1,打开 LED 的亮度。 | | `analogWrite(analogOutPin,``outputValue` | analogWrite 函数有两个参数:管脚号和值,在这种情况下,outputValue 中的值被发送到连接到管脚 9 的组件。在这种情况下,它是一个 LED,这将改变 LED 的亮度。 |

将草图上传到 Arduino 您应该会看到 LED 亮度增加,然后熄灭。

数字输入

显示数字输入的良好电路是开关按钮。开关按钮不是向上就是向下,它有两种状态:按下或未按下。它引入了另一个概念,叫做输入上拉。

带开关的 Arduino 有问题。当开关打开时,它没有完成电路,没有电压,所以 Arduino 不知道输入是什么;可能是 0,也可能是 1。由于它不知道您可能会得到奇怪的结果,所以它会产生噪声,因为输入值是未知的,并且它会尝试输入一些东西。上拉电阻解决了这个问题;当开关打开时,它设置一个电压。

上拉电阻内置于 Arduino 中,当使用 pinMode()函数时,可以通过将其设置为 INPUT_PULLUP 而不仅仅是 INPUT 来访问。当开关打开时,引脚读数为高,当开关按下时,引脚读数为低。

Digital Input

在本练习中,您将使用一个按钮来打开和关闭 Arduino 上的 LED。为此,您需要:

  • 1 x 火神一号
  • 1 个开关按钮

更换组件时,请记住断开 Arduino 与电脑的连接。开关安装在试验板上。一个引脚接地,另一个引脚连接数字引脚 2。图 1-14 显示了所需的组件,图 1-15 显示了 Arduino 的设置。

A453258_1_En_1_Fig15_HTML.jpg

图 1-15

Setup for the components for the digital input exercise

A453258_1_En_1_Fig14_HTML.jpg

图 1-14

Components for the digital input exercise: 1. Breadboard, 2. Switch, 3. Arduino Uno

在 Arduino IDE 中创建一个新的草图,我称之为我的 chapter_01_2,并复制清单 1-3 中的代码。验证并将代码上传到 Arduino。当您按下按钮时,Arduino 上的 LED 应该会亮起。

int buttonInput = 2;
int LEDOutput = 13;

void setup() {
pinMode(buttonInput, INPUT_PULLUP);
  pinMode(LEDOutput, OUTPUT);
}

void loop() {
  int sensorVal = digitalRead(buttonInput);
  if (sensorVal == HIGH) {
     digitalWrite(13, LOW);
  } else {
     digitalWrite(13, HIGH);
  }
}

Listing 1-3
chapter_01_2.ino

代码解释表 1-3 更详细地解释了 chapter_01_2.ino 的代码。

表 1-3

chapter_01_2.ino explained

| `pinMode(buttonInput, INPUT_PULLUP);` | 您需要使用 INPUT_PULLUP 作为按钮开关的 pinMode()函数中的第二个参数。 | | `int sensorVal = digitalRead(buttonInput);` | 开关的值被读入每个循环的变量中。 | | `if (sensorVal == HIGH) {``digitalWrite(LEDOutput, LOW);``} else {``digitalWrite(LEDOutput, HIGH);` | if/else 语句检查开关是高还是低。使用上拉意味着按钮的逻辑是相反的。如果它很高,这意味着它是上升的,所以 LED 是关闭的。当它是低电平时,它被按下,从而打开 LED。 |

模拟输入

模拟输入与光敏电阻和电位计等元件一起使用,这些元件提供不同的值。Arduino Uno 可以记录 0 到 5 伏之间的值;这样你可以得到一个介于 0 和 1023 之间的模拟输入值。模拟输入发送信号电压。当接收到信号电压时,会根据内部参考进行检查。图 1-16 中显示了一个示例。

A453258_1_En_1_Fig16_HTML.png

图 1-16

An illustration of the analog input process

当接收到一个信号电压时,在线路上的多个点相对于内部基准电压进行测试。例如,它检查输入是否大于 0;如果不是,它检查它是否大于引用中的下一个数字,并一直检查直到它是。该点成为输入数字。

Analog Input

本练习使用电位计作为模拟输入。当电位计转到一半时,它会打开和关闭 Arduino 上的 LED。

本练习所需的组件如下:

  • 1 x 火神一号
  • 1 个电位计

图 1-17 显示了组件,图 1-18 显示了 Arduino 的设置。

A453258_1_En_1_Fig18_HTML.jpg

图 1-18

Setup for the components for the analog input exercise

A453258_1_En_1_Fig17_HTML.jpg

图 1-17

Components for the analog input exercise: 1. Breadboard, 2. Potentiometer, 3. Arduino Uno

打开新草图。我叫它 chapter _ 01 _ 3;然后复制清单 1-4 中的代码。

int pinAnalogInput  =  A0;
int LEDOutput = 13;
int valueLight =  0;

void setup() {
  pinMode(LEDOutput, OUTPUT);
}

void loop() {
  valueLight =  analogRead(pinAnalogInput);
  if (valueLight < 500) {
    digitalWrite(LEDOutput, LOW);
  } else {
    digitalWrite(LEDOutput, HIGH);
  }
  delay(500);
}

Listing 1-4chapter_01_3.ino

验证草图并将 USB 插回电脑,将草图上传到 Arduino。现在,当您将电位计转到一半时,Arduino 上的 LED 应该会忽明忽暗。

代码与本章前面的草图非常相似。主要区别在于模拟引脚 int pinAnalogInput = A0 的变量;模拟输入通过引脚 A0;

摘要

本章是对 Arduino 的基本介绍。它着眼于电路如何工作,以及模拟和数字输入和输出。这些是 Arduino 的基本模块,将在整本书中构建。下一章将带您开始学习 JavaScript,并构建一个能够接收 Arduino 发送的数据的 web 服务器。

二、创建 Web 服务器

要开始将 Arduino 连接到 web,对 Web 技术有一个基本的了解是很有用的。本章将介绍一些原理,包括什么是 web 服务器,URL 是如何构造的,什么是路由,什么是 Node.js。然后它将变得实用,您将学习如何用 Node.js 创建一个 web 服务器,并从服务器向网页来回发送数据。它将涵盖 Node.js、ejs 和 socket.io。

什么是 Web 服务器?

web 服务器向 web 浏览器提供页面;它还处理信息并存储页面的数据和素材。它允许使用超文本传输协议(HTTP)处理请求。此协议允许网络使用称为统一资源定位符(URL)的地址(指向您的网页的地址)相互通信。URL 有一个定义好的结构,以协议开头,后面是域名、域扩展名以及可选的文件和文件夹名;见图 2-1 。

A453258_1_En_2_Fig1_HTML.jpg

图 2-1

URL structure

域名是互联网协议(IP)地址的自然英语翻译。IP 地址是一系列数字,任何连接到互联网的东西都有一个 IP 地址。这包括智能手机和智能电视;任何连接到互联网的设备都会有一个 IP 地址。

当互联网上的计算机相互通信时,它们使用它们的 IP 地址。当你在浏览器中输入网址时,它会被转换成 IP 地址。这将告诉 web 服务器您想要的页面的地址。这是到那个页面的路径。如果服务器找到这个页面,它会把它返回给你的浏览器。如果不能,它将返回一个错误页面。

Web 服务器有许多惯例来连接网络上的一台计算机并向另一台计算机传输数据。其中之一就是代表性状态转移,也就是 RESTful。它使计算机系统具有互操作性;这意味着,无论服务器如何设置,如果它实现了 RESTful web 服务,它就可以与任何其他也实现它们的服务器对话。当 HTTP 使用 RESTful 时,可以使用 GET、POST、PUT 和 DELETE 请求。例如,POST 允许您在网页上填写表单,并将其发送到浏览器。

您可以在自己的计算机上创建 web 服务器,使用 Node.js 就是一种方法。这意味着您可以在本地机器上开发应用程序,并在部署之前进行测试。本地 web 服务器使用域名 localhost,该域名解析为 IP 地址 127.0.0.1。

选择途径

如果没有路由,您将无法查看网页。路由决定了 web 服务器如何响应来自 web 浏览器的 URL 请求。回到 example.com,当有人输入 URL 时,服务器必须知道服务哪个页面。如果您添加到其他网页,如 example.com/about,将必须有一个在服务器上为这个网页的路线。路由还告诉服务器应该如何响应请求。它使用 RESTful 命令做到这一点;如果一个路由以 GET 开始,服务器知道它需要获取页面的内容。如果它以 POST 开始,服务器知道它将从网页接收数据,并且路由将定义下一步应该做什么。

Node.js 是什么?

Node.js 是用于执行 JavaScript 服务器代码的运行时环境。这意味着你可以在浏览器和服务器上使用同一种语言,JavaScript。使用 Node.js,您可以创建到网页的路由、连接到本地主机、连接到数据库,以及用 JavaScript 向网页发送数据。它允许你使用相同的语言构建 web 应用程序。

Node.js 与 Arduinos 配合得非常好。使用串行端口,您可以使用服务器将数据从 Arduino 传递到网页,并将数据从网页传递到 Arduino。

除了下载 Node.js 之外,您还需要下载其他软件包,以便更简单地创建您想要的应用程序。您可以使用包管理器来完成这项工作;有几个不同的,但本书使用的是节点包管理器(npm)。

使用命令行界面

命令行界面是一种使用文本向计算机发送指令的方式。你可以用它做很多事情,包括移动你的电脑目录,创建新文件和运行代码。

要使用 Node.js,您需要使用命令行界面。您可以使用它来安装新模块、启动服务器,以及查看来自应用程序的消息和错误。

Windows 和 Mac 都有内置的命令行界面应用程序。在 Windows 中它被称为命令提示符或 cmd.exe,在 Mac 中它被称为终端。两者都将打开一个控制台窗口,用于输入命令。

这是一个非常强大的工具,需要谨慎使用,因为你可以清除你的系统或做出难以撤销的更改。

命令行界面在所谓的命令行 shell 中实现。shell 是一个程序,它接受文本命令并将它们翻译成操作系统能够理解的语言。

当您打开控制台窗口时,它应该显示登录用户的主目录。这是该用户的顶层目录,您可以从中导航到该用户的文件和文件夹。

Using The Mac Terminal

Mac 终端应用程序位于应用程序文件夹内的“实用工具”文件夹中。它的路径如下:

硬盘驱动器/应用程序/实用程序/终端

当应用程序打开时,您应该会看到一个控制台窗口,显示您的主目录,后跟\(:例如:~ <username>\)

尝试以下命令并查看表 2-1 中您可能会发现有用的其他命令:

表 2-1

Some useful terminal Commands

| 命令 | 结果 | | :-- | :-- | | 显示当前工作目录 | 写入当前目录的完整路径 | | 限位开关(Limit Switch) | 列出目录的内容 | | cd | 下一级目录的路径 | | cd / | 2 层以下目录的路径 | | 激光唱片.. | 上移一个目录 | | 激光唱片 | 移回主目录 | | mkdir〔??〕 | 将在当前目录下创建一个新目录 | | 触摸 | 将使用该名称和扩展名创建一个新文件 |
  1. 打开终端,一个新的控制台窗口将会打开。
  2. 键入 ls + return,您将看到当前目录下所有文件和文件夹的列表。
  3. 键入 cd + return,您将进入该目录。
  4. 使用 ls 列出文件和目录,然后键入 cd 和目录名以移动到另一个目录。
  5. cd 标牌..+ return,您将在目录中上移一个文件夹。
  6. 键入 cd + return,您将移动到您的主目录。
  7. 键入 Ctrl + l 或 Cmd+k,这两个键都会清除控制台屏幕。Crtl+l 只是清空屏幕,Cmd+k 也是清空终端缓冲区。

Using The Windows Command Prompt

windows 控制台被称为命令提示符或 cmd.exe。有多种方法可以打开命令提示符控制台窗口,这些方法会根据您运行的 windows 版本而变化(参见表 2-2 )。您可以使用 Windows 搜索来查找命令提示符;搜索的是 Windows 10 上的 Cortana。开始在搜索栏中键入“命令提示符”;最匹配的应该是桌面应用“命令提示符”单击“命令提示符”打开控制台窗口。

当应用程序打开时,您应该会看到一个控制台窗口,显示您的主目录,后面跟着一个>应该是这样的:C:\Users\Username >,您开始在>后面键入。

尝试几个命令:

  1. 打开命令提示符,将会打开一个新的控制台窗口。
  2. 键入 dir + enter,您应该会看到当前目录中的所有文件和文件夹。
  3. 键入 cd + enter,你将进入那个文件夹。
  4. 使用 ls 列出文件和目录,使用 cd 移动到另一个目录。
  5. cd 标牌..+ enter,您将在目录中上移一个文件夹。
  6. 键入 cd %userprofile% + enter 返回主目录。
  7. 键入 cls + enter,控制台屏幕将被清除。

命令中可以有可选参数。如果您使用 dir 命令,您将看到目录中每个文件或文件夹的大量信息。如果您只想查看姓名,您可以键入 dir /b。

表 2-2

Some useful command prompt commands

| 命令 | 结果 | | :-- | :-- | | `echo %cd%` | 写入当前目录 dir 的完整路径 | | `cd ` | 当前目录下一级目录的路径 | | `cd /` | 当前目录下第二层目录的路径 | | `cd ..` | 上移一个目录 | | `cd` | 移回主目录 | | `mkdir ` | 将在当前目录下创建一个新目录 | | `NUL> ` | 将使用该名称和扩展名创建一个新文件 |

注意:如果您开始在控制台窗口中输入一个目录名,然后按 tab 键,目录名的其余部分将会自动填写,只要它是唯一包含这些字母的目录。

要向后或向前移动到上一个命令,请使用键盘上的上下箭头。

Mac 控制台区分大小写。Mac 控制台对空白敏感。

设置 Node.js 服务器

现在背景已经覆盖了,是时候开始编码了。如果您的计算机上没有安装 Node.js,您需要将它与节点包管理器一起安装。根据你已经在电脑上安装了什么,这可能需要一些时间,但一旦完成,进一步下载会快得多。

安装 Node.js

首先,如果您不确定您的计算机上是否安装了 Node.js,您可以在控制台窗口中检查。

Check If Node.js Is Installed

  1. 打开控制台窗口。
  2. 在控制台提示符下键入 node -v,如果安装了 Node.js,您应该会看到您的版本号(例如,v6.10.3)。
  3. 在控制台提示符下键入 npm -v,如果安装了 npm,您应该会看到版本号(例如,3.10.10)。

如果您看到版本号,请跳过安装 Node.js 的下一步,直接进入“创建应用程序”一节。

Install Node.js On Windows

在 Windows 中,您可以直接从 Node.js 网站安装 Node.js。

  1. 前往 https://nodejs.org/en/
  2. 下载 Windows 版本(x64)。为了这本书,我下载了 v6.10.3.LTS。msi)。
  3. 运行安装程序;为此:
    1. 双击下载的文件;它应该位于您的下载文件夹中,名称类似于 node-v6.10.3.x64。
    2. 安装程序窗口应该出现“按下运行按钮,这将打开 Node.js 安装向导,然后按下一步按钮。
    3. 将出现许可协议,您需要同意安装 Node.js 的许可。如果同意,请选中复选框并按下一步按钮。
    4. 您可以通过按下 next 按钮接受默认设置,直到您看到 finish 按钮,默认设置会将 Node.js 安装到一个默认目录。
    5. 按“完成”按钮完成安装。
  4. 出现提示时,让应用程序对您的设备进行更改。
  5. 重新启动计算机。
  6. 按照上面“检查是否安装了 Node.js”一节中的说明,检查 node.js 和 npm 是否已安装。

Install Node.js On a Mac

在 Mac 上,有多种方法可以安装 Node.js。最简单的方法是从 Node.js 网站下载应用程序。虽然这是最简单的方法,但它也有缺点。它安装 Node.js 的方式意味着您可能需要管理员权限来安装补充模块和库。您可以在 install 命令之前使用 sudo 命令安装这些模块和库。sudo 命令为您提供了该安装的管理员权限。sudo 代表超级用户 do,用于 UNIX 风格的操作系统。这允许您以管理员用户的身份安装软件包。

使用 sudo 并不是最佳实践,因为拥有管理员权限意味着您可以对您的计算机进行不必要的更改。使用 sudo 还会影响一些模块的工作方式。

另一种安装 Node.js 的方法是使用节点版本管理器(NVM);它安装它,所以你不需要管理员权限来安装其他模块和库。安装起来稍微困难一些,因为你需要安装 Xcode,还需要一个. bashprofile 文件。还有一个好处:可以很容易地在 Node.js 的不同版本之间进行切换。

从 Node.js 网站安装 Node.js

如果以这种方式安装 Node.js,当您为应用程序安装新模块时可能会出现错误,并且它们不会下载。如果发生这种情况,您需要以管理员权限重新安装该模块。为此,您可以在 install 命令前键入 sudo。然后会提示您输入密码。

  1. 前往 https://nodejs.org/en/
  2. 下载 macOS 版本(x64);为了这本书,我下载了 v6.10.3.LTS。pkg)。
  3. 运行安装程序并遵循它的请求,让它安装在默认目录下。
  4. 让应用程序对您的设备进行更改。
  5. 重新启动计算机。
  6. 检查 Node.js 和 npm 是否已安装。

使用节点版本管理器(NVM)安装 Node.js

要安装 NVM,您需要在 Mac 上安装 Xcode 和. bashprofile。

如果没有安装 Xcode,从 app store 安装;这可能需要几个小时。

  1. 打开一个终端窗口,确保你是在根目录~ $如果不是在提示符下键入 cd。
  2. 请检查您是否有. bashprofile 文件。在$提示符下,键入 open -a TextEdit.app。bash_profile,如果您有一个. bashprofile,它将打开,或者您可以关闭该文件。
  3. 如果在提示符下没有. bash_profile,请键入 touch。bash_profile。
  4. 要在控制台提示符下安装 NVM,请键入:curl https://raw.githubusercontent.com/creationix/nvm/v0.25.0/install.sh | bash。
  5. 要安装 Node.js 的最新稳定版本,请在提示符下键入 nvm install stable。
  6. 在提示符下,键入 nvm 使用节点。
  7. 在 Node.js 上安装本书中使用的版本,在提示符下键入 nvm install 6.11.0。
  8. 打开控制台窗口时,将 6.11.0 版设为默认版本。在提示符下,键入 nvm 别名默认值 6.11.0。
  9. 开始使用这个版本的 Node.js,并在提示符下键入 nvm use 6.11.0。
  10. 可以看到已经安装的 Node.js 的版本:type nvm ls。
  11. 检查 Node.js 和 npm 是否已安装。

你可以在 github 页面github . com/creation IX/nvm找到更多关于 nvm 以及如何使用它的信息。

创建 Node.js 应用程序

到本章结束时,你将已经构建了一个使用 socket.io 从服务器向连接的浏览器发送更新的小应用程序。您将通过一系列的步骤来完成这一过程,包括创建 web 服务器、创建到 web 页面的路由、web 页面的一些基本样式,以及将数据从服务器发送到浏览器。您将以两种不同的方式从服务器发送数据:首先通过 route 函数发送到网页,然后使用 web 套接字。

要编写和编辑代码,你需要一个专门的文本编辑器。这可以是源代码编辑器或集成开发环境(IDE)。它们很容易下载和安装。有许多可用的代码,如 Sublime Text、Atom 和 Visual Studio 代码。

您需要做的第一件事是为应用程序创建目录。我调用了我的 chapter_02,所以这将是应用程序的名称。

Create The Application Directory

  1. 打开控制台窗口。
  2. 在终端键入 cd / / ,移动到你想要存储项目的目录。
  3. 在终端类型 mkdir 中为项目创建一个新文件夹。
  4. 移入新目录,在终端键入 cd

目录结构

当你创建一个 web 应用程序时,你需要一个目录结构。应用程序的主文件夹将是应用程序的根目录。与应用程序相关的所有其他文件和文件夹都应该在该文件夹中。组成应用程序的文件将引用此结构中的文件和文件夹。您将创建其中的一些文件和文件夹,其他文件和文件夹将在初始设置或下载模块时自动创建。

图 2-2 显示了本章的目录结构。package.json 文件将在安装时创建,节点模块文件夹将在您下载新模块时自动创建。“/”字符代表应用程序的根。

A453258_1_En_2_Fig2_HTML.jpg

图 2-2

The directory structure for the application Using NPM Init To Create An Application

npm 代表节点程序包管理器。它承载了成千上万的可重用代码包,您可以下载并在项目中使用。

npm 还有一个名为 npm init 的命令,这是一种创建 Node.js 应用程序的有用方法。它将询问一系列问题,然后创建一个 package.json 文件。您可以随时按 Ctrl+C 退出该过程。

使用 npm 很容易创建 Node.js 服务器的框架:

  1. 打开控制台窗口。
  2. 导航到您将用于应用程序的文件夹。
  3. 在控制台提示符下,键入 npm init+enter。
  4. 更改默认答案或按 enter 键接受它们。保持默认入口点为 index.js。
  5. 在代码编辑器中打开项目文件夹。打开应用程序的根文件夹,因为您希望能够看到连接到项目的所有文件和文件夹。此时,您应该会看到一个文件 package.json。

图 2-3 显示了一个 package.json 文件的例子。

package.json 是一个重要的文件,它保存应用程序的元数据,并用于处理应用程序的依赖关系。当您开始安装库时,package.json 文件中会有对它们的引用。如果您共享您的应用程序文件,您不会包括所有的库文件。因为 package.json 有对它们的引用,所以可以使用 npm install 在复制的位置安装它们。

A453258_1_En_2_Fig3_HTML.jpg

图 2-3

An example of a package.json file

请注意,名称必须是小写字母,没有空格,但您可以使用下划线和破折号。

Create A Node.js Server

在 Node.js 中,创建一个启动服务器的 JavaScript 文件。它存储在项目的根目录中,并将成为应用程序的入口点。这个文件通常被称为 app.js 或 index.js。当我使用 npm init 创建 package.json 时,我保留了 index.js 条目脚本的默认值,因此现在需要创建 index.js 文件。

在应用程序的根目录下创建一个名为 index.js 的新文件。确保您位于与 package.json 相同级别的应用程序目录中。

在新创建的 index.js 文件中,写入清单 2-1 中的以下代码。

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);
server.listen(3000, function() {
  console.log('Listening on port 3000...');
});
Listing 2-1
index.js code

清单 2-1 显示了使用 Express.js 设置 web 服务器的基本代码。Express.js 不是 Node.js 库的一部分,所以必须马上安装,但首先我将解释表 2-3 中的代码。

代码解释

服务器所需的模块(如 Express.js)被加载到页面顶部,并分配给变量。JavaScript 使用 var 关键字创建变量。

表 2-3

index.js code explained

| `var http = require('http');` | 这一行将 HTTP 接口引入应用程序;这允许服务器通过 HTTP 协议与浏览器通信。 | | :-- | :-- | | `var express = require('express');` | 这包括我们将用来创建服务器和路由的 express 框架。Express 附带了许多功能,使设置节点服务器变得更加容易。它不是 Node.js 库的一部分,因此需要安装。 | | `var app = express();` | 调用 express 应用程序,返回值放在一个变量中。这包含一个新的 express 应用程序。 | | `var server = http.createServer(app);` | 这将创建一个服务器对象,在发出服务器请求时调用该对象。 | | `server.listen(3000, function() {` `});` | 这告诉服务器在端口 3000 上监听对服务器的请求。 | | `console.log('Listening on port 3000...');` | console.log 是一个将消息输出到控制台的 JavaScript 函数。这里用它来告诉你服务器正在运行。 |

Using NPM To Install Libraries

此时,如果运行这段代码,就会出现错误。它使用一个名为 Express.js 的外部库,该库不属于 node . js。express . js 使得创建 web 服务器变得容易得多。需要下载它,并在 package.json 中保存对它的引用。

  1. 打开一个控制台窗口,并确保您与 package.json 文件位于同一目录中。
  2. 在命令行中键入 NPM install express @ 4 . 15 . 3-save+enter。
  3. 下载完成后,启动服务器。在控制台中,确保您位于应用程序的根目录,与 index.js 处于同一级别。

如果您在 Mac 上安装 Express.js 时遇到错误,可能是因为您需要管理员权限来安装它。尝试再次安装,这次键入 sudo NPM install express @ 4 . 15 . 3-save,然后在密码提示符下键入计算机的密码。

在控制台中,您现在应该看到监听端口 3000 的控制台日志。

如果您使用的是 Windows,您可能会看到一条安全警报,提示 Windows 防火墙已阻止此应用的某些功能。勾选表示私有网络的方框,如我的家庭或工作网络。

如果您打开 web 浏览器并键入 localhost:3000,您应该会看到:无法获取/

这是因为还没有路由,所以服务器不知道将哪个页面提供给浏览器。您将在一分钟内创建路线。

如果您查看您的应用程序目录,您会看到有一个名为节点模块的新文件夹。这是第一次在应用程序中安装新库时创建的。如果你往里面看,你会看到 Express.js 的文件和文件夹都在里面。

注意使用- save 在 package.json 文件中保存对下载模块的引用。

在本书中,我将使用@来安装新模块。这意味着你将安装我一直在使用的相同版本。没有@它将安装最新的模块。

Creating a Route To a Web Page

使用清单 2-1 中的代码,创建一个将一些文本发送到网页的简单路由,将以下粗体命令添加到您的文件中,这些命令在表 2-4 中有进一步的描述:

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);

app.get('/', function (req, res) {

  res.send("Hi There!");

});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

代码解释

现在,如果您重新启动服务器,您应该会在网页上看到文本 Hi。

表 2-4

index.js code explained

| `app.get('/', function (req, res) {``res.send('Hi There!');` | 函数 app.get 创建一个到应用程序根目录的路径。/'表示根,它将是主 URL,或者在本例中是 localhost:3000。如果您想将消息发送到不同的网页,例如,发送到 about 页面,您可以使用 app.get('/about ',function (req,res)。 |
  1. 键入 Ctlr+c 停止服务器。
  2. 在终端中再次键入 node index.js 来重启服务器。
  3. 刷新 web 浏览器。

添加第二个应用程序。转到第一个应用程序下面。转到清单 2-1 中的代码。

app.get('/about', function (req, res) {
  res.send("this is an about page");
});

现在您需要重新启动服务器,以便它选择新的路由:

  1. 按 Ctlr+c 停止服务器。
  2. 在终端中再次键入 node index.js 来重启服务器。
  3. 刷新 web 浏览器并转到 localhost:3000/about。

现在,您应该会在网页上看到“这是一个关于页面”的字样。您可以删除关于路线。

NodeMon(节点名)

每次对服务器进行更改时,您都必须停止并重新启动服务器,以使更改生效。有一个很有用的库叫做 nodemon,它会注意到你对它正在监视的文件的修改,并为你重启服务器。在控制台窗口中使用它很容易安装。它应该全局安装,以便所有 Node.js 应用程序都可以访问它。

Installing Nodemon

  1. 打开一个控制台窗口,并确保您在主目录;您可以在 Mac 上通过键入 cd 转到主目录,在 Windows pc 上通过键入 cd %userprofile%转到主目录
  2. 在提示符下键入 npm install nodemon -g (-g 全局安装)。
  3. 在控制台中,导航到 chapter_02 应用程序的根目录,使用 cd 命令执行此操作,例如 cd Documents/code/chapter_02
  4. 当您在控制台中位于 Node.js 应用程序的根目录时,通过键入 nodemon 并按 enter 键启动服务器。

现在,如果您对 index.js 文件进行了更改,您可以刷新浏览器并查看更新。Nodemon 自动启动 package.json 中列出的主 JavaScript 文件。

您不需要将它保存到 package.json,因为它不是您的应用程序的一部分;它是开发应用程序时的助手。

创建网页

到目前为止,您已经将数据发送到 web 浏览器,但它只是从路由器打印出一条消息。现在你需要创建一个网页。通常网页是在带有。html 扩展。这些是静态网页。因为您将使用来自服务器的数据更新页面,所以需要创建一个可以接受这些数据的动态页面。

一种方法是为。html 页面向服务器发出 AJAX 请求,然后服务器返回一些数据。这依赖于浏览器页面向服务器请求数据。

另一种更有效的方法是让服务器用它拥有的数据更新网页。在 Node.js 中,这是通过模板引擎完成的。

模板引擎

模板引擎允许您在整个网页中创建变量,服务器可以更新这些变量,而无需网页发出请求。在本书的后面,我们将把数据从 Arduino 传递到服务器。由于网页将使用模板引擎创建,因此该页面将使用新数据自动更新。

有许多不同的模板引擎可以使用,其中一些我已经在附录 b 中列出了。

Set Up The Server

要使用 ejs,需要将一些代码添加到 index.js 文件中,但是首先要将 ejs 添加到项目中:

  1. 打开控制台窗口并导航到应用程序目录的根目录,或者导航到应用程序目录的根目录。或者,如果服务器在应用程序的根目录下运行,请按 Ctlr + c 停止它。
  2. 在应用程序根目录下的控制台提示符处,键入 npm install ejs@2.5.6 - save + enter。

现在,您应该能够在 package.json 文件中看到 ejs 了。在项目中包含 ejs 只是一行代码。用粗体代码行更新 index.js 文件(清单 2-1 ):

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);

app.set('view engine', 'ejs');

app.get('/', function (req, res) {
  res.send('Hi There!')
});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

这一行新代码将允许您在项目中使用 ejs。

到目前为止,你已经在 route 中使用了 res.send。在 route 中使用 res.send 允许你发送简单的数据到一个网页,但是对于大多数应用程序来说,你希望能够发送包含更多信息的页面。为此,您可以使用函数 res.render 这允许您指定将在浏览器中呈现的文件,并向其发送新数据。

将 index.js 文件从代码(清单 2-1 )更改为粗体代码;这添加了几个变量并更改了路由,因此它使用 res.render 而不是 res.send:

....

app.set('view engine', 'ejs');

var title = "Some Arduino components starting with p"

var componentArray = ['potentiometer', 'piezo', 'phototransistor', 'pushbutton'];

app.get('/', function (req, res) {

    res.render('index', {
                title: title,
                components: componentArray
    });

});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

代码解释

新代码从两个变量开始,这两个变量保存要传递给浏览器的数据(见表 2-5 )。

  1. 在应用程序路由处启动服务器。确保您与 index.js 文件位于同一个文件夹中。在控制台提示符下,键入 nodemon。
  2. 刷新您的网页,您应该会看到一个错误。

表 2-5

index.js code explained

| `var title = "Some Arduino components starting with p"` | title 变量保存一些文本。在 JavaScript 中,字符串被" "或" "包围。 | | :-- | :-- | | `var componentArray = ['potentiometer', 'piezo', 'phototransistor', 'pushbutton'];` | 在 JavaScript 中,[ ]用于创建数组。数组是数据的集合,可以通过其在数组中的索引(位置)来访问。componentArray 是一个由四个都是字符串的元素组成的数组。JavaScript 数组中的索引从 0 开始。要访问数组的第一个元素,可以使用 componentArray[0],这将返回字符串电位计。componentArray[3]将返回字符串按钮。 | | `res.render('index', {``title: title,``components: componentArray` | 现在不是呈现一个字符串,而是告诉 Node.js 你想要呈现哪个页面。在这种情况下,它是 index.js 文件。然后列出要传递给页面的数据,在本例中是 title 和 componentArray。 |

您应该会在页面和控制台窗口中看到如下所示的错误:

错误:无法在视图目录“/Users/indie/Documents/web/book/chapter 2/03 _ set-up-ejs/views”中查找视图“索引”

这是因为现在你要求它找到一个不存在的索引页。

Set Up The Web Page

ejs 页面看起来与 html 页面相似,只是它使用了。您可以将来自服务器的 ejs 页面数据作为变量传递。在页面上,您仍然使用相同的 html 标记,但是您也可以使用 ejs 语法。用 ejs 创建的页面需要放在一个名为 views 的文件夹中。

  1. 在应用程序的根目录下,创建一个名为 views 的新文件夹。
  2. 在 views 文件夹中创建一个名为 index.ejs 的新文件。要在控制台窗口中执行此操作,请执行以下操作:
    1. 在应用程序类型 cd 视图的根
    2. 在 Mac 上键入 touch index.ejs
    3. 我们有 Windows pc 类型 nul > index。例如

在 Windows 中,您可能会得到拒绝访问的控制台响应,但文件应该已经创建。

在新创建的 index.ejs 文件中,写入清单 2-2 中的代码。

<!DOCTYPE html>
<html>
<head>
    <title>an ejs page</title>
</head>
<body>
    <h1>EJS</h1>
    <p>This page is an ejs page and will show data from the server</p>
</body>
</html>
Listing 2-2index.ejs code

在控制台窗口中,确保您位于项目的根目录,并重新启动服务器。在浏览器上,转到 http://localhost:3000/现在,您应该可以在网页上看到文本。您用一些简单的 HTML 创建了这个页面。HTML 代表超文本标记语言,是用于创建网页的通用标记语言。我将在第四章中更详细地介绍 HTML。它列出了页面的结构和其中的元素。

Adding Data To The Web Page

服务器已经将来自 res.render 的数据传递给了浏览器。它传递了一个名为 title 的字符串,其中包含文本“一些以 P 开头的 Arduino 组件”和一个名为 components 的数组,其中包含['potentiometer ',' piezo ',' photo tomy ',' pushbutton']。使用 ejs,浏览器现在可以访问这些数据。

用粗体文本更新清单 2-2 中的 index.ejs:

<!DOCTYPE html>
<head>
    <title>an ejs page</title>
</head>
<body>
    <h1>EJS</h1>
    <p>This page is an ejs page and will show data from the server</p>

    <h2><%= title %></h2>
    <% components.forEach(function(component) { %>
        <p>component: <%= component %> </p>
    <% }); %>

</body>
</html>

代码解释

,或者是 ejs 库的一部分。

在你写 JavaScript 的时候使用标签,它会在标签里面运行 JavaScript,文本不会出现在页面上。通常,当你想在网页上添加 JavaScript 时,你必须将它封装在脚本标签中,稍后你会用到。EJS 有自己版本的脚本标签,当您编写代码来访问从服务器传来的数据时,可以使用它。

当标签被使用时,它们里面的内容就会出现在页面上。在标签内部,您可以引用从服务器传递到浏览器的变量,并在网页上看到它。参见表 2-6 。

表 2-6

index.ejs code explained

| `

<%= title %>

` | 标题是从服务器传递的数据的一部分。如你想看标题你用。您可以将 EJS 包装在任何您喜欢的 HTML 标签中。在这种情况下,ejs 被包装在一个 H2 标签中。 | | :-- | :-- | | 组件: | 它使用一个 JavaScript forEach 函数来迭代从服务器传来的数组数据,并写出数组的每个元素。 |

Adding CSS

CSS 代表级联样式表,它用于设计网页上的元素。一个没有 CSS 的网页看起来很基础。虽然 CSS 可以添加到。最佳实践是创建一个单独的。保存样式的 CSS 文件。然后,您需要一个到。中的 css 文件。ejs 页面。

在 web 应用程序中,有一些称为静态文件的文件,它们不是由服务器创建的,而是在网页上使用的。这些文件包括 CSS 文件、图像和 JavaScript 文件。要在. ejs 文件中使用它们,您需要知道从静态文件到。ejs 文件。Express.js 有一个名为 express.static 的中间件函数来帮助解决这个问题。您在应用程序的根目录下创建一个文件夹来保存所有静态文件;该文件夹通常称为公共文件夹。在 index.js 文件中,express.static 函数用于注册公共文件夹。这意味着。ejs 将这个文件夹识别为静态文件的根文件夹,您不必将的绝对路径写到。当你调用 css 文件时。你会写出这样的东西:<link href="/css/main.css" rel="stylesheet" type="text/css">

要将 CSS 添加到页面中,首先创建一个静态文件夹。

  1. 在应用程序的根目录下,创建一个名为 public 的新文件夹。
  2. 在这个文件夹中创建另一个名为 css 的文件夹。
  3. 在 css 文件夹中创建一个名为 main.css 的文件。
  4. 用下面的更新代码更新 index.js 文件,使其包含静态函数。

现在用粗体代码更新清单 2-1 中的 index.js 文件:

...

app.set('view engine', 'ejs');

app.use(express.static(__dirname + '/public'));

var title = "Some Arduino components starting with P"
var componentArray = ['potentiometer', 'piezo', 'phototransistor', 'pushbutton'];

...
server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

代码解释

注册静态文件文件夹需要一行代码(表 2-7 )。

表 2-7

index.js code explained

| `app.use(express.static(__dirname + '/public'));` | 这告诉应用程序所有的静态文件都将从一个名为 public 的文件夹中提供。 |

现在打开您刚刚创建的 main.css 文件并添加到 css 中(清单 2-3 ):

*{
    margin: 0;
    padding:0;
}
body{
    background-color: #F2F3F4;
    font-family: Verdana, Arial, Helvetica, sans-serif;
}

h1, h2, p{
    padding: 10px;
}

h1{
    background-color: #4ABCAC;
    color: white;
}

#components{
    margin: 10px;
    border: #F78733 solid 2px;
    display: inline-block;
}

Listing 2-3main.css

您还需要更新 index.ejs 文件,告诉它在哪里可以找到 CSS 文件。用粗体 HTML 更新 index.ejs 文件(清单 2-2 ):

<!DOCTYPE html>
<head>
    <title>an ejs page</title>
    <link href="/css/main.css" rel="stylesheet" type="text/css">
</head>
<body>
    <h1>EJS</h1>
    <p>This page is an ejs page and will show data from the server</p>
    <h2><%= title %></h2>
    <div id="components">
        <% components.forEach(function(component) { %>
            <p>component: <%= component %> </p>
        <% }); %>
    </div>
</body>
</html>

因此,在服务器运行的情况下,刷新您的网页,您现在应该会看到新的样式;它使用 HTML 标签和一个 id 来设置内容的样式。

package.json 和版本控制

现在,您已经为您的应用程序安装了几个包,是时候再看一下 package.json 文件了。它保存了关于应用程序的信息,包括您安装的依赖项(模块)的名称及其版本号。

这些依赖关系由不同的人编写,并且在不同的时间更新。这些更新可能会破坏您的代码。语义版本控制用于跟踪变更。这意味着版本号的每个数字都有特定的含义。如图 2-4 所示,版本号由三个数字组成,用句号分隔。每个新版本的数字都会增加,每个数字代表一种不同的更新。

A453258_1_En_2_Fig4_HTML.jpg

图 2-4

Version control numbers

在 package.json 文件中,您可以看到依赖关系。

{
  "name": "set-up-routes",
  "version": "1.0.0",
  "description": "setting up simple routes",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Indira",
  "license": "ISC",
  "dependencies": {
    "ejs": "².5.6",
    "express": "⁴.15.3"
  }
}

每个安装的模块旁边是它的版本号。您可能还会看到一个符号,如*或~。当您从 package.json 运行 npm install 时,这些符号为可以下载的版本提供了一些灵活性。

=或 v 这确保安装了完全相同版本的软件包。例如,v2.5.6 将确保下载软件包的版本 2.5.6。

~这修复了主要版本和次要版本,但允许更高的修补版本。例如,2.5.6 将确保安装的版本高于或等于 2.5.6,但低于 2.6.0。

^这修复了主要版本号,但允许不同的次要或修补版本。例如,².5.6 将确保已安装的版本可以大于或等于 2.5.6 且小于 3.0.0。

这是一个通配符,表示可以安装任何版本。比如 2。表示可以安装任何以 2 开头的版本。

Setting Up a WebSocket With Socket.io

现在回到创建应用程序。此时,服务器在加载时传递网页数据。如果数据更新,网页将不会反映这种变化。您可以编写一个脚本,定期 pinged 服务器以查看是否有变化,但这不是很有效;如果没有新数据,您将会浪费调用,并且当新数据到达时,页面将不得不等到下一次调用来更新。

WebSocket 协议解决了这个问题:新数据将直接发送到网页,网页可以将数据发送回服务器,以更新连接到服务器的其他浏览器。这本书将使用 socket.io 库进行 web 套接字调用。

首先,socket.io 需要安装为 socket.io 不随 Node.js 一起安装。

  1. 打开控制台窗口,导航到应用程序的根目录。
  2. 在提示符下键入 NPM install socket . io @ 1 . 7 . 3–save。

现在,您可以将 socket.io 包含到 index.js 文件中。Index.js 将不再使用变量 title 和 componentArray 向浏览器发送数据,因此可以删除它们。app.get 函数也被更新,因此变量不再被发送到 index.ejs。更新 index.js 文件,使其与清单 2-4 中的代码匹配,新代码以粗体显示:

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);

var io = require('socket.io')(server);

app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));

app.get('/', function (req, res) {

  res.render('index')

});

io.on('connection', function(socket){

    console.log('Connection to client established');
    socket.on('disconnect',function(){
        console.log('Server has disconnected');
    });

});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

Listing 2-4index.js updated

代码解释

Socket.io 改变了数据传递给浏览器的方式;它不再在路由中发送,而是通过套接字发送(表 2-8 )。

表 2-8

index.js updated code explained

| `var io = require('socket.io')(server);` | 这段代码包含 socket.io 并将服务器附加到它上面。 | | :-- | :-- | | `app.get('/', function (req, res) {``res.render('index')` | 这将创建一个从服务器到 URL 根目录下的 index.ejs 页面的路由。这一次,您没有通过路由发送数据。 | | `io.on('connection', function(socket){` `console.log('Connection to client established');` | 当网页连接到服务器时,io.on 函数将告诉套接字做什么。每次浏览器连接到服务器时,您都会看到一个控制台日志。 | | `socket.on('disconnect',function(){``console.log('Server has``disconnected');` | 当浏览器断开与服务器的连接时,该功能将运行。 |

Rewrite The Index.ejs File To Include Socket.io

index.ejs 需要显示来自套接字的数据。您不再需要显示来自服务器的数据的 CSS 或许多 HTML 组件。有新的 HTML 组件将显示来自套接字的数据。套接字使用 JavaScript。index.ejs 文件中必须有一个对应的 socket 引用 index.js 中的 socket,所以 index.ejs 中必须有一个对 socket.io 的引用标签用于将 JavaScript 代码添加到 index.ejs 中(见表 2-9 )。用清单 2-5 中的代码更新 index.ejs,注意,index.ejs 以前版本中的很多代码已经被删除了。

<!DOCTYPE html>
<head>
    <title>WebSockets</title>
</head>
<body>

    <div class="wrapper">
        <h1>Using socket.io</h1>
        <p>This page will update with socket.io</p>
    </div>

<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script>
    var socket = io();
</script>
</body>
</html>

Listing 2-5index.ejs

代码解释

在控制台中,确保您位于应用程序的根目录并启动应用程序。

尝试在不同的浏览器和浏览器标签上打开和关闭页面,并查看控制台。每次有到服务器的新连接时,您应该看到到客户机的连接已经建立。每次通过关闭页面来关闭到服务器的连接时,您应该会看到服务器已经断开连接。

表 2-9

index.ejs code explained

| | 在 socket.io 库中调用网页;没有这个页面就不能访问库。 | | :-- | :-- | | var socket = io(); | 为 socket.io 函数创建一个变量。 |

插座如何工作

Socket.io 有许多广播和监听数据的函数。socket.emit 广播数据,socket.on 监听数据。

这些函数在服务器和浏览器上使用一对匹配的 id。这些匹配的 id 对将相互监听更新,并相互发送数据。

其结构是:

socket.emit('an_example_id', message);

socket.on('an_ example_id', function(message){
      Do something with the message from socket.emit
});

socket.emit 将用匹配的 id 将数据发送给函数 socket.on。Socket.on 将侦听来自 socket.emit 的具有匹配 id 的数据。

这意味着您可以拥有多个具有不同 id 的套接字,并且不同套接字之间的数据不会混淆。

Sending Data To a Web Page With Socket.io

现在,您将在服务器和浏览器页面上创建一个简单的套接字,在它们之间传递信息。网页上会有一个按钮,当它被点击时会更新一个数字。按钮已被点击的消息将通过 socket.io 发送到服务器。号码将被改变,然后服务器端的 socket.io 将信息发送回连接的网页。

在 index.js 中添加粗体代码:

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);
var io = require('socket.io')(server);

app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));

app.get('/', function (req, res) {
  res.render('index')
});

var buttonValue = 0;

io.on('connection', function(socket){
    console.log('Connection to client established');
    io.emit('clicked message', buttonValue);

    socket.on('clicked message', function(msg){
          buttonValue = 1 - buttonValue;
            io.emit('clicked message', buttonValue);
            console.log('Received message from client!',msg);
    });

socket.on('disconnect',function(){
        console.log('Server has disconnected');
    });
});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

代码解释

表 2-10 分解了你刚刚添加的代码。

表 2-10

index.js code explained

| `var buttonValue = 0;` | 这个变量包含一个值,当有人点击浏览器上的一个按钮时,这个值就会改变。 | | :-- | :-- | | `socket.on('clicked message', function(msg){``buttonValue = 1 -   buttonValue;``io.emit('clicked message', buttonValue);``console.log('Received message from client!', buttonValue);` | 在这段代码中,套接字 id 是“clicked message”。此套接字将侦听由函数 io.emit('clicked message ',msg)从浏览器发送的消息。当它收到一个时,它将执行指令 button value = 1-button value;这会将 buttonValue 的值更改为零或一。然后,它将使用 io.emit('clicked message ',buttonValue)将新值发送给监听更改的 web 浏览器。 |

清单 2-5 中的 index.ejs 也需要用粗体代码进行更新:

<!DOCTYPE html>
<head>
    <title>WebSockets</title>
</head>
<body>
    <div class="wrapper">
        <h1>Using socket.io</h1>
        <p>This page will update with socket.io</p>
        <button id="clicked">click me</button>
        <div id="updates"></div>
    </div>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script>
    var socket = io();
    var button = document.getElementById('clicked');

    button.onclick = function(e){
        socket.emit('clicked message', 'clicked');
    }
    socket.on('clicked message', function(msg){
        document.getElementById('updates').innerHTML = msg;
    });
</script>
</body>
</html>

代码解释

您现在应该有一个可以与网页交互并更新网页的工作服务器(表 2-11 )。如果你点击页面上的按钮,它将会更新,同时也会更新具有相同 URL 的其他页面;您还应该在控制台中看到一条消息。

表 2-11

index.ejs code explained

| `var button = document.getElementById('clicked');` | 这行代码是一些基本的 JavaScript。在 HTML 中有一个 id 为“clicked”的按钮元素。变量按钮将保存对该元素的引用,因此可以在 JavaScript 中引用它。 | | :-- | :-- | | `button.onclick = function(e){``socket.emit('clicked    message','clicked');` | onclick 是当点击网页上的按钮时执行的功能。函数 socket.emit('clicked message ',' clicked ');叫做。这将把“已点击”的消息传递给服务器的对应 socket.io 函数 socket.on(“已点击的消息”)。 | | `socket.on('clicked message', function(msg){document.getElementById('updates').innerHTML = msg;     });` | 这段代码监听来自服务器的 Id 为“clicked message”的消息,当它得到一个消息时,它使用 JavaScript 函数 document.getElementById 在页面上查找 id 为“updates”的元素,并将其内部 html 更改为从服务器传入的数据。 |

摘要

本章向您介绍了 web 技术,以及如何创建 web 服务器来与 web 浏览器收发数据。

在下一章中,您将使用这些技能来创建一个服务器,该服务器将从 Arduino 导入数据并在网页上显示它。

三、Arduino 到前端:第一部分

在第二章中,你学习了如何用 Node.js 创建一个 web 服务器,并使用它向网页发送数据。在本章中,您将开始从 Arduino 向 Node.js 服务器发送数据,并在网页上使用这些数据。

数据将来自连接到 Arduino 的开关按钮,并通过串行端口进入您的计算机。您可以将这些数据导入 Node.js 服务器并在网页上使用。本章结束时,您将拥有一个带有彩色方块的网页,每次按下 Arduino 按钮,方块都会改变颜色。图 3-1 是你在本章结束时所做的一个例子。

A453258_1_En_3_Fig1_HTML.jpg

图 3-1

Two possible outcomes of the exercise in Chapter 3

串行端口介绍

串行端口将数据一个接一个地以单个位的形式传入和传出计算机。一个位的值可以是 0(低/关/假)或 1(高/开/真)。这些位可以连接在一起传输更复杂的数据,不同的位数有不同的名称。八位是一个字节,一千字节(KB)是 1024 字节(1024 x 8 位),一兆字节(MB)是 1024 千字节。由于这些位只能是 0 或 1,所以它们被称为二进制数据。

使用 Arduino,您可以通过 USB 端口在电脑上来回发送串行数据。每个 Arduino 都有一个串口,有的不止一个。Arduino Uno 使用 RX(引脚 0)和 TX(引脚 1)进行通信。如果使用串行接口,则不能将任何东西连接到管脚 0 和 1。Arduino IDE 有一个内置的串行监视器来查看串行数据。

当您将 Arduino 连接到电脑时,它将连接到电脑的一个串行端口。您需要知道它连接到哪个端口,因为您需要在 Node.js 应用程序中引用它。

查找串行端口

在 Mac 和 Windows PC 上,串行端口号看起来略有不同。在 Mac 上,它看起来像这样:/dev/tty。 or /dev/cu。。在 Windows 中,它看起来会像这样:COM

有多种方法可以找到 Arduino 连接的串行端口:

  1. 连接 Arduino 后,打开 Arduino IDE。在菜单中单击工具菜单,然后将鼠标悬停在端口菜单上;您将看到所有设备都连接到串行端口,Arduino 的串行端口看起来像这样:/dev/tty . USB modem(Arduino/Uno)在 Mac 上,它看起来像 COM
  2. 在 Mac 上,打开终端窗口,键入 ls /dev/tty.usbmodem*。您应该得到类似/dev/tty.usbmodem 的输出。
  3. 在 PC 上,打开设备管理器并打开端口(COM & LPT)菜单,您应该会看到类似 Arduino Uno COM 的内容。

串行数据和 Arduino

有许多功能可以帮助您在 Arduino 之间传输串行数据。他们使用一个叫做串行的库。表 3-1 显示了库中可用的一些功能。

表 3-1

Arduino serial functions

| 命令 | 结果 | | :-- | :-- | | `Serial.begin(9600)` | begin 函数设置串行数据的传输速率;它以每秒的位数来衡量,称为波特率。 | | `Serial.end()` | 表示串行通信结束,并释放引脚 RX 和 TX,以便用于其它输入和输出。 | | `Serial.write()` | 将二进制数据写入串行端口。 | | `Serial.println()` | 打印出串行数据。 |

波特率

波特率设置通过串行端口传输数据的速率。它是以每秒位数来衡量的。Arduino 可以使用的速率有 300、600、1200、2400、4800、9600、14400、19200、28800、38400、57600 或 115200。您可以设置的波特率的最大速度取决于您的设备。如果设备不能处理更高的速度,那么一些数据将不会被注册,您将会丢失数据。速率 9600 是 Arduino 的常用波特率。

Setting Up The Arduino Circuit

在本章中,您将把一个开关按钮连接到一个 Arduino,并使用串行功能来确定按钮是否被按下。

本章中 Arduino 的设置将使用 Arduino Uno、试验板、开关按钮、220 欧姆电阻器和跳线。图 3-2 显示了您需要的套件。

A453258_1_En_3_Fig2_HTML.jpg

图 3-2

1. Breadboard, 2. Switch button, 3. 220 ohm resistor, 4. Arduino

一旦你准备好了工具包,你需要如图 3-3 所示进行设置,并将其连接到你电脑上的 USB 端口。连接组件时,请确保 Arduino 没有连接到电脑或任何其他电源。

A453258_1_En_3_Fig3_HTML.jpg

图 3-3

The circuit setup Write The Arduino Code

当 Arduino 连接到电脑时,打开 Arduino IDE。在 IDE 中有两件事情需要设置:连接的板的类型和它连接的端口。以下是 IDE 的设置:

  1. 在 Arduino IDE 菜单中,选择工具/电路板,然后选择 Arduino/Genuino Uno。
  2. 在工具/端口菜单中选择 Arduino 连接的端口,它会显示类似于 PC 上的 COM3 (Arduino/Genuino Uno)或 Mac 上的/dev/Cu . USB modem 621(Arduino/genu ino Uno)的内容。

然后选择文件/新建打开一个新文件。将文件另存为 chapter_3。复制清单 3-1 中的代码。

    int switchButton = 2;
    void setup() {
        Serial.begin(9600);
        pinMode(switchButton, INPUT);
    }
    void loop() {
        int buttonState = digitalRead(switchButton);
        if(buttonState == HIGH){
        Serial.println("1");
    }else{
        Serial.println("0");
    }
        delay(500);
    }
Listing 3-1chapter_3 code

代码解释

表 3-2 描述了清单 3-1 中的代码。

表 3-2

chapter_3.ino code explained

| `int switchButton = 2;` | 这段代码创建了一个变量来保存输入到 Arduino 中的开关数。在 Arduino 上,它连接到数字引脚 2。 | | `Serial.begin(9600);` | 该功能设置数据传输的波特率。 | | `pinMode(switchButton, INPUT);` | pinMode 是一个为引脚设置模式的功能,INPUT 是默认设置,用于接收数据。它被传递给保存数字 pin 号的 switchButton 变量。 | | `int buttonState = digitalRead(switchButton);` | 变量 buttonState 保存来自按钮所连接的数字引脚 2 的数据。如果按钮被按下,它将为高电平,否则为低电平。 | | `if(buttonState == HIGH){` `Serial.println("1");` `}else{` `Serial.println("0")` `;` | if 语句检查 buttonState 是否为高。如果是,按钮被按下,Serial.println 将向串行端口发送“1”。如果不是,else 语句将改为发送“0”。 | | `delay(500);and` | 由于代码处于循环中,您可以延迟循环的再次开始。如果不这样做,代码可能在循环再次开始之前还没有执行完,您可能会丢失数据。延迟函数使用毫秒,500 是半秒。你需要在延迟中找到平衡点;你不想丢失数据,但如果你让延迟太长,你可能会错过按钮被按下。 |

Run The Arduino Code

单击勾号图标检查代码是否正确,然后单击箭头图标将代码发送到 Arduino。

代码上传后,在 IDE 中单击打开串行监视器;在图 3-4 中以红色显示。

A453258_1_En_3_Fig4_HTML.jpg

图 3-4

How to open the serial port monitor

您应该开始在串行端口窗口中看到数据。它可能不是你期望看到的 0 或 1,但如果串行端口监视器中的波特率与代码中的波特率不匹配,就会发生这种情况。图 3-5 显示了可以在串行端口窗口中更改的位置。转到此下拉菜单,将比率更改为 9600。当按钮被按下时,你应该看到一系列的 1 被打印出来;否则输出应该是 0。

A453258_1_En_3_Fig5_HTML.jpg

图 3-5

The drop-down changes the baud rate.

注意在使用使用串行端口的 web 应用程序之前,您需要关闭 Arduino IDE 中的串行端口监视器。如果不这样做,您将得到一个错误消息,说明端口已经在使用中。

使用前端的数据

现在您可以在 Arduino 中看到串行数据,下一步是将它发送到 Node.js 服务器,以便可以在 web 浏览器上显示。本章中的 Node.js 应用程序将从 Arduino 接收数据,并使用 Socket.io 将数据传递到前端。

串行端口库

您将导入的库之一是 SerialPort 库。这个库允许你通过串口从 Arduino 导入数据到 Node.js。

要使用 Node.js 中的库打开一个端口,您需要包含库的路径并创建一个新的 port 对象。

来自串行端口库的数据是一个缓冲区对象。缓冲区对象是通过串行端口进入的位流(二进制数据)。JavaScript 不能很好地处理二进制数据。SerialPort 有一个 readLine 解析器,可以将二进制数据转换成字符串。代码如下所示:

serialport.parsers.readline("\n")

“\n”是在 JavaScript 中创建新行的方式。readLine 将二进制数据转换成文本行。当它看到换行符时,它知道这是当前数据流的结尾,因此它分离不同的数据流。

串行端口库中有许多函数,但我们将在本书中使用其中的几个。您可以在附录 b 中找到关于 SerialPort 库的更多信息。

下载串行端口库

您将使用 npm 来安装串行端口库。在 PC 上,在使用 npm 安装 SerialPort 之前,您需要下载几个其他的包。在 Mac 上,你将能够下载它,而不需要任何额外的库,所以你不需要做以下步骤。

如果您使用的是 PC,请按照以下步骤下载 SerialPort 库所需的支持库。

  1. 首先,安装 node-gyp,因为它用于编译 Node.js 中的本机附加模块。你可以在 https://github.com/nodejs/node-gyp#installation 找到更多信息。
  2. 还需要安装额外的 windows 构建工具。这些必须安装在以管理模式运行的控制台窗口中。通过右键单击 Windows 菜单并选择 CMD.exe(以管理员身份运行)或在搜索栏中键入来打开 CMD.exe。在控制台中键入 NPM install-g-production windows-build-tools。您可以在 https://github.com/felixrieseberg/windows-build-tools 了解更多关于工具的信息;安装可能需要几分钟时间。

Create a Node.js Application

本章的目录结构如下:

/chapter_03
    /node_modules
    /views
        index.ejs
    index.js
    package.json

首先要为本章创建一个新的 Node.js 应用程序,并安装必要的库。

  1. 创建一个新文件夹来存放应用程序。我把我的叫做 chapter_03。
  2. 打开命令提示符(Windows 操作系统)或终端窗口(Mac)并导航到新创建的文件夹。
  3. 当你在正确的目录键入 npm init 创建一个新的应用程序;您可以按下 return 键浏览每个问题,或者对它们进行更改。
  4. 您现在可以开始添加必要的库;要在命令行中下载 Express.js,请键入 NPM install express @ 4 . 15 . 3–save。
  5. 然后安装 ejs,键入 NPM install ejs @ 2 . 5 . 6–save。
  6. 下载完成后,安装串口。在 Mac 上键入 NPM install serial port @ 4 . 0 . 7-save 在 Windows PC 上键入 NPM install serial port @ 4 . 0 . 7-build-from-source。
  7. 然后最后安装 socket.io,输入 NPM install socket . io @ 1 . 7 . 3–save。

如果查看 package.json 文件,您应该会看到以下依赖项:

"dependencies": {
    "ejs": "².5.6",
    "express": "⁴.15.3",
    "serialport": "⁴.0.7",
    "socket.io": "¹.7.3"
}

现在,您可以为应用程序编写代码了。在 chapter_03 文件夹的根目录下创建一个名为 index.js 的文件,复制清单 3-2 中的代码。

注意在本书中,您将使用 index.js 中的串行端口库。您需要在 index.js 中添加一个对 Arduino 所连接的串行端口的引用。在 Mac 上显示的代码中,将其更改为“/dev/tty.usbmodem ”,在 PC 上将其更改为“COM ”。您需要保留“”并删除< >符号

    var http = require('http');
    var express = require('express');
    var app = express();
    var server = http.createServer(app);
    var io = require('socket.io')(server);
    var SerialPort = require('serialport');
    var serialport = new SerialPort('<add in the serial port    
    for your Arduino>', {
            parser: SerialPort.parsers.readline('\n')
    });
    app.engine('ejs', require('ejs').__express);
    app.set('view engine', 'ejs');
    app.get('/', function (req, res){
        res.render('index');
    });
    serialport.on('open', function(){
        console.log('serial port opened');
    });
    io.on('connection', function(socket){
        console.log('socket.io connection');
        serialport.on('data', function(data){
            data = data.trim();
            socket.emit('data', data);
        });
        socket.on('disconnect', function(){
            console.log('disconnected');
        });
    });
    server.listen(3000, function(){
        console.log('listening on port 3000...');
    });
Listing 3-2index.js code

记得添加你正在使用的串行端口。如果您现在运行这段代码,将会出现错误。它引用了一个尚未创建的 index.ejs 文件。

代码解释

表 3-3 描述了清单 3-2 中的代码。

表 3-3

index.js explained

| `var SerialPort = require('serialport');` | 这会将 SerialPort 库引入 Node.js 应用程序,并将其存储为一个变量。 | | `var serialport = new SerialPort(''` | 该代码创建一个新的串行端口对象。您需要在< >之间添加 Arduino 所连接的串行端口。在 Mac 上它应该看起来像/dev/tty.usbmodem ,在 PC 上它应该看起来像 COM | | `{``parser: SerialPort.parsers.readline('\n')` | 使用 readline 对数据进行解析,' \n '会创建一个新行来分隔每行数据。 | | `serialport.on('open', function(){` | 当端口打开时,将发出 open 事件。当串行端口打开时,您可以指定事件,在代码中有一个控制台日志,这样您就可以知道它是否已经打开。 | | `serialport.on('data', function(data){` | 数据事件开始监视新数据,并将函数传递给新数据。 | | `data = data.trim();` | 该函数允许您访问新数据,但首先需要删除字符前后的任何空白。 | | `socket.emit('data', data);` | 使用 socket.io 函数 emit 将数据传递到前端;它的引用 id 为“数据”。 |

Interacting With A Web Page

来自 Arduino 的数据将用于更新网页。每次按下按钮,方块的颜色都会改变。一个变量将跟踪从 Arduino 发送的当前数据。当新数据进入页面时,有一个 JavaScript 函数检查新数据是否与当前数据不同。

如果是,并且数据是字符串“1”,那么该函数将从颜色列表数组中随机选取一个元素。然后更新方块的颜色。它还更新一段文本和当前变量,因此新数据成为当前数据。

如果新数据为“0 ”,正方形的颜色不会改变,但一段文本会更新。当前变量将再次用新数据更新。

您现在需要在 views 文件夹中创建一个 index.ejs 文件;首先在应用程序的根目录下创建一个 views 文件夹,然后在其中创建一个名为 index.ejs 的文件。将清单 3-3 中的代码复制到 index.ejs 文件中。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Get data</title>
    </head>
    <body>
        <h1>Arduino data</h1>
        <p>Press the button on the Arduino to change the  
        color of the square</p>
        <p>The button is <span id="button-state"></span> </p>

        <svg width="120" height="120" viewBox="0 0 120
        120">
            <rect id="change-color"
             fill="LightSkyBlue"
             width="120"
             height="120"
             />
        </svg>
        <script src="/socket.io/socket.io.js"></script>
        <script>
            var socket = io();
            var current = "0";
            var shape = document.getElementById('change-color');
            var buttonState =
            document.getElementById('button-state');
            var colorArray = ["LightSkyBlue",
            "LightSlateGray","DarkOliveGreen", "orange",
            "DarkRed", "gold", “purple”];

            socket.on("data", function(data){
                if(data === "1"){
                    buttonState.innerHTML = "pressed";
                    if(data !== current){
                        var newColor = colorArray[Math.floor(Math.random()*colorArray.length)];
                        shape.style.fill = newColor;
                    }

                } else{
                    buttonState.innerHTML = "not pressed";
                }
                current = data;
            });
        </script>
    </body>
</html>

Listing 3-3index.ejs code

现在,在控制台窗口中,导航到应用程序的路径,并键入 nodemon index.js 或 node index.js 来启动应用程序。打开浏览器并转到 http://localhost:3000/查看应用程序的运行情况。

每次按下按钮,矩形的颜色都会改变。由于数组中的颜色是随机选取的,因此它可能会选取与当前颜色相同的颜色。如果您想确保矩形改变颜色,您可以为当前颜色创建一个变量,并检查新颜色是否不同。

代码解释

表 3-4 描述了清单 3-3 中的代码。

表 3-4

index.ejs explained

| `` | 这将创建一个具有宽度、高度和颜色的可缩放矢量图形(SVG)正方形。在第四章中会有关于 SVG 的细节。 | | `var current = "0";` | 这将创建一个保存串行数据当前值的变量。该变量将用于检查来自串行端口的数据是否已经改变。 | | `var shape = document.getElementById('change-color');` | Shape 是一个保存对 SVG 矩形的引用的变量。该变量用于更新矩形的颜色。它使用 SVG 的 id 找到它。 | | `var buttonState = document.getElementById('button-state');` | buttonState 是保存对 span 元素的引用的变量。它通过 id 查找元素,并更新其中的文本。 | | `var colorArray = ["LightSkyBlue", "LightSlateGray","DarkOliveGreen", "orange", "DarkRed", "gold", "purple"];` | 变量 colorArray 包含不同颜色名称的数组。 | | `socket.on("data", function(data){` | socket.on 函数正在侦听来自 socket.emit 的数据,其 id 为“data ”,并将传入的数据传递给一个函数。 | | `if(data === "1"){` | if 语句检查新数据是否是字符串“1”如果是,则网页上的文本发生变化,并调用另一个 If 语句。 | | `if(data !== "current"){` | 该 if 语句检查新数据是否与。==,不等于)当前数据。如果不相同,它执行语句中的代码。 | | `var newColor = colorArray[Math.floor(Math.random()` `*colorArray.length)];` | 这段代码从 colorArray 中选择一种颜色。JavaScript Math.random()函数用于在 0 和数组中的元素数之间选择一个随机数。它乘以数组的长度,所以它只选择数组长度内的一个数。 | | `shape.style.fill = newColor;` | 使用变量 shape,SVG 的填充样式被更改为新的颜色。 | | `else{``buttonState.innerHTML = "not pressed";` | 如果新数据的值不是“1”,那么带有 id 按钮状态的 span 的 HTML 将更改为字符串“未按下” | | `current = data;` | 保存当前数据值的变量需要用新数据的值来更新。 |

摘要

您现在应该有一个工作应用程序,当您按下 Arduino 上的按钮时,它的网页会更新。这一章中有很多新概念,第四章将更详细地介绍这些概念。

四、创建 Web 内容简介

在继续之前,理解超文本标记语言(HTML)、级联样式表(CSS)、可缩放矢量图形(SVG)和 JavaScript 是有好处的。这四个概念将贯穿全书,用于创建交互式 web 应用程序、处理数据以及向 Arduino 发送数据和从 Arduino 接收数据。如果你对其中一些领域有信心,就直接跳到你想了解更多的部分。如果你对所有这些科目都感到满意,请跳到第五章。

超文本标记语言

超文本标记语言(HTML)用于在网页上创建内容。如果您创建一个扩展名为. txt 的文件,它可以像许多其他文件类型一样在 web 浏览器中打开,那么您不需要 HTML 来创建内容。使用 HTML 的原因是它提供了你的页面结构。它允许您定义标题和段落,在页面上创建不同的内容块,以及放置图像。结构由 HTML 元素组成;这些元素可以用 CSS 样式化,并与 JavaScript 和 CSS 交互。图 4-1 显示了一个 HTML 段落元素的格式。

A453258_1_En_4_Fig1_HTML.jpg

图 4-1

The structure of a paragraph element

HTML 元素

HTML 元素通常由开始和结束标记组成。开始标记包含对元素类型的引用和元素的属性。

HTML 中的元素通常是块元素或行内元素。块元素在页面上一个接一个:例如,标题和段落。内联元素在块内工作并格式化元素。

块状元素

有各种各样的块元素可用。表 4-1 列出了其中的一些。

表 4-1

Some HTML block elements

| 命令 | 结果 | | :-- | :-- | | `

,

,

,

,
,
` | 这些用于创建标题;数字越小,标题越重要。 | | `

` | 段落元素用于创建文本段落, | | `