3、Python串口编程基础:pySerial库安装、串口参数配置、数据发送与接收基础API

好,咱们进入实战环节。前面聊了那么多UART的理论,现在该动手了。Python做串口通信,绕不开的就是pySerial这个库。我最早用Python调串口是在一个产线测试项目里,当时赶工期,文档也没细看,结果被几个小坑绊得够呛。今天我把这些经验揉碎了讲给你听。

3.1 安装pySerial:别小看这一步

安装本身很简单,一行命令搞定:

pip install pyserial

但有个细节我吃过亏——权限问题。在Linux下,如果你直接用pip装,可能发现程序跑起来报错说打不开串口。为什么?因为当前用户没有dialout组的权限。

我曾经在树莓派上折腾了半小时,最后发现是忘了把用户加到dialout组。执行下面这条命令,然后注销重登就好了:
sudo usermod -a -G dialout $USER

Windows下一般没问题,但注意别装成Python 2的版本。现在都2025年了,用Python 3吧。

3.2 串口参数配置:参数配不对,通信全白费

打开串口前,你得告诉pySerial一堆参数。我习惯把它们写在一个字典里,方便维护:

import serial

config = {
    'port': 'COM3',          # Windows下是COM口,Linux下是/dev/ttyUSB0之类的
    'baudrate': 115200,      # 波特率,常见的有9600、19200、115200
    'bytesize': serial.EIGHTBITS,  # 数据位,通常是8位
    'parity': serial.PARITY_NONE,   # 校验位,NONE/EVEN/ODD
    'stopbits': serial.STOPBITS_ONE, # 停止位,1位或2位
    'timeout': 1,            # 读超时,单位秒。None表示一直等
    'xonxoff': False,        # 软件流控,一般关掉
    'rtscts': False          # 硬件流控,也关掉
}

ser = serial.Serial(**config)

这里有个参数我得重点说说——timeout。我见过不少新手把它设成None,结果程序卡死在read()那里,界面假死。你想想看,如果对端设备突然不发了,你的程序就永远等下去了。

我个人习惯:调试阶段timeout设1秒,正式环境根据最坏情况设3-5秒。这样即使通信异常,程序也能及时报错退出。

3.3 数据发送与接收:核心API实战

pySerial的发送和接收API非常简洁,就几个函数。但简洁不代表简单,用不好照样出问题。

3.3.1 发送数据

# 发送字符串(需要编码成bytes)
ser.write(b'Hello UART\n')

# 发送十六进制数据
ser.write(bytes([0xAA, 0x55, 0x01, 0x02, 0x03]))

# 发送整型变量
data = 0x1234
ser.write(data.to_bytes(2, 'big'))  # 大端模式,2字节

注意:write()返回的是实际发送的字节数。我遇到过USB转串口线质量差,明明要发100字节,实际只发了80字节。所以严谨的做法是检查返回值:

sent = ser.write(data)
if sent != len(data):
    print(f"警告:只发送了{sent}/{len(data)}字节")

3.3.2 接收数据

接收有几种方式,看场景选:

方法 说明 适用场景
ser.read(size) 读取指定字节数,超时返回已读到的数据 已知数据帧长度
ser.readline() 读到换行符\n为止 文本协议,如AT指令
ser.read_until(expected) 读到指定字节序列为止 自定义帧尾,如0x0D0A
ser.in_waiting 返回接收缓冲区中的字节数 非阻塞轮询

我常用的模式是先查in_waiting,再读:

if ser.in_waiting > 0:
    data = ser.read(ser.in_waiting)
    print(f"收到{len(data)}字节: {data.hex()}")
避坑指南:readline()依赖超时机制。如果对端设备不发送换行符,程序会一直等到timeout。我曾经调试一个GPS模块,死活收不到完整数据,最后发现模块输出的是回车符\r而不是换行符\n。改用read_until(b'\r')就解决了。

3.4 完整示例:一发一收

把上面知识点串起来,写个简单的环回测试:

import serial
import time

ser = serial.Serial(
    port='COM3',
    baudrate=115200,
    timeout=1
)

# 发送测试数据
test_data = bytes([0xAA, 0x55, 0x01, 0x02, 0x03, 0x04, 0x05])
ser.write(test_data)
print(f"发送: {test_data.hex()}")

# 等待并接收回显
time.sleep(0.1)  # 给设备一点处理时间
if ser.in_waiting > 0:
    rx_data = ser.read(ser.in_waiting)
    print(f"接收: {rx_data.hex()}")
    
    # 简单校验
    if rx_data == test_data:
        print("环回测试通过!")
    else:
        print("数据不匹配!")
else:
    print("未收到数据")

ser.close()

这个例子虽然简单,但已经包含了串口编程的核心流程:打开→配置→发送→接收→校验→关闭。后面的章节我们会在这个基础上不断加码。

3.5 本章知识结构

下面这张图把pySerial的核心脉络理清楚了,你可以对照着回顾:

pySerial串口编程核心知识结构 pySerial库 安装与权限 参数配置 数据发送 数据接收 pip install dialout组 波特率 数据位/校验/停止 write(bytes) 检查返回值 read/readline in_waiting 核心流程:打开 → 配置 → 发送 → 接收 → 校验 → 关闭 关键提醒 • timeout参数必须设置,避免程序死锁 • 发送后检查返回值,确保数据完整发出