ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

时间:2020-12-07 16:36:28

授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石。。。

QQ技术互动交流群:ESP8266&32 物联网开发 群号622368884,不喜勿喷

一、你如果想学基于Arduino的ESP8266开发技术

一、基础篇

  1. ESP8266开发之旅 基础篇① 走进ESP8266的世界
  2. ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境
  3. ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
  4. ESP8266开发之旅 基础篇④ ESP8266与EEPROM
  5. ESP8266开发之旅 基础篇⑤ ESP8266 SPI通信和I2C通信
  6. ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库

二、网络篇

  1. ESP8266开发之旅 网络篇① 认识一下Arduino Core For ESP8266
  2. ESP8266开发之旅 网络篇② ESP8266 工作模式与ESP8266WiFi库
  3. ESP8266开发之旅 网络篇③ Soft-AP——ESP8266WiFiAP库的使用
  4. ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
  5. ESP8266开发之旅 网络篇⑤ Scan WiFi——ESP8266WiFiScan库的使用
  6. ESP8266开发之旅 网络篇⑥ ESP8266WiFiGeneric——基础库
  7. ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
  8. ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
  9. ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用
  10. ESP8266开发之旅 网络篇⑩ UDP服务
  11. ESP8266开发之旅 网络篇⑪ WebServer——ESP8266WebServer库的使用
  12. ESP8266开发之旅 网络篇⑫ 域名服务——ESP8266mDNS库
  13. ESP8266开发之旅 网络篇⑬ SPIFFS——ESP8266 Flash文件系统
  14. ESP8266开发之旅 网络篇⑭ web配网
  15. ESP8266开发之旅 网络篇⑮ 真正的域名服务——DNSServer
  16. ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新

三、应用篇

  1. ESP8266开发之旅 应用篇① 局域网应用 ——炫酷RGB彩灯
  2. ESP8266开发之旅 应用篇② OLED显示天气屏
  3. ESP8266开发之旅 应用篇③ 简易版WiFi小车

四、高级篇

  1. ESP8266开发之旅 进阶篇① 代码优化 —— ESP8266内存管理
  2. ESP8266开发之旅 进阶篇② 闲聊Arduino IDE For ESP8266配置
  3. ESP8266开发之旅 进阶篇③ 闲聊 ESP8266 Flash
  4. ESP8266开发之旅 进阶篇④ 常见问题 —— 解决困扰
  5. ESP8266开发之旅 进阶篇⑤ 代码规范 —— 像写文章一样优美
  6. ESP8266开发之旅 进阶篇⑥ ESP-specific APIs说明

    笔者本书的主题是基于Arduino平台来开发ESP8266。那么从另外一个角度来看待这句话,可以理解为:把ESP8266当作一款类似于Arduino UNO型号(为什么不是Mega2560呢?可以从硬件资源方向考虑)的Arduino开发板,用Arduino平台的开发方式来开发项目,只不过ESP8266是在Arduino UNO的基础上加了网络功能
    本章将介绍ESP8266作为Arduino UNO开发板的一些重要开发知识点。
    主要分为8个部分:
    1.ESP8266 Arduino程序结构
    2.计时和延时(Timing and delays)
    3.NodeMcu 端口映射
    4.数字IO(Digital IO)
    5.中断功能
    6.模拟输入(ADC)
    7.模拟输出(PWM)
    8.串口通信(Serial)

1. Arduino程序结构

    在第2章中,笔者提供了一个测试用例,让我们来回顾一下,代码如下:

/**
 * Demo:
 *    测试ESP8266 demo
 *    打印ESP8266模块信息
 *    1.打印Arduino Core For ESP8266 版本,笔者是2.4.2版本
 *    2.打印Flash的唯一性芯片id(读者可以思考一下是否可以用来做点什么唯一性参考)
 *    3.打印Flash实际大小
 *    4.打印IDE配置的使用Flash大小
 *    5.打印IDE配置的Flash连接通信的频率
 *    6.打印Flash连接模式:QIO QOUT DIO DOUT,可以理解为Flash传输速率
 * @author 单片机菜鸟
 * @date 2018/10/22
 */
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  //使能软件看门狗的触发间隔
  ESP.wdtEnable(5000);
}

void loop() {
  //喂狗
  ESP.wdtFeed();
  FlashMode_t ideMode = ESP.getFlashChipMode();
  String coreVersion = ESP.getCoreVersion();
  Serial.print(F("Arduino Core For ESP8266 Version: "));
  Serial.println(coreVersion);
  Serial.printf("Flash real id(唯一标识符):   %08X\n", ESP.getFlashChipId());
  Serial.printf("Flash 实际大小: %u KBytes\n", ESP.getFlashChipRealSize()/1024);
  Serial.printf("IDE配置Flash大小: %u KBytes,往往小于实际大小\n", ESP.getFlashChipSize()/1024);
  Serial.printf("IDE配置Flash频率 : %u MHz\n", ESP.getFlashChipSpeed()/1000000);
  Serial.printf("Flash ide mode:  %s\n\n", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT" : ideMode == FM_DIO ? "DIO" : ideMode == FM_DOUT ? "DOUT" : "UNKNOWN"));

  delay(1000);
}

    去掉代码细节,会得到类似于Arduino编程的代码结构:

/**
 * ESP8266 Arduino程序结构
 * @author 单片机菜鸟
 * @date 2018/10/24
 */
void setup() {
  // 这里开始写初始化代码,只会执行一次

}

void loop() {
  //这里写运行代码,重复执行
}

    对于习惯c语言编程的读者,以上代码又可以抽象成以下伪代码结构:

/**
 * ESP8266 Arduino程序伪代码结构
 * @author 单片机菜鸟
 * @date 2018/10/24
 */
void main(){
  watchdogEnable();//启动看门狗
  setup();//初始化函数
  while(1){
    loop();//业务代码函数
  }
}

代码解析

1.在ESP8266 Arduino编程中,默认会开启看门狗功能,也就是对应伪代码的watchdogEnable(),意味着我们需要适当喂狗,不然会触发看门狗复位;
2.setup()方法:初始化函数,只会运行一次,所以一般情况下,我们都会在这里配置好初始化参数,比如IO口模式、串口波特率设置等等;
3.loop()方法:不断重复执行,这里编写我们的业务代码,同时要注意执行喂狗操作。

2. 计时和延时(Timing and delays)

    时间控制,基本上可以说存在于每一个项目代码中。目前在Arduino中跟时间控制有关的方法包括以下几个:
    delay(ms)
    暂停一个给定的毫秒数的时间间隔。
    delayMicroseconds(us)
    暂停一个给定的微秒数的时间间隔。
    millis()
    返回重启(reset)后所经过的毫秒数。
    micros()
    返回重启(reset)后所经过的微秒数

温馨提示

    通常,我们控制LED灯闪烁都会加上一个delay延时来达到切换亮灭时间长度。但是delay有个缺点就是:在给定的时间间隔内是不能做其他操作,这样对于一些需要响应按键操作的场景就不适用了。那么有没有什么办法既能延时又能不影响其他操作呢?当然,这就是millis()的妙用,通过获取两个时间点的毫秒数,然后计算它们的差值,差值时间间隔内是可以执行其他操作的。代码片段如下:

long debouncdDelay = 60;//延时间隔
long lastDebounceTime = 0; //最近记录的一次时间

// 判断时间间隔是否大于设定的时间间隔。
if(millis()-lastDebounceTime>debouncdDelay){
    lastDebounceTime = millis();
}

3. NodeMcu 端口映射

    在前面,笔者有说到,本书的实验案例是基于NodeMcu这块ESP8266开发板来进行的,其中NodeMcu的核心芯片是ESP8266-12F。要想知道ESP8266-12F给我们提供了什么功能模块,首先了解一下它有什么引脚端口以及NodeMcu与它之间的引脚端口映射关系。

3.1 ESP8266-12F

    首先,认识一下ESP8266-12F的引脚定义,通常会隐藏pin6-pin11,如下图:
ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
    当然,笔者也会提供完整的引脚图以便对比,如下图:
ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
    分析引脚图,可以得出几个结论:
    1.ESP8266-12F总共有22个引脚,对应了第1章选型表的SMD-22封装工艺,同时有GPIO0-GPIO16共17个通用IO口,但是得注意有些IO口还可以完成其他功能(也叫做引脚复用),诸如Serial、I2C、SPI,由相应的函数库完成;
    2.ESP8266具有一个可用的单通道ADC;
    3.GPIO6-GPIO11(复用引脚CS、MISO、MOSI、SCK)用于连接外部flash,对用户不可用,试图使用这些引脚作为IO将会导致程序奔溃;
    4.支持SPI总线通信,对应引脚为GPIO12-GPIO15;
    5.支持I2C总线,对应引脚为GPIO4-GPIO5;
    6.支持串口通信Serial、Serial1,默认对应引脚GPIO1-GPIO3;

3.2 NodeMcu

    接下来,先了解一下NoodeMcu的实物图,如下图:
ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    同时,读者也需要知道ESP8266-12F与NodeMcu的端口映射关系,如下图:
ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    可以看出:
    1.中间的DEVKIT部分,就是NodeMcu提供给外界的端口,对应实物图上标注的端口名称;
    2.除开中间部分,其他部分基本上对应ESP8266引脚,以不同颜色块来区分不同功能;

温馨提示

    NodeMcu上的CLK、SD0、CMD、SD1、SD2引脚,是用于连接外接flash芯片,不应该用于连接其他模块,悬空即可,以防程序奔溃。

    或许笔者会觉得看图有点复杂,所以笔者总结了下面的GPIO引脚映射表,以供参考:

NodeMCU的引脚名称 ESP8266内部GPIO引脚号 可复用功能 备注
D0 GPIO16 可用,只能用作GPIO读/写,不支持特殊功能
D1 GPIO5 I2C总线的SCL 可用
D2 GPIO4 I2C总线的SDA 可用
D3 GPIO0 不可用,烧录固件或者运行模式控制端口
D4 GPIO2 Serial1的TX Serial1没有RX
D5 GPIO14 SPI总线的SCLK 可用
D6 GPIO12 SPI总线的MISO 可用
D7 GPIO13 SPI总线的MOSI、Serial的RX 可用
D8 GPIO15 SPI总线的CS、Serial的TX 可用
D9 GPIO3 Serial的RX 可用
D10 GPIO1 Serial的TX 可用
SD2 GPIO9 尽量不用
SD3 GPIO10 尽量不用

    从上面表格可以看出,我们大约11个GPIO引脚可用。而11个中的2个引脚通常被保留用于RX和TX,以便进行串口通信。因此最后,只剩下8个通用I / O引脚,即D0到D8(除开D3特殊用途)。

温馨提示

    请注意,D0 / GPIO16引脚只能用作GPIO读/写,不支持特殊功能。

4. 数字IO(Digital IO)

    上面说到,ESP8266-12F(也可以大胆说ESP8266-12系列)最终只剩下8个通用的I/O引脚以供我们使用,即是NodeMcu上的D0-D8(除D3之外)。
    Arduino中的引脚号直接与ESP8266 GPIO的引脚号对应通信。pinMode/digitalRead/digitalWrite函数不变,所以要读取GPIO2,可调用digitalRead(2)。除了D0可以设置为INPUT(输入)、OUTPUT(输出)或者INPUT_PULLDOWN(输入,默认下拉,也就是低电平),剩余的数字IO引脚可以设置为INPUT(输入)、OUTPUT(输出)或者INPUT_PULLUP(输入,默认上拉,也就是高电平)。
    下面,将在NodeMcu的D1引脚上写一个LED Blink的Arduino草图:

/**
 * LED灯闪烁实验
 */
void setup() {
    pinMode(D1, OUTPUT);   // 初始化D1引脚为输出引脚
}

void loop() {
    digitalWrite(D1, LOW); // 亮灯
    delay(1000); // 延时1s
    digitalWrite(D1, HIGH);// 灭灯
    delay(1000); // 延时1s
}

注意

    某些开发板和模块,仍将使用第9和第11引脚(如果闪存芯片工作于DIO模式,与默认的QIO模式相反),它们可用于IO。

5. 中断功能

    中断可以理解为在正常的运行流程中突然插入的操作,这就像你在忙于工作的时候,领导突然叫你去买个下午茶,然后你就去把下午茶买回来,再继续工作。基于ESP8266的NodeMcu的数字IO的中断功能是通过attachInterruptdetachInterrupt函数所支持的。除了D0/GPIO16,中断可以绑定到任意GPIO的引脚上。所支持的标准中断类型有:CHANGE(改变沿,电平从低到高或者从高到低)、RISING(上升沿,电平从低到高)、FALLING(下降沿,电平从高到低)。
    首先,我们来看看Arduino IDE中用于中断的函数。
    1.attachInterrupt()
    该功能用于在将指定引脚设置为响应中断。
    函数: attachInterrupt(pin, function, mode);
    参数:
        pin:要设置中断编号,注意,这里不是引脚编号。
        function:中断发生时运行的函数, 这个函数不带任何参数,不返回任何内容。
        Interrupt type/mode:它定义中断被触发的条件方式。
            CHANGE:改变沿,引脚电平从低变为高或者从高变为低时触发中断。
            RISING:上升沿,引脚电平从低变为高时触发中断。
            FALLING:下降沿,引脚电平从高变为低时触发中断。
    返回值: 无;

    2.detachInterrupt()
    该功能用于禁用指定GPIO引脚上的中断。
    函数: detachInterrupt(pin)
    参数:
        pin:要禁用的中断的GPIO引脚。
    返回值: 无;

    3.digitalPinToInterrupt()
    该功能用于获取指定GPIO引脚的中断号。
    函数: digitalPinToInterrupt(pin)
    参数:
        pin:要获取中断号的GPIO引脚。

例子
    将NodeMcu的D2引脚设置为上升沿中断。在D2上外接一个按键,按键通过电阻下拉到地。当发生中断的时候,我们在串口监视器上打印“Hello ESP8266”。

ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

例子代码

/**
 * 功能描述:ESP8266中断演示
 */
void setup() {
 Serial.begin(115200);//设置串口波特率
 attachInterrupt(digitalPinToInterrupt(D2), InterruptFunc, RISING);//设置中断号、响应函数、触发方式
}

void loop() {
}

/**
 * 中断响应函数
 */
void InterruptFunc(){
 Serial.println("Hello ESP8266");
}

6. 模拟输入(ADC)

    学过模拟电路或者数字电路的人都会听过ADC,它又叫做模数转换器,用于将模拟信号转换成可视化的数字形式。ESP8266具有内置的10位ADC,只有一个ADC通道,即只有一个ADC输入引脚可读取来自外部器件的模拟电压。
    ESP8266上的ADC通道和芯片供电电压复用,也就是说我们可以将其设置为测量系统电压或者外部电压。

6.1 测量外部电压

    相关方法
        analogRead(A0),用于读取施加在模块的ADC引脚上的外部电压;
    输入电压范围
        0 - 1.0V之间;
    测量精度
        由于ADC具有10位分辨率,因此会给出0-1023的值范围;
    注意点
        为了支持外部电压范围(0-3.3v),NodeMcu做了一个电阻分压器,如图所示:

ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    例程
    编写一个读取NodeMcu的ADC引脚上的模拟电压。我们这里使用电位器在ADC引脚上提供0-3.3V的可变电压。如下图连接线:
ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
    代码如下:

/**
 * 功能描述:ESP8266 ADC 读取外部电压
 * 在串口调试器查看效果
 */
void setup() {
  Serial.begin(115200);//配置波特率
}

void loop() {
  Serial.print("ADC Value: ");
  Serial.println(analogRead(A0));//输出0-1023 对应 外部输入电压 0-1.0v
  //延时1s
  delay(1000);
}

6.2 测量系统电压

    相关方法
        ESP.getVcc(),读取NodeMCU模块的VCC电压,单位是mV;
    注意点
        ADC引脚必须保持悬空;在读取VCC电源电压之前,应更改ADC模式以读取系统电压。
要ADC_MODE(mode)在#include行后面改变ADC模式。
模式是ADC_TOUT(对于外部电压),ADC_VCC(对于系统电压)。默认情况下,它读取外部电压。
    例程
    编写ESP8266读取系统电压,代码如下:

/**
 * 功能描述:ESP8266 ADC 读取系统电压
 * 在串口调试器查看效果
 */
ADC_MODE(ADC_VCC);//设置ADC模式为读取系统电压

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.print("ESP8266当前系统电压(mV): ");
  Serial.println(ESP.getVcc());
  delay(1000);
}

7. 模拟输出(PWM)

    PWM(Pulse Width Modulation,脉宽调制),是在保持波的频率不变的同时改变脉宽的技术。当我们需要连续控制电压变化,实现呼吸灯或者电机转速的时候,就要用到PWM,如下图。
ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
    首先,我们来理解一下占空比。一个脉冲周期由一个ON周期(VCCC)和一个OFF周期(GND)组成。一段时间内ON周期占据脉冲周期的比例就叫做占空比。

DutyCycle(percentage)=Ton/TotalPeriodX100

    例如,一个10ms的脉冲保持ON 2ms,那么根据公式,占空比是20%。

注意点

    脉冲频率一般都是固定的,跟占空比没有关系。

NodeMcu PWM引脚

    如下图,标注PWM引脚。

ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    基本上数字IO都可以作为PWM复用引脚,除了D0。不过需要注意的是,D3尽量不用,它内部连接ESP8266 GPIO0。

NodeMcu PWM有关Arduino函数

    1.analogWrite()
    该功能用于在指定的引脚上启用软件PWM。
    函数: analogWrite(pin,val)
    参数:
        pin:要启用软件PWM的GPIO引脚。
        val:数值,一般在0到PWMRANGE范围,默认PWMRANGE是1023。
    返回值: 无;
    注意点:
        analogWrite(pin, 0)用于禁用指定引脚上的PWM。
    2.analogWriteRange()
    该功能用于改变PWMRANGE数值。
    函数: analogWriteRange(new_range)
    参数:
        new_range:新的PWMRANGE数值。
    返回值: 无;
    注意点:
        可以理解为PWM精度范围。同样的PWM频率下,默认占空数值0-123。如果你改变PWMRANGE为2047,那么占空数值就变成0-2047。精度高了一倍。
    3.analogWriteFreq()
    该功能用于改变PWM频率。
    函数: analogWriteFreq(new_frequency)
    参数:
        new_frequency:新PWM频率,默认是1kHZ。
    返回值: 无;
    注意点:
        百度上很多资料都说PWM频率范围为1-1KHz。但是通过查看源码,如下:

static uint16_t analogFreq = 1000;

extern void __analogWriteFreq(uint32_t freq) {
  if (freq < 100) {
    analogFreq = 100;
  } else if (freq > 40000) {
    analogFreq = 40000;
  } else {
    analogFreq = freq;
  }
}

    可以看出,Arduino For ESP8266的PWM频率范围应该是100Hz-40KHz

PWM例程

    呼吸灯,LED灯明暗连续变化。代码如下:

/**
 * 功能描述:ESP8266 PWM演示例程
 * @author 单片机菜鸟
 * @date 2018/10/25
 */

#define PIN_LED D6

void setup() {
  // 这里开始写初始化代码,只会执行一次
  pinMode(PIN_LED,OUTPUT);
  analogWrite(PIN_LED,0);
}

void loop() {
  //这里写运行代码,重复执行
  for(int val=0;val<1024;val++){
     //占空比不断增大  亮度渐亮
     analogWrite(PIN_LED,val);
     delay(2);
  }

  for(int val=1023;val>=0;val--){
     //占空比不断变小  亮度渐暗
     analogWrite(PIN_LED,1023);
     delay(2);
  }
}

8. 串口通信(Serial)

    ESP8266的串口通信与传统的Arduino设备完全一样。除了硬件FIFO(128字节用于TX和RX)之外,硬件串口还有额外的256字节的TX和RX缓存。发送和接收全都由中断驱动。当FIFO/缓存满时,write函数会阻塞工程代码的执行,等待空闲空间。当FIFO/缓存空时,read函数也会阻塞工程代码的执行,等待串口数据进来。
    NodeMcu上有两组串口,Serial和Serial1。
    Serial使用UART0,默认对应引脚是GPIO1(TX)和GPIO3(RX)。在Serial.begin执行之后,调用Serial.swap()可以将Serial重新映射到GPIO15(TX)和GPIO13(RX)。再次调用Serial.swap()将Serial重新映射回GPIO1和GPIO3。不过,一般情况下,默认就好。

串口映射例程

/**
 * 功能描述:ESP8266 Serial映射例程
 * @author 单片机菜鸟
 * @date 2018/10/25
 */

void setup() {
  // 这里开始写初始化代码,只会执行一次
  Serial.begin(115200);
  Serial.println("GPIO1(TX),GPIO3(RX)");
  //调用映射方法
  Serial.swap();
  Serial.println("GPIO15(TX),GPIO13(RX)");
  //重新映射回来
  Serial.swap();
  Serial.println("GPIO1(TX),GPIO3(RX)");
}

void loop() {
  //这里写运行代码,重复执行
}

    Serial1使用UART1,默认对应引脚是GPIO2(TX)。Serial1不能用于接收数据,因为它的RX引脚被用于flash芯片连接。要使用Serial1,请调用Serial.begin(baudrate)。代码如下:

/**
 * 功能描述:ESP8266 串口例程
 * @author 单片机菜鸟
 * @date 2018/10/25
 */

void setup() {
  // 这里开始写初始化代码,只会执行一次
  Serial.begin(115200);
  Serial.println("Hello Serial");
  Serial1.begin(115200);
  Serial1.println("Hello Serial1");
}

void loop() {
  //这里写运行代码,重复执行
}

    如果不使用Serial1并且不映射串口,可以将UART0的TX映射到GPIO2,具体操作是:在Serial.begin()之后调用Serial.set_tx(2)或者直接调用Serial.begin(baud,config,mode,2)。
    默认情况下,当调用Serial.begin后,将禁用WiFi库的诊断输出。要想再次启动调试输出,请调用Serial.setDebugOutput(true)。要将调试输出映射到Serial1时,需要调用Serial1.setDebugOutput(true)。
    调用Serial.setRxBufferSize(size_t size)允许定义接收缓冲区的大小,默认值是256(缓冲区也是使用内存,意味着不能一味地去增大这个值)。
    Serial和Serial1对象都支持5,6,7,8个数据位,奇数(O)、偶数(E)和无(N)奇偶校验,以及1或者2个停止位。要设置所需的模式,请调用Serial.begin(baudrate, SERIAL_8N1), Serial.begin(baudrate, SERIAL_6E2)等。
    Serial和Serial1都实现了一种新方法用来获取当前的波特率设置。要获取当前的波特率,请调用Serial.baudRate(),Serial1.baudRate()。代码如下:

/**
 * 功能描述:ESP8266 串口波特率例程
 * @author 单片机菜鸟
 * @date 2018/10/25
 */

void setup() {
  // 这里开始写初始化代码,只会执行一次
  // 设置当前波特率为57600
  Serial.begin(57600);
  // 获取当前波特率
  int br = Serial.baudRate();
  // 将打印 "Serial is 57600 bps"
  Serial.printf("Serial is %d bps", br);
}

void loop() {
  //这里写运行代码,重复执行
}

    Serial和Serial1都属于硬件串口(HardwareSerial)的实例,如果读者需要使用ESP8266 软件串口的功能,请参考以下库:https://github.com/plerup/espsoftwareserial。
    为了检测进入Serial的未知波特率的数据,可以调用Serial.detectBaudrate(time_t timeoutMillis)。这个方法尝试在timeoutMillis ms的时间内检测波特率,检测成功返回波特率,检测失败返回0。detectBaudrate()方法在Serial.begin()被调用之前调用(因为它不需要用到接收缓冲区或者串口配置),并且它不能检测数据位位数或者停止位。这个检测过程不会去改变数据的波特率,所以可以在检测成功之后,调用Serial.begin(detectedBaudrate)。

串口用处

    一般来说,串口通信用在两个方面:
    1.与外围串口设备传输数据,比如蓝牙模块、Arduino等等;
    2.开发过程中用来调试代码,通过串口输出Debug信息了解程序运行信息。例程如下:

/**
 * Demo1:
 *    statin模式下,创建一个连接到可接入点(wifi热点),并且打印IP地址
 * @author 单片机菜鸟
 * @date 2019/09/02
 */
#include <ESP8266WiFi.h>

#define AP_SSID "xxxxx" //这里改成你的wifi名字
#define AP_PSW  "xxxxx"//这里改成你的wifi密码
//以下三个定义为调试定义
#define DebugBegin(baud_rate)    Serial.begin(baud_rate)
#define DebugPrintln(message)    Serial.println(message)
#define DebugPrint(message)    Serial.print(message)

void setup(){
  //设置串口波特率,以便打印信息
  DebugBegin(115200);
  //延时2s 为了演示效果
  delay(2000);
  DebugPrintln("Setup start");
  //启动STA模式,并连接到wifi网络
  WiFi.begin(AP_SSID, AP_PSW);

  DebugPrint(String("Connecting to ")+AP_SSID);
  //判断网络状态是否连接上,没连接上就延时500ms,并且打出一个点,模拟连接过程
  //笔者扩展:加入网络一直都连不上 是否可以做个判断,由你们自己实现
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    DebugPrint(".");
  }
  DebugPrintln("");

  DebugPrint("Connected, IP address: ");
  //输出station IP地址,这里的IP地址由DHCP分配
  DebugPrintln(WiFi.localIP());
  DebugPrintln("Setup End");
}

void loop() {
}

9. 总结

    总体上讲,本章基础内容比较多,笔者介绍ESP8266在Arduino平台上的一些基础知识点,包括程序结构、NodeMcu端口映射、ESP8266 数字IO、PWM、ADC、串口通信等等。
本章目的很简单,就是为了告诉读者,ESP8266到底给我们提供了什么可利用硬件资源,以方便我们项目开发。