第4章:串口通信实战——扫描可用串口、配置参数、打开/关闭串口
串口通信,说白了就是让电脑和光谱仪“说上话”。
我刚开始做自动进样系统时,最头疼的就是串口连不上。后来发现,90%的问题都出在串口参数没配对上。这一章,咱们就把串口通信的底裤扒干净。
4.1 扫描可用串口——别让设备“隐身”
你想想看,光谱仪插上USB转串口线后,它在电脑里到底叫啥名字?
Windows里可能是 COM3、COM5,Linux里可能是 /dev/ttyUSB0。手动去设备管理器里翻,太慢了。我习惯用代码自动扫一遍。
核心思路:调用系统API,枚举所有可用的串口设备。
Python里最常用的库是 pyserial 自带的 serial.tools.list_ports。
import serial.tools.list_ports
def scan_serial_ports():
"""扫描并打印所有可用串口"""
ports = serial.tools.list_ports.comports()
if not ports:
print("没有发现可用串口。请检查连接。")
return []
print(f"发现 {len(ports)} 个串口:")
for port in ports:
print(f" 端口: {port.device}")
print(f" 描述: {port.description}")
print(f" 硬件ID: {port.hwid}")
print("-" * 40)
return ports
# 调用扫描
available_ports = scan_serial_ports()
我在项目中遇到过一个问题:有些USB转串口线插上后,系统能识别但 list_ports 返回空。后来发现是驱动没装好。嗯,这里要注意——先装驱动,再插线,顺序反了容易出幺蛾子。
小技巧:如果扫描结果为空,试试拔插USB线,或者换个USB口。有些劣质HUB会导致串口“假死”。
4.2 配置串口参数——对不上号就“哑巴”
串口通信就像两个人打电话,必须用同一个“语言”。这个语言由四个参数决定:
| 参数 | 常见值 | 说明 |
|---|---|---|
| 波特率 | 9600, 19200, 115200 | 每秒传输的比特数。光谱仪常用9600或115200 |
| 数据位 | 7, 8 | 一帧数据中有效数据的位数。绝大多数设备用8位 |
| 停止位 | 1, 1.5, 2 | 帧结束标志。常用1位停止位 |
| 校验位 | None, Even, Odd | 检错方式。无校验(None)最常见 |
我曾经调试一台老款光谱仪,折腾了两小时连不上。最后发现它的波特率是 19200,而我默认设成了9600。说白了,就是鸡同鸭讲。
配置代码很简单,但参数必须和设备手册一致:
import serial
def configure_serial(port_name, baudrate=9600, bytesize=8,
parity='N', stopbits=1, timeout=1):
"""
配置并打开串口
:param port_name: 串口名,如 'COM3' 或 '/dev/ttyUSB0'
:param baudrate: 波特率
:param bytesize: 数据位
:param parity: 校验位 'N'无 'E'偶 'O'奇
:param stopbits: 停止位
:param timeout: 读取超时(秒)
:return: serial.Serial 对象
"""
try:
ser = serial.Serial(
port=port_name,
baudrate=baudrate,
bytesize=bytesize,
parity=parity,
stopbits=stopbits,
timeout=timeout
)
print(f"串口 {port_name} 配置成功!")
print(f" 参数: {baudrate}/{bytesize}/{parity}/{stopbits}")
return ser
except serial.SerialException as e:
print(f"串口配置失败: {e}")
return None
# 示例:配置光谱仪常用参数
ser = configure_serial('COM3', baudrate=115200, bytesize=8,
parity='N', stopbits=1)
注意:配置参数时,parity 参数在 pyserial 里用字符串表示:'N' 无校验,'E' 偶校验,'O' 奇校验。大小写敏感,别写错了。
4.3 打开与关闭串口——优雅地“挂电话”
串口是独占资源。一个程序打开了,别的程序就不能再用。所以用完一定要关掉,不然下次打开会报错。
我见过有人写代码只开不关,结果程序崩溃后串口一直占着,只能重启电脑。嗯,这很坑。
正确的做法是:
import serial
import time
def open_and_close_demo():
"""演示串口的打开与关闭"""
# 打开串口
ser = serial.Serial('COM3', 115200, timeout=1)
if ser.is_open:
print(f"串口 {ser.port} 已打开")
print(f"当前参数: {ser.baudrate}/{ser.bytesize}/{ser.parity}/{ser.stopbits}")
# 这里做你的通信操作
# ser.write(b'AT\r\n')
# response = ser.readline()
# 模拟工作2秒
time.sleep(2)
# 关闭串口
ser.close()
print(f"串口 {ser.port} 已关闭")
else:
print("串口打开失败")
# 更推荐的方式:使用 with 语句自动管理
def safe_serial_operation():
"""使用 with 语句,自动关闭串口"""
with serial.Serial('COM3', 115200, timeout=1) as ser:
print(f"串口 {ser.port} 已打开,开始工作...")
# 你的通信代码写在这里
# 即使发生异常,with 块结束后也会自动关闭
pass
print("串口已自动关闭")
最佳实践:永远使用 with 语句操作串口。它会在代码块结束后自动调用 close(),哪怕中间出了异常。这比手动 try-finally 更简洁。
4.4 完整实战——扫描+配置+开关一条龙
把上面三块拼起来,就是一个完整的串口初始化流程:
import serial
import serial.tools.list_ports
def auto_connect_spectrometer(target_description=None):
"""
自动扫描并连接光谱仪
:param target_description: 可选,根据描述筛选设备
:return: 串口对象或 None
"""
# 1. 扫描可用串口
ports = serial.tools.list_ports.comports()
if not ports:
print("未发现任何串口设备")
return None
# 2. 筛选目标设备
target_port = None
for port in ports:
print(f"发现: {port.device} - {port.description}")
if target_description and target_description in port.description:
target_port = port.device
print(f" -> 匹配目标设备: {target_port}")
break
if not target_port:
# 如果没有指定筛选条件,默认用第一个
target_port = ports[0].device
print(f"未指定筛选条件,使用第一个串口: {target_port}")
# 3. 配置并打开串口
try:
ser = serial.Serial(
port=target_port,
baudrate=115200, # 光谱仪常用波特率
bytesize=8,
parity='N',
stopbits=1,
timeout=2
)
print(f"成功连接到 {target_port}")
return ser
except serial.SerialException as e:
print(f"连接失败: {e}")
return None
# 使用示例
ser = auto_connect_spectrometer(target_description="USB Serial Port")
if ser:
# 通信完成后关闭
ser.close()
print("串口已关闭,资源释放完毕")
避坑指南:我曾经在调试时发现,某些光谱仪在打开串口后会发送一段“握手信息”。如果你不读走它,后续的指令就会错位。所以打开串口后,建议先 ser.flushInput() 清空缓冲区。
4.5 常见问题与排查
- 串口扫描不到? 先看设备管理器里有没有。没有就是驱动问题,有但扫不到可能是权限问题(Linux下需要
sudo或加入dialout组)。 - 能打开但收不到数据? 检查波特率、数据位、停止位、校验位是否和设备一致。用示波器看TX/RX引脚有没有波形,最直接。
- 打开串口报“权限被拒绝”? Windows下可能是别的程序占用了(比如串口调试助手)。关掉其他程序再试。
- 数据乱码? 大概率是波特率不匹配。或者数据位/校验位设置错误。
嗯,串口通信就这么点事。但就是这点事,搞不定的话整个自动进样系统都动不了。下一章,咱们开始真正和光谱仪“对话”——发送指令、接收数据。