第2章:Python与硬件通信基础:认识串口(RS232/RS485)、Python的serial库安装与基础用法
好,咱们正式开始动手了。
上一章我们聊了光谱仪自动进样系统的整体架构。你可能已经跃跃欲试,想赶紧写代码控制硬件。别急,在写代码之前,有一道绕不开的坎——串口通信。
说白了,你电脑跟光谱仪、进样器、注射泵这些设备怎么说话?就是靠串口。我做了这么多年自动化,90%的仪器控制项目,底层都是串口在干活。今天咱们就把串口这层窗户纸捅破。
2.1 串口是什么?RS232和RS485的区别
串口,全称串行通信接口。它一次只传一个比特,像排队过独木桥。听起来慢,但胜在简单可靠。
工业现场最常见的两种串口标准:RS232 和 RS485。
| 特性 | RS232 | RS485 |
|---|---|---|
| 传输方式 | 单端(不平衡) | 差分(平衡) |
| 最大距离 | 约15米 | 约1200米 |
| 最大节点数 | 1对1 | 最多256个节点 |
| 电压范围 | ±3V ~ ±15V | ±1.5V ~ ±6V |
| 抗干扰能力 | 弱 | 强 |
| 常见应用 | 老式PC、调试口 | 工业总线、仪器网络 |
我个人习惯:短距离、一对一、调试阶段,用RS232。比如你桌上那台光谱仪,多半就是RS232接口。长距离、多设备、现场布线,用RS485。比如进样器、注射泵、阀门组挂在一条总线上。
2.2 串口通信的三要素
串口通信要想通,三个参数必须对得上。就像对暗号,错一个都不行。
- 波特率(Baud Rate):每秒传输的符号数。常见的有9600、19200、115200。光谱仪一般用9600或115200。我建议你直接看设备手册,别猜。
- 数据位(Data Bits):一般是8位。老设备可能有7位,但很少见了。
- 停止位(Stop Bits):1位或2位。绝大多数设备用1位。
还有一个经常被忽略的——校验位(Parity)。None、Even、Odd三种。None最常见。如果通信不稳定,可以试试Even。
2.3 Python的serial库安装
Python操作串口,靠的是 pyserial 这个库。它封装了底层的系统调用,你只需要几行代码就能收发数据。
安装很简单,打开终端或命令行,敲一行命令:
pip install pyserial
如果你用的是Anaconda环境,也可以:
conda install -c conda-forge pyserial
装完之后,验证一下:
python -c "import serial; print(serial.__version__)"
如果能打印出版本号,恭喜你,环境搭好了。
python -m pip install pyserial 确保安装到当前Python解释器。
2.4 serial库基础用法:打开、读写、关闭
好,现在咱们写第一段串口代码。目标:打开串口,发一条命令,收一条回复。
import serial
# 打开串口
ser = serial.Serial(
port='COM3', # Windows下是COM口,Linux下是/dev/ttyUSB0
baudrate=9600,
bytesize=8,
parity='N',
stopbits=1,
timeout=1 # 超时时间,单位秒
)
# 检查是否打开成功
if ser.is_open:
print(f"串口 {ser.port} 已打开")
# 发送数据(需要编码成bytes)
ser.write(b'*IDN?\n') # 很多仪器用 *IDN? 查询身份
# 读取数据
response = ser.readline() # 读取一行,直到换行符
print(f"收到: {response.decode().strip()}")
# 关闭串口
ser.close()
print("串口已关闭")
这段代码麻雀虽小,五脏俱全。我解释几个关键点:
- port:串口号。Windows去设备管理器里看,Linux用
ls /dev/ttyUSB*或ls /dev/ttyACM*找。 - timeout:这个参数很重要。不设的话,
readline()会一直等,程序就卡死了。我一般设1秒,够用。 - 编码:串口传的是字节,不是字符串。所以发送前要
.encode()或直接写b'...',收到后要.decode()。
2.5 常用方法速查
除了上面用的 write 和 readline,还有几个方法你迟早会用上:
| 方法 | 说明 | 示例 |
|---|---|---|
ser.read(n) |
读取n个字节 | data = ser.read(10) |
ser.read_until(expected) |
读到指定字节为止 | data = ser.read_until(b'\n') |
ser.in_waiting |
缓冲区中等待读取的字节数 | if ser.in_waiting > 0: ... |
ser.flush() |
清空输入输出缓冲区 | ser.flush() |
ser.close() |
关闭串口 | ser.close() |
我个人最常用的是 read_until。为什么?因为很多仪器的响应以换行符 \n 或回车换行 \r\n 结尾。用 read_until 可以完整地拿到一条消息,不会半截断开。
2.6 一个完整的实战例子:查询光谱仪状态
假设你面前有一台光谱仪,串口参数是:COM5、115200、8、N、1。我们写一段代码,查询它的状态。
import serial
import time
def query_spectrometer(command):
"""发送命令并返回响应"""
try:
with serial.Serial('COM5', 115200, timeout=2) as ser:
ser.write(command.encode() + b'\r\n')
time.sleep(0.1) # 给设备一点反应时间
response = ser.read_until(b'\n')
return response.decode().strip()
except serial.SerialException as e:
print(f"串口错误: {e}")
return None
# 查询设备型号
model = query_spectrometer("*IDN?")
print(f"设备型号: {model}")
# 查询当前波长
wavelength = query_spectrometer(":SENSE:WAVELENGTH?")
print(f"当前波长: {wavelength} nm")
你想想看,这段代码里我用了 with 语句。好处是:不管代码是否报错,串口都会自动关闭。省得你忘了关串口,下次运行时报“端口被占用”。
try...finally 确保关闭。
2.7 小结
这一章我们干了三件事:
- 搞懂了RS232和RS485的区别——一个短距离一对一,一个长距离多节点。
- 装好了pyserial库——一行pip命令搞定。
- 写了第一段串口通信代码——打开、发送、接收、关闭。
下一章,我们会深入设备协议,教你如何解析光谱仪返回的数据。说白了,串口只是管道,真正的内容在协议里。到时候你会看到,原来仪器返回的是一串有规律的字符串,我们要做的就是把它变成能用的数值。
嗯,今天就到这儿。动手试试吧,把代码跑起来,你会觉得串口这东西,其实没那么神秘。