4、串口通信基础:RS232/RS485协议原理、串口参数配置、pySerial库实战

串口通信,说白了就是设备之间最古老也最可靠的对话方式之一。我做了这么多年自动化控制,几乎每个项目都离不开它。你想想看,PLC、传感器、变频器、扫码枪……这些工业设备哪个不是靠串口在背后默默传数据?

今天我们就来把串口通信这层窗户纸捅破。从协议原理到参数配置,再到用Python的pySerial库实战,一条龙讲清楚。

4.1 RS232与RS485:两种最常用的串口协议

先说说这两个协议的区别。我刚开始入行时也搞混过,后来在项目里吃过亏才彻底弄明白。

4.1.1 RS232:点对点的老大哥

RS232是最早的串口标准。它的特点是:

  • 传输距离短:一般不超过15米。我在一个工厂里试过拉20米的线,数据就开始丢包了。
  • 速率不高:常见的是9600、19200、115200bps。再高就容易出错。
  • 全双工:可以同时收发数据,就像两个人同时说话也能听见对方。
  • 电压摆幅大:逻辑1是-3V到-15V,逻辑0是+3V到+15V。抗干扰能力还行。
我的经验:RS232最适合短距离、一对一通信。比如电脑连一个PLC,或者连一个串口打印机。别想着用它组网,它天生就是单打独斗的料。

4.1.2 RS485:工业现场的通信王者

RS485就不一样了。它是我在工业项目中最常用的协议,没有之一。

  • 传输距离远:理论1200米。我在一个污水处理厂里实测过,800米完全没问题。
  • 支持多节点:一条总线上可以挂32个设备(现在很多芯片支持256个)。
  • 差分信号:用两根线(A和B)传输,抗干扰能力极强。电机启动时电压波动那么大,数据照样稳。
  • 半双工:同一时间只能发或者收。需要程序控制收发切换。
注意:RS485总线两端必须加120欧姆的终端电阻。我曾经在一个项目中忘了加,结果总线反射严重,数据怎么都对不上。折腾了两天才找到原因。

4.2 串口参数配置:波特率、数据位、停止位

串口通信就像两个人约定好怎么说话。参数必须完全一致,否则就是鸡同鸭讲。

4.2.1 波特率(Baud Rate)

波特率就是每秒传输的符号数。说白了就是通信速度。

波特率 每秒传输字节数(近似) 适用场景
9600 约960字节 大多数工业设备默认值
19200 约1920字节 数据量稍大时使用
115200 约11520字节 高速传输,如固件升级

我个人习惯:能用9600就用9600。为什么?因为越高的波特率对线路质量要求越高。我在一个粉尘很大的车间里试过,115200根本跑不稳,降到9600就稳如老狗。

4.2.2 数据位(Data Bits)

数据位就是每个字节实际传输的数据位数。常见的有7位和8位。

  • 8位:最常用。传输一个完整的字节(0-255)。
  • 7位:老设备或ASCII码传输时用。比如一些老式打印机。

嗯,这里要注意:现在99%的设备都用8位数据位。除非你遇到古董设备,否则别纠结。

4.2.3 停止位(Stop Bits)

停止位是一个字节传输结束后的间隔。常见的有1位、1.5位和2位。

  • 1位:默认值,够用。
  • 2位:给设备更多时间处理数据。我在一些老旧的PLC上遇到过,必须设成2位才能稳定通信。

4.2.4 校验位(Parity)

校验位用于简单的错误检测。有三种:

  • 无校验(None):最常用。现在通信质量好了,很少需要校验。
  • 偶校验(Even):保证1的个数为偶数。
  • 奇校验(Odd):保证1的个数为奇数。
核心配置:大多数工业设备默认是 9600波特率、8数据位、1停止位、无校验。简写为 9600-8-N-1。记住这个组合,能解决80%的串口通信问题。

4.3 pySerial库实战:用Python搞定串口通信

理论说完了,咱们来点实际的。pySerial是Python操作串口的标配库。我所有自动化项目都用它。

4.3.1 安装与基本使用

# 安装
pip install pyserial

# 基本使用
import serial

# 打开串口
ser = serial.Serial(
    port='COM3',        # Windows下用COM口,Linux下用/dev/ttyUSB0
    baudrate=9600,      # 波特率
    bytesize=8,         # 数据位
    parity='N',         # 校验位:N无校验,E偶校验,O奇校验
    stopbits=1,         # 停止位
    timeout=1           # 超时时间(秒)
)

# 发送数据
ser.write(b'Hello, PLC!')

# 读取数据
data = ser.read(10)     # 读取10个字节
line = ser.readline()   # 读取一行

# 关闭串口
ser.close()

你看,就这么简单。但实际项目中坑不少。我来说几个。

4.3.2 避坑指南:我踩过的那些坑

坑一:忘记关闭串口
我曾经写过一个脚本,每次运行都打开串口但不关闭。结果第三次运行时串口就报错了。记住:用完后一定要 ser.close(),或者用 with 语句自动管理。
# 推荐写法:用with自动关闭
with serial.Serial('COM3', 9600, timeout=1) as ser:
    ser.write(b'AT\r\n')
    response = ser.readline()
    print(response)
# 退出with块后自动关闭
坑二:读写时序问题
RS485是半双工的,发完数据后不能立刻读。需要等设备处理完。我一般发完数据后 sleep 50-100毫秒再读。
import time

ser.write(b'\x01\x03\x00\x00\x00\x01\x84\x0A')
time.sleep(0.1)  # 给设备处理时间
response = ser.read(7)

4.3.3 实战:读取Modbus RTU设备数据

Modbus RTU是工业上最常用的串口协议。下面是一个完整的读取示例:

import serial
import time
from binascii import hexlify

def read_modbus_register(port, slave_id, register_addr, count=1):
    """
    读取Modbus RTU保持寄存器
    """
    # 构建读取命令
    # 功能码03:读取保持寄存器
    cmd = bytes([
        slave_id,           # 从站地址
        0x03,               # 功能码
        (register_addr >> 8) & 0xFF,  # 寄存器地址高字节
        register_addr & 0xFF,         # 寄存器地址低字节
        (count >> 8) & 0xFF,          # 读取数量高字节
        count & 0xFF                  # 读取数量低字节
    ])
    
    # 计算CRC校验(这里简化了,实际要用完整CRC算法)
    # 实际项目中请使用 crcmod 库
    crc = calculate_crc16(cmd)
    cmd += crc
    
    with serial.Serial(port, 9600, timeout=1) as ser:
        ser.write(cmd)
        time.sleep(0.1)
        
        # 读取响应
        # 响应格式:从站地址 + 功能码 + 数据长度 + 数据 + CRC
        response = ser.read(5 + count * 2)
        
        if len(response) >= 3:
            data_length = response[2]
            data = response[3:3+data_length]
            return data
    
    return None

# 使用示例
data = read_modbus_register('COM3', 1, 0x0000, 2)
if data:
    print(f"读取到的数据: {hexlify(data).decode()}")
我的建议:调试串口通信时,先用串口调试助手(比如SSCOM、Putty)手动发命令看看设备返回什么。确认没问题了再写代码。这样能省下大量排错时间。

4.4 本章知识体系

下面这张图把串口通信的核心知识点串起来了:

串口通信知识体系 串口通信 协议原理 参数配置 RS232:点对点、全双工、短距离 RS485:多节点、半双工、长距离 波特率:9600/19200/115200 数据位/停止位/校验位 pySerial实战 打开/发送/读取/关闭 Modbus RTU协议读取示例

串口通信说白了就是三个环节:选对协议、配好参数、写好代码。每个环节都有坑,但只要你按我说的来,基本不会出大问题。

嗯,今天就先讲到这里。记住:调试串口时,先确认硬件连接,再检查参数配置,最后才怀疑代码。这个顺序能帮你省下大量时间。


公众号:蓝海资料掘金营,微信deep3321