2. Python串口通信:pySerial库安装、串口参数配置、读写操作
好,咱们进入正题。串口通信,说白了就是让电脑跟仪器「说上话」。做分析仪器的人,这关必须过。我当年第一次调一台气相色谱仪,折腾了一整天没反应,最后发现是波特率配错了——嗯,这种坑我踩过不少,今天一并告诉你。
2.1 pySerial库安装
Python操作串口,最常用的就是pySerial。这玩意儿轻量、稳定,我几乎所有项目都用它。
安装很简单,一行命令搞定:
pip install pyserial
如果你用的是Anaconda环境,也可以:
conda install pyserial
我个人习惯用pip,因为版本更新更快。装完之后,在Python里试试导入:
import serial
print(serial.__version__)
能打印出版本号,说明装好了。如果报错,大概率是pip没装对——检查一下你的Python环境是不是激活了。
python -m venv myenv 创建环境,再装库,干净又省心。
2.2 串口参数配置
串口通信不是插上线就能聊的。你得告诉电脑:用什么速度、多少数据位、有没有校验。这些参数必须跟仪器端完全一致,否则数据就是一堆乱码。
核心参数有这几个:
| 参数 | 说明 | 常见值 |
|---|---|---|
| 波特率 | 每秒传输的比特数 | 9600, 19200, 115200 |
| 数据位 | 每个字节的数据位数 | 7, 8 |
| 停止位 | 每个字节后的停止信号 | 1, 1.5, 2 |
| 校验位 | 错误检测方式 | None, Even, Odd |
| 超时 | 读取等待时间(秒) | 0.5, 1, None |
配置代码长这样:
import serial
ser = serial.Serial(
port='COM3', # Windows下是COM口,Linux下是/dev/ttyUSB0
baudrate=9600, # 波特率
bytesize=8, # 数据位
parity='N', # 无校验
stopbits=1, # 1位停止位
timeout=1 # 超时1秒
)
这里有个坑——端口号。Windows上你可以在设备管理器里查,Linux上用 ls /dev/tty*。我遇到过好几次,插拔USB后端口号变了,代码里写死的COM3就报错。后来我学乖了,用循环自动检测:
import serial.tools.list_ports
ports = serial.tools.list_ports.comports()
for port in ports:
print(f"发现端口: {port.device} - {port.description}")
2.3 读写操作
配置好了,就该收发数据了。读写操作是串口通信的核心,也是坑最多的地方。
2.3.1 写数据
写数据用 write() 方法。注意,它只接受字节类型,不能直接传字符串:
# 发送字符串
ser.write(b'AT\r\n') # 字节串
ser.write('AT\r\n'.encode()) # 字符串转字节
# 发送十六进制数据
ser.write(bytes([0x01, 0x03, 0x00, 0x00, 0x00, 0x01]))
我个人习惯用 encode(),因为代码可读性更好。但如果你跟仪器通信,很多仪器用的是Modbus协议,那就得用十六进制方式发送。
2.3.2 读数据
读数据有几种方式,看你的场景:
# 读取固定字节数
data = ser.read(10) # 读10个字节
# 读取一行(直到换行符)
line = ser.readline() # 读到 \n 为止
# 读取所有可用数据
data = ser.read_all() # 非阻塞,读缓冲区所有数据
# 循环读取
while True:
if ser.in_waiting > 0: # 检查是否有数据
data = ser.read(ser.in_waiting)
print(data.hex()) # 打印十六进制
这里有个关键点——超时设置。如果你设了timeout=1,read()最多等1秒。如果不设超时,read()会一直等下去,程序就卡死了。我刚开始做项目时就犯过这错,程序跑起来没反应,还以为是仪器坏了。
readline() 配合超时,这是最稳妥的方式。大多数仪器返回的数据都以换行符结尾,一行一行读,逻辑清晰,不容易丢数据。
2.3.3 完整示例
来个完整的读写示例,模拟跟一台分析仪器通信:
import serial
import time
# 配置串口
ser = serial.Serial(
port='COM3',
baudrate=9600,
bytesize=8,
parity='N',
stopbits=1,
timeout=1
)
# 发送查询命令
command = b'READ_DATA\r\n'
ser.write(command)
print(f"发送: {command}")
# 等待仪器响应
time.sleep(0.5)
# 读取响应
response = ser.readline()
print(f"收到: {response.decode().strip()}")
# 关闭串口
ser.close()
你想想看,这个流程是不是很清晰?发送命令、等待、读取、关闭。实际项目中,我会把这段逻辑封装成函数,方便反复调用。
2.4 常见问题与避坑指南
做串口通信,问题千奇百怪。我挑几个最常见的说说:
- 端口被占用: 程序崩溃后没关串口,下次运行就报错。解决办法:用
try...finally确保关闭,或者重启电脑。 - 数据乱码: 多半是波特率或数据位不匹配。我曾经遇到过,仪器用7位数据位,我设成8位,结果读出来的数据全是错的。
- 读取超时: 仪器没发数据,或者发的格式不对。建议先用串口调试助手(比如Putty)手动发命令,确认仪器正常再写代码。
- 粘包问题: 仪器连续发多条数据,readline()可能一次读到多条。解决办法:用固定帧头帧尾来分包,或者加时间戳判断。
time.sleep(0.1),给仪器一点反应时间。别问我怎么知道的——都是血泪教训。
2.5 小结
好了,串口通信这块就讲这么多。总结一下:
- 安装pySerial用pip,简单直接
- 配置参数要跟仪器完全一致,尤其是波特率
- 写数据用write(),读数据用readline()最稳
- 别忘了设超时,别忘了关串口
下一章咱们讲数据记录——怎么把串口收到的数据存到文件里。嗯,那又是另一番天地了。