ESP32 for arduino 的3个hardware serial

在arduino IDE的开发环境中,如果使用的开发板不是arduino的开发平台,而是ESP32模组的开发板,那么在实际开发中由于ESP32的支持库与arduino不同,会使得我们在使用一些类,对象,函数等系统资源时会与arduino 标准的用法有很多区别。对于没有arduino硬件平台使用经验的人则不用于关注这个区别,直接按ESP32的规则去使用就行了。对于原来有arduino硬件平台上开发经历的人而言,则要注意这此区别。下面就ESP32平台中Serial这个串行通信对象的进行说明:

概述

ESP32的基于硬件的串行通信接口总共有三个。分别定义在了如下的GPIO口:

名称 IO口的对应关系 系统默认的对象名
UART0 GPIO1 - TX0 GPIO3 - RX0 Serial
UART1 GPIO10 - TX1 GPIO9 - RX1 Serial1
UART2 GPIO17 - TX2 GPIO16 - RX2 Serial2

针对三个硬件串行通信接口,ESP32已预先对应的建立了三个对象Serial、Serial1、Serial2。因此我们才可以在开发时直接上来就写Serial.begin(9600) ; Serial.print(“Hello World!”);这样使用串口。

HardwareSerial库

三个串行通讯对象实际,都在HardwareSerial.h库中进行了定义。
该库具体路径:

C:\Users\loneve\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.5\cores\esp32\HardwareSerial.cpp

(每个人的安装路径在C:\Users\loneve部分可能不一样,请注意区分)。

【Heardware.h中的定义】

#ifndef HardwareSerial_h
#define HardwareSerial_h

#include 

#include "Stream.h"
#include "esp32-hal.h"

class HardwareSerial: public Stream
{
public:
    HardwareSerial(int uart_nr);

void begin (
unsigned long baud, 
uint32_t config=SERIAL_8N1, 
int8_t rxPin=-1, 
int8_t txPin=-1, 
bool invert=false, 
unsigned long timeout_ms = 20000UL
);
...................................

protected:
    int _uart_nr;
    uart_t* _uart;
    uint8_t _tx_pin;
    uint8_t _rx_pin;
};

///

【Heardware.h中的定义】

...............
#include "pins_arduino.h"
#include "HardwareSerial.h"
#define RX1 9

#define TX1 10

#define RX2 16

#define TX2 17

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
HardwareSerial Serial(0);
HardwareSerial Serial1(1);
HardwareSerial Serial2(2);
#endif

HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}

void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms)
{
    if(0 > _uart_nr || _uart_nr > 2) {
        log_e("Serial number is invalid, please use 0, 1 or 2");
        return;
    }
    if(_uart) {
        end();
    }
    if(_uart_nr == 0 && rxPin < 0 && txPin < 0) {
        rxPin = 3;
        txPin = 1;
    }
    if(_uart_nr == 1 && rxPin < 0 && txPin < 0) {
        rxPin = RX1;
        txPin = TX1;
    }
    if(_uart_nr == 2 && rxPin < 0 && txPin < 0) {
        rxPin = RX2;
        txPin = TX2;
    }

   .....................
    }
}

这本来是一件方便开发者使用的设置,但是我们在实际开发时会发现,Serial对象一般已被开发板定义用来进行USB通讯,以及用来给开发板烧录编译好的程序。而Serial1由于占用了GPIO9和GPIO10,而这两个IO口已被开发板用在了SPI Flash上。因此实际Serial1我们也是用不上的。只有Serial2可以用。
幸运的是,ESP32有个可以把硬件串口映射到其它任意端口的能力。

映射到其它端口

因此我们可以这样用:

HardwareSerial MySerial(1);

void setup() {
MySerial.begin(9600, SERIAL_8N1, 16, 17);
}

还是根据库文件源代码

HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}

void begin  (
unsigned long baud, 
uint32_t config=SERIAL_8N1, 
int8_t rxPin=-1,  
int8_t txPin=-1, 
bool invert=false, 
unsigned long timeout_ms = 20000UL );

我们可以知道这两个函数所带参数的定义:
构造函数HardwareSerial(int uart_nr)只有一个参数。设定是串行通行口几,因此上例中HardwareSerial MySerial(1);是建立了一个指向了硬件UART1的串行通讯对象MySerial。由于自已为这个对象起了名字。因此在启动该端口时必须至少指定(波特率、串行帧格式、rx对应的GPIO序号、TX对应的GPIO序号)。
另两个invert 和timeout_ms两个参数取默认值就好,不用设定。那接下来,就可以愉快的使用自已定义的串行通讯对象了。
下面把两种不同的使用方式放在一起对比,便于理解:

使用系统默认的串口:

Serial.begin(9600);
Serial.print(“Hello World!);

使用自定义串口:

HardwareSerial MySerial(1);

void setup() {
MySerial.begin(9600, SERIAL_8N1, 16, 17);
}
void loop{
    uint8_t inputByte =MySerial.read();
}

这里有两点需要注意:

1、GPIO6,7,8,9,10,11已被用于SPI Flash,所以在定义串口TX和RX时请避开这些引脚。
2、由于ESP32开发板的GPIO36、39、34、35是纯输入口,因此最好不要把串口通讯IO口的TX定义在上面这四个口。RX则可以随便定义。

关于Serial接口,先定这些,之后如有必要再进一步深入探讨。

你可能感兴趣的:(ESP32,嵌入式,串口通信)