4. 串口参数配置实战:波特率、数据位、停止位、校验位、超时时间的配置与测试
串口通信的参数配置,说白了就是让两个设备约定好「怎么说话」。我刚开始做嵌入式那会儿,总觉得这些参数随便填就行,结果经常收到一堆乱码。后来才明白——收发双方的参数必须完全一致,差一点都不行。
这一节,咱们把五个核心参数掰开揉碎讲清楚。你跟着我走一遍,以后配置串口再也不会翻车。
4.1 波特率:通信的「节拍器」
波特率(Baud Rate)定义的是每秒传输多少个符号。在串口里,一个符号就是一个比特,所以波特率就等于比特率。
| 波特率(bps) | 典型应用场景 | 优缺点 |
|---|---|---|
| 9600 | 工业仪表、GPS模块、老旧设备 | 稳定可靠,抗干扰强,但速度慢 |
| 115200 | 调试输出、传感器数据、WiFi模块 | 速度适中,兼容性好,最常用 |
| 921600 | 高速数据传输、固件升级 | 速度快,但线长超过1米容易丢包 |
| 3000000+ | 芯片内部调试、短距离高速通信 | 极快,对硬件和线缆要求极高 |
我的习惯:调试阶段一律用115200。这个速率在大多数USB转串口芯片上表现最稳定,而且Python的serial库对这个速率支持最好。等产品定型了再根据实际需求调整。
配置波特率在Python里就一行代码:
import serial
ser = serial.Serial(
port='COM3',
baudrate=115200, # 波特率
timeout=1
)
嗯,这里要注意——波特率不是越高越好。我曾经在一个项目里为了追求速度,把波特率设到了2Mbps,结果线缆稍微长一点就开始丢数据。后来老老实实降到460800,问题全解决了。
4.2 数据位:一帧里装多少数据
数据位(Data Bits)决定每个字节实际传输多少位。常见的有7位和8位。
- 8位数据位:最常用,能表示0-255的完整字节。ASCII字符、二进制数据都用这个。
- 7位数据位:老式设备或特殊协议用,只能表示0-127。比如某些工业PLC还在用7位。
- 5位、6位:基本绝迹了,只有极古老的设备才用。
避坑指南:我曾经接手过一个项目,设备一直发乱码。查了两天,最后发现设备用的是7位数据位,而我默认配了8位。你想想看,高位对不上,数据肯定全错。所以拿到新设备,第一件事就是确认数据位。
配置代码:
ser = serial.Serial(
port='COM3',
baudrate=115200,
bytesize=serial.EIGHTBITS, # 8位数据位
timeout=1
)
4.3 停止位:帧与帧之间的「休止符」
停止位(Stop Bits)告诉接收方「这一帧结束了」。常见的有1位、1.5位和2位。
| 停止位 | 说明 | 使用场景 |
|---|---|---|
| 1位 | 标准配置,开销最小 | 绝大多数现代设备 |
| 1.5位 | 特殊定时要求 | 某些老式电机控制器 |
| 2位 | 额外冗余,更稳定 | 长距离通信、噪声环境 |
我个人习惯:能用1位就不用2位。多一位停止位虽然更稳,但传输效率会下降约10%。除非你的通信环境特别恶劣,否则1位完全够用。
ser = serial.Serial(
port='COM3',
baudrate=115200,
bytesize=serial.EIGHTBITS,
stopbits=serial.STOPBITS_ONE, # 1位停止位
timeout=1
)
4.4 校验位:数据完整性的「安检员」
校验位(Parity Bit)用来检测传输过程中有没有发生错误。说白了就是加一个额外的比特,让整个帧里1的个数是奇数还是偶数。
- 无校验(N):不加校验位,效率最高。短距离、低噪声环境首选。
- 奇校验(O):让1的总数为奇数。能检测出奇数个位翻转。
- 偶校验(E):让1的总数为偶数。效果和奇校验一样,只是规则相反。
- 标记校验(M):校验位固定为1。很少用。
- 空格校验(S):校验位固定为0。也很少用。
实战建议:大多数场景用「无校验」就够了。如果通信环境有干扰,优先用偶校验——因为很多工业协议默认就是偶校验,兼容性更好。
配置代码:
ser = serial.Serial(
port='COM3',
baudrate=115200,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE, # 无校验
stopbits=serial.STOPBITS_ONE,
timeout=1
)
4.5 超时时间:别让程序死等
超时(Timeout)是串口编程里最容易忽略、也最容易出问题的参数。它决定了read()函数最多等多久。
| 超时设置 | 行为 | 适用场景 |
|---|---|---|
timeout=None |
一直等,直到收到指定字节数 | 数据量确定、不会丢包的场景 |
timeout=0 |
非阻塞模式,立即返回 | 轮询读取、实时性要求高 |
timeout=N |
最多等N秒,超时返回已收到的数据 | 最常用,兼顾实时性和可靠性 |
我曾经踩过的坑:有次写一个自动测试脚本,没设超时。结果设备突然掉线,程序卡在
read()那里一动不动,整个测试流程全停了。从那以后,我所有串口程序都强制设超时,哪怕设个0.1秒也比不设强。
我的推荐配置:
ser = serial.Serial(
port='COM3',
baudrate=115200,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=1 # 1秒超时,够用又不会卡死
)
4.6 完整配置与测试流程
下面我把所有参数串起来,写一个完整的配置和测试脚本。你直接复制就能用。
import serial
import time
def configure_serial(port, baudrate=115200):
"""配置串口参数并返回串口对象"""
try:
ser = serial.Serial(
port=port,
baudrate=baudrate,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=1
)
print(f"[OK] 串口 {port} 已打开,参数:{baudrate} 8N1")
return ser
except serial.SerialException as e:
print(f"[ERROR] 打开串口失败:{e}")
return None
def test_communication(ser):
"""发送测试数据并检查回显"""
if ser is None:
return
test_data = b"Hello UART!\n"
ser.write(test_data)
print(f"[TX] 发送:{test_data}")
time.sleep(0.1) # 等设备处理
response = ser.read(ser.in_waiting)
print(f"[RX] 收到:{response}")
if response == test_data:
print("[PASS] 回显测试通过")
else:
print("[FAIL] 回显测试失败,请检查参数")
if __name__ == "__main__":
ser = configure_serial("COM3", 115200)
test_communication(ser)
if ser:
ser.close()
4.7 参数配置知识图谱
下面这张图帮你理清五个参数之间的关系。你一看就明白:
4.8 常见问题排查清单
配置完串口发现通信不正常?别慌,按这个清单一步步查:
- 检查波特率:两边是不是一样?差1bps都不行。
- 检查数据位:都是8位吗?7位和8位混用必出乱码。
- 检查停止位:1位还是2位?对不上会丢帧。
- 检查校验位:无校验、奇校验还是偶校验?这个最容易忽略。
- 检查超时:是不是设了
None导致程序卡死? - 检查硬件连接:TX接RX了吗?地线接了吗?
我的调试三板斧:第一,用示波器看波形,波特率对不对一眼就知道。第二,用串口助手先手动发数据,排除代码问题。第三,把超时设成0.5秒,避免程序卡死。这三招帮我解决了90%的串口问题。