UART 串口通信

UART stands for Universal Asynchronous Receiver/Transmitter. It’s not a communication protocol like SPI and I2C, but a physical circuit in a microcontroller, or a stand-alone IC.
摘自 Circuit Basics | http://www.circuitbasics.com/basics-uart-communication/

简单来说,就是一种比较常用的通信协议,使用 RXTX 两个引脚进行通信.使用Bandrate (波特率)控制通信速率

  • RX 表示耳朵,用来通信过程中接收数据

  • TX 表示嘴巴,用来通信过程中发送数据

  • BandRate 表示传输和接收数据的速度,单位是 bit/s 也就是每秒钟接收或者发送多少个 bit,收发双方必须保证使用同一个波特率才能保证数据的正常收发.

ESP 32 引脚图

ESP32 开发板引脚基本相同,这里采用某宝上果云科技的 GOOUUU-ESP32 开发板,然后从网上找了 NodeMCU-32S 的开发板的引脚图,并没有什么区别.

32s_pin

ESP32 共有三对串口:

组号RXTX
0GPIO3GPIO1
1GPIO9GPIO10
2GPIO16GPIO17

第一组为板子上标出的 RXTX 引脚, USB 连接板子的使用需要占用 0 号串口引脚,因此可用的只有 1 号和 2 号引脚.除了天生的串口引脚外, ESP32 还可以自定义 GPIO 引脚作为串口引脚.(PS.部分 ESP3234,35,36,39 这四个 GPIO 引脚只能作为输入,但是作为 TX 必须要能够输出,作为 RX 必须要能够输入,所以在选择 GPIO 引脚的时候需要注意这个问题)

UART 的 API

以下内容来源于 MicroPython 官方文档

导包

UART 模块可以直接从 machine 中导入:

1
from machine import UART

构造函数

UART作为一个对象,其构造函数定义如下:

1
UART(id, baudrate, databits, parity, rx, tx, stopbit, timeout)
参数描述
id串口编号,总共有三对串口,但是0号通常被占用,所以常用的是1和2
bandrate波特率,常用波特率有: 9600 115200
databits数据位,是通信中的每一个字节单元所包含的比特位数。可选的值为 6, 7, 8, 9,默认 8 个位,也就是一个 byte
parity基础校验方式 ,None不进行校验,0 表示偶校验 1 表示奇校验, 校验方式通常是传感器给出的,如果既不是奇校验也不是偶校验而是其他校验方式,需要在这里写None后,接收数据并自行校验
rx接收口的GPIO编号
tx发送口的GPIO编号
stopbit停止位个数,用来表示数据收发完成,可以为1或2, 默认为1
timeout超时时间,取值范围: 0 < timeout ≤ 2147483647

这里以 HH06.03 分贝传感器为例,可以使用以下代码构造一个串口通信对象

1
2
3
from machine import UART
hh06 = UART(1, baudrate=115200)
print(hh06)

读写数据

uart.read(length)

length 表示从串口读取数据的长度,该函数若长度未指定则读取所有数据。

1
uart.read(10)         # 读入10个字符

uart.readline()

顾名思义,就是从串口读取一行数据

1
uart.readline()      # 读入一行

uart.readinto(buf)

读入数据并且保存到缓冲区

uart.write(data)

向串口写入数据,函数会返回 data 的长度

1
uart.write(b'\xbb\xaa')    # 向串口写入2个Byte

uart.any()

检查待读入数据的长度,并返回.如果没有数据则返回长度 0

HH06.03 分贝检测模块串口通信示例

采用 HH06.03ESP32 进行串口通信作为示例.该模块的参数如下:

项目参数描述
产品型号HH_06.03
模块功能检测声音分贝值
通信形式主动型
工作电压DC 5.0V
工作电流29mA/5.0V
通信方式串行 TTL/5V
测量范围40-130dB
频率范围40-8kHz
计权方式A 计权
分辨率0.1dB
帧间隔约 500ms
PCB 尺寸47.12*28.00mm
整体尺寸54.4628.009.70(H)mm

模块采用如下主动发送协议:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
一、 串口参数及协议 
1.1 串口参数
串口波特率:115200,校验位:无,停止位:1 位
1.2 串口数据包协议
数据包格式:起始符+命令+数据+校验值
1)起始符:BBAA ,2 字节数据(0xBB、0xAA);
2)命令:1 字节长度;
00,返回模块固件版本号命令;
01,返回分贝数据命令;
3)数据:2 字节长度 ,软件版本信息及分贝值数据放于此数据段;
4)校验值:1 字节长度,起始符、命令及数据的算术和校验,不计超过 256 的溢出值。
二、通信命令说明
2.1 模块固件版本号命令
如:BB AA 00 02 00 67
起始符:BB AA,表示一帧的开始。
命令:00,表示此帧为返回模块软件版本号帧。
数据:02 00,表示模块软件版本号为 2.0。
校验值:67,为 BB AA 00 02 00 的的算术和校验值。
注:此帧为模块上电后第一个返回的包,且只在上电后返回一次。
2.2 分贝数据命令
如:BB AA 01 7F 02 E7
起始符:BB AA,表示一帧的开始。
命令:01,表示此帧为返回分贝值数据。
数据:7F 02,表示检测到的分贝值为 63.9dB。低字节在前,高字节在后,且每单位为 0.1dB。
校验值:E7,为 BB AA 01 7F 02 的的算术和校验值。
注:此帧为模块上电返回固件版本号命令帧后每约 500ms 返回一次此帧

串口收到的数据类型为 byte,在 Python3 中需要使用 int.from_bytes(byteData, 'big') 转换为整数方便计算,完整的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from machine import UART
hh06 = UART(1)
print(hh06)
frameHeader = b'\xbb\xaa\x01'
while True:
if frameHeader == hh06.read(3):
frameDataLowPosition = hh06.read(1)
frameDataHighPosition = hh06.read(1)
frameCheck = hh06.read(1)
frameDataLowPosition = int.from_bytes(frameDataLowPosition, 'big')
frameDataHighPosition = int.from_bytes(frameDataHighPosition, 'big')
frameCheck = int.from_bytes(frameCheck, 'big')
if ((frameDataLowPosition+frameDataHighPosition+187+170+1)&0xFF) == frameCheck:
db = (frameDataHighPosition<<8 | frameDataLowPosition)*0.1
print(db)