3. 串口通信基础:串口协议原理、波特率与数据位、Python pyserial库实战、串口数据抓包分析

串口通信,说白了就是嵌入式世界里最古老也最通用的「对话方式」。我刚开始做飞控地面站那会儿,第一件事就是搞定串口——因为不管你是用MAVLink还是自定义协议,最终都得靠这根串口线把数据从飞控板上拽下来。

这一章,咱们就把串口通信的底裤扒干净。从协议原理到Python实战,再到抓包分析,一条龙走完。

3.1 串口协议原理:为什么叫「串」口?

串口通信的全称是「串行通信接口」。所谓串行,就是数据一位一位地按顺序传输,像一列火车一样,一个车厢接一个车厢地通过铁轨。与之对应的是并行通信,一次传8位、16位,但线多、成本高、抗干扰差。

我当年在学校做第一个单片机项目时,用的就是并行LCD屏,那排线密密麻麻的,焊错一根就黑屏。后来换成串口屏,两根线搞定,世界清净了。

串口通信的核心要素就三个:

  • 波特率(Baud Rate):每秒传输的符号数,单位是bps。常见的有9600、115200、921600等。
  • 数据位(Data Bits):每个数据包包含的实际数据位数,通常是8位,也有7位、9位的情况。
  • 停止位(Stop Bits):标志一个数据帧结束的位,常见1位或2位。

再加上可选的校验位(Parity Bit),就构成了一个完整的串口数据帧。

串口数据帧结构(8N1为例):

起始位(1) + 数据位(8) + 校验位(无) + 停止位(1) = 10位/帧

发送一个字节,实际需要传输10位。所以115200波特率下,理论最大字节传输速率是115200/10 = 11520字节/秒。

3.2 波特率与数据位:为什么飞控常用115200?

你可能会问:为什么无人机飞控和地面站之间,默认波特率大多是115200?

原因很简单:平衡。115200在大多数STM32和Pixhawk硬件上,时钟误差小于1%,而且传输速率够用——MAVLink协议一个典型消息包也就几十字节,115200足够每秒传几百条消息。再往上走,比如921600,虽然更快,但对线材和干扰更敏感,我就在项目里吃过这个亏。

我记得有一次调试一款四旋翼,飞控日志里总有随机丢包。查了两天,最后发现是USB转串口线质量太差,921600下误码率飙升。降到115200后,稳如老狗。

波特率 字节/秒(8N1) 适用场景 注意事项
9600 960 调试、GPS模块 慢,但稳定
57600 5760 旧版飞控 中等速率
115200 11520 主流飞控默认 推荐首选
921600 92160 高速数传、日志下载 对线材要求高

避坑指南:我曾经遇到过飞控和地面站波特率设置不一致,但双方都能收到数据——只是全是乱码。这种情况在调试时特别容易忽略,因为串口灯还在闪,你以为在通信,其实在「鸡同鸭讲」。所以第一件事永远是:确认波特率一致。

3.3 Python pyserial库实战:从打开串口到收发数据

好了,理论讲完,咱们直接上代码。Python的pyserial库是串口通信的事实标准,几乎所有的地面站软件底层都用它。

先安装:

pip install pyserial

然后,一个最基础的串口收发程序长这样:

import serial
import time

# 打开串口
ser = serial.Serial(
    port='COM3',        # Windows下是COM口,Linux下是/dev/ttyUSB0或/dev/ttyACM0
    baudrate=115200,
    bytesize=serial.EIGHTBITS,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    timeout=0.1         # 读取超时,单位秒
)

# 检查是否打开成功
if ser.is_open:
    print(f"串口 {ser.port} 已打开,波特率 {ser.baudrate}")

# 发送数据
ser.write(b'Hello, Flight Controller!\n')

# 读取数据
while True:
    if ser.in_waiting > 0:
        data = ser.readline()
        print(f"收到: {data}")
    time.sleep(0.01)

这段代码看起来简单,但有几个坑我得提醒你:

  • 端口号:Windows下COM口编号可能变来变去,建议用设备管理器确认。Linux下用ls /dev/tty*查看。
  • 超时设置:timeout=0表示非阻塞,readline会立即返回空;timeout=None表示阻塞等待直到读到数据。我一般设0.1秒,既不会卡死,也不会空转。
  • 换行符:MAVLink协议是二进制协议,不依赖换行符。但调试时发文本消息,记得加\n。

3.4 串口数据抓包分析:用逻辑分析仪看「真」数据

写代码是一回事,但有时候你发出去的数据和飞控收到的数据,可能根本不是一回事。这时候就需要抓包分析了。

我个人最常用的工具是逻辑分析仪,便宜点的几十块钱的Saleae克隆版就够用。配合PulseView或Saleae Logic软件,直接看串口线上的电平变化。

抓包步骤:

  1. 把逻辑分析仪的通道0接到飞控的TX引脚,GND共地。
  2. 设置采样率,至少4倍于波特率(115200建议用1MHz以上)。
  3. 触发方式设为下降沿(起始位是低电平)。
  4. 开始抓取,然后让地面站发一条MAVLink消息。
  5. 在软件里解码串口协议,设置波特率、数据位、停止位。

你会看到类似这样的波形:

实际抓包波形解读:

空闲时,TX线为高电平(逻辑1)。

起始位:拉低为0,持续1个位时间。

数据位:从LSB(最低有效位)到MSB依次传输。

停止位:拉高为1,持续1个或2个位时间。

如果波形上有毛刺或电平不稳,说明干扰严重,需要检查接地或降低波特率。

我曾经遇到一个诡异问题:地面站发送的MAVLink心跳包,飞控偶尔收不到。用逻辑分析仪一抓,发现TX线上每隔几十个字节就有一个窄脉冲——原来是USB转串口芯片的驱动问题,导致数据帧间隔不稳定。换了个芯片型号,问题解决。

重要提醒:不要完全相信串口调试助手的显示。有些调试助手会过滤掉非打印字符,而MAVLink是二进制协议,很多字节是不可见的。用逻辑分析仪或二进制抓包工具(如RealTerm、Hercule)才能看到完整数据。

3.5 本章知识体系总览

下面这张图,把串口通信的核心知识点串起来了。你可以把它当作一个快速索引,以后遇到串口问题,先看这张图定位问题在哪一层。

串口通信知识体系 串口协议原理 波特率 (Baud Rate) 数据位 (Data Bits) 停止位/校验位 Python pyserial 实战:打开 → 配置 → 读写 → 关闭 串口数据抓包分析:逻辑分析仪 + 波形解码 常见问题:波特率不匹配 / 线材干扰 / 驱动问题 / 丢包 提示:串口通信是地面站与飞控之间的物理层基础,所有上层协议(MAVLink等)都依赖它正常工作。 调试时,建议从物理层开始排查:先看波形,再看协议。

嗯,串口通信这块内容,说深不深,说浅不浅。但它是整个地面站通信的基石——你想想看,如果串口这层都搞不定,后面MAVLink协议解析、消息路由、遥测显示,全都是空中楼阁。

我个人建议,学完这一章后,拿一块飞控板或者一个USB转串口模块,亲手跑一遍上面的Python代码,再用逻辑分析仪看一眼波形。只有亲眼看到那串高低电平在示波器上跳动,你才算真正理解了串口。