Python串口通信库pyserial安装与基础用法
在硬件调试、物联网开发及工业仪器交互场景中,计算机与单片机、传感器等外设之间最通用的连接通道就是串口(Serial Port)。pyserial 是 Python 生态中最主流且成熟的跨平台串口通信封装库,本文将介绍其安装流程、端口识别、参数配置、字节读写规范以及常见故障排查方法,帮助读者掌握稳定的串口开发流程。
一、pyserial的安装与环境验证
在配置开发环境前,需要明确一个常见混淆点:该库在 PyPI 上的正式包名为 pyserial,但在 Python 代码中导入时使用的是 import serial。切勿在终端中执行 pip install serial,因为这是一个功能不同的独立过时包,混淆安装会导致属性缺失或版本异常。
安装命令如下:
pip install pyserial
安装完成后,可在命令行终端中运行以下命令验证安装结果与当前版本:
python -c "import serial; print(serial.__version__)"
示例输出:
3.5
如果命令能够正常打印出版本号且未报告 ModuleNotFoundError,说明基础运行环境已准备就绪。
二、串口通信的标准操作流程
无论是简单的点对点测试,还是多传感器连续轮询,使用 pyserial 进行通信都遵循固定且严谨的操作顺序。跳过识别或未显式释放资源都会导致端口被系统独占锁定。
三、枚举与查找可用串口
不同操作系统对串口设备的命名规则各不相同:
- Windows:通常为
COM1、COM3等格式; - Linux:USB 转串口通常为
/dev/ttyUSB0,板载虚拟串口为/dev/ttyACM0; - macOS:通常为
/dev/cu.usbserial-XXXX或/dev/cu.usbmodemXXXX。
通过 serial.tools.list_ports 工具模块,可以在脚本中自动扫描已连接的硬件,而无需手动进入设备管理器查看:
import serial.tools.list_ports
ports = serial.tools.list_ports.comports()
if not ports:
print("未发现可用串口设备")
else:
for port in ports:
print(f"端口名: {port.device}")
print(f"描述信息: {port.description}")
print(f"硬件标识: {port.hwid}")
print("-" * 30)
示例输出:
端口名: COM3
描述信息: USB-SERIAL CH340 (COM3)
硬件标识: USB VID:PID=1A86:7523 SER=5 LOCATION=1-2
------------------------------
四、打开串口与超时模式解析
实例化 serial.Serial 类即可打开串口。常用参数说明如下:
port:端口名称(字符串)。baudrate:通信波特率,常见有9600、115200等,必须与下位机配置保持一致。bytesize:数据位,默认为serial.EIGHTBITS(8位)。parity:校验位,默认为serial.PARITY_NONE(无校验)。stopbits:停止位,默认为serial.STOPBITS_ONE(1位)。timeout:读取超时时长,单位为秒。
关键差异:三种读取超时模式的对比
在编写数据接收逻辑时,timeout 的设定直接决定了程序的响应模式。不同场景下具体表现差异明显:
五、数据收发与类型转换
串口物理线路传输的最小单元是二进制字节。在 Python 3 中,字符串(str)与字节串(bytes)属于不同类型,pyserial 的读写接口只接受并返回 bytes 类型。
1. 数据发送(Write)
直接传入字符串会触发 TypeError: unicode strings are not supported, please encode to bytes。正确的做法是使用 encode() 转换为字节串,或直接使用字节字面量 b"...":
import serial
ser = serial.Serial('COM3', 9600, timeout=1)
# 发送字符串(需编码)
message = "GET_STATUS\r\n"
ser.write(message.encode('utf-8'))
# 发送十六进制原始字节指令
cmd = bytes([0xAA, 0x01, 0x55])
ser.write(cmd)
ser.close()
2. 数据读取(Read 与 Readline)
读取数据有两种常用方法:
ser.read(size):读取指定数量的字节。若设置了超时且数据不足,则在超时后返回已读取到的部分。ser.readline():连续读取直到遇到\n(换行符)或触发超时。适合以换行符作为结束符的 ASCII 文本协议。ser.in_waiting:属性值表示当前输入缓冲区中尚未读取的字节总数,可用于非阻塞判断。
import serial
with serial.Serial('COM3', 9600, timeout=1) as ser:
# 检查缓冲区是否有数据
if ser.in_waiting > 0:
raw_data = ser.readline()
# 解码并去除末尾空白字符
text = raw_data.decode('utf-8', errors='replace').strip()
print(f"收到数据: {text}")
六、推荐实践范式:上下文管理器与异常捕获
如果在通信过程中发生报错导致程序中断,而未能执行 ser.close(),该串口可能会一直被操作系统标记为“使用中”,导致下次运行报占用错误。使用 with 上下文管理器可以确保不论正常退出还是出现异常,系统句柄都能安全释放。
import serial
import time
port_name = 'COM3'
baud_rate = 115200
try:
with serial.Serial(port_name, baud_rate, timeout=2) as ser:
print(f"成功打开串口: {port_name}")
# 部分硬件在打开连接时会重启,建议预留准备时间
time.sleep(1.5)
# 清空残留的输入缓存
ser.reset_input_buffer()
# 发送测试指令
ser.write(b"PING\r\n")
# 接收一行响应
response = ser.readline()
if response:
print("设备响应:", response.decode('utf-8', errors='ignore').strip())
else:
print("等待超时,设备未响应")
except serial.SerialException as e:
print(f"串口通信异常: {e}")
except FileNotFoundError:
print(f"未找到指定端口: {port_name}")
七、常见问题排查与避坑指南
serial.SerialException 进行专门捕获并增加断线重连逻辑,这样当物理 USB 线缆被意外拔出或重新插上时,系统具备自动恢复能力。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













