第3章:Python环境搭建与串口通信库
做嵌入式调试这么多年,我有个习惯——拿到一块新板子,第一件事就是看看串口能不能通。为什么?因为串口是嵌入式系统的「生命线」。你想想看,系统跑没跑起来、打印了什么信息、哪里卡住了,全得靠它。这一章,我们就来搞定Python环境下的串口通信。
3.1 Python环境搭建
我个人习惯用Python 3.8以上的版本。为什么?因为pySerial在3.8上跑得最稳,我踩过3.6的坑,有些旧版本对串口缓冲区的处理不太一样。
安装Python很简单,去官网下载安装包就行。但有个细节要注意——安装时记得勾选「Add Python to PATH」。我曾经帮一个同事排查了半天,结果发现他没勾这个选项,命令行里死活找不到python命令。
装好之后,打开命令行(Windows用cmd或PowerShell,Mac/Linux用终端),输入:
python --version
如果看到版本号,说明环境搭好了。嗯,这一步很简单,但很多人会卡在这里。
3.2 pySerial的安装
pySerial是Python操作串口的标配库。安装它只需要一行命令:
pip install pyserial
如果你用的是Python 3,可能需要用pip3:
pip3 install pyserial
装完之后,验证一下:
python -c "import serial; print(serial.__version__)"
如果输出版本号,比如3.5,那就搞定了。我记得有一次在Linux上装,系统自带的Python和pip版本不匹配,折腾了半天。后来发现用python3 -m pip install pyserial就能解决。
3.3 端口扫描——找到你的设备
拿到一块新板子,插上USB转串口线,系统里会多出一个端口。但端口号是多少?Windows上可能是COM3、COM5,Linux上可能是ttyUSB0、ttyAMA0。手动去设备管理器里翻?太慢了。
我写了个小脚本,专门用来扫描可用端口:
import serial.tools.list_ports
ports = serial.tools.list_ports.comports()
for port in ports:
print(f"端口: {port.device}")
print(f"描述: {port.description}")
print(f"硬件ID: {port.hwid}")
print("-" * 40)
跑一下,你会看到类似这样的输出:
端口: COM3
描述: USB Serial Port (COM3)
硬件ID: USB VID:PID=1A86:7523 SER=12345678 LOCATION=1-2
----------------------------------------
这里有个小技巧——看硬件ID。VID和PID是USB设备的身份标识。比如1A86:7523是CH340芯片的,067B:2303是PL2303的。我在项目中遇到过,同一个电脑插了两个不同厂家的串口线,光看端口号分不清谁是谁。这时候看硬件ID就一目了然。
3.4 基础读写操作——让数据流动起来
端口找到了,接下来就是打开它、读写数据。这是串口通信的核心。
先看一个最简单的例子:
import serial
# 打开串口
ser = serial.Serial(
port='COM3', # 端口号,根据实际情况改
baudrate=115200, # 波特率,常见的有9600、115200
timeout=1 # 超时时间,单位秒
)
# 发送数据
ser.write(b'Hello, World!\n')
# 读取数据
data = ser.readline()
print(f"收到: {data}")
# 关闭串口
ser.close()
这段代码看着简单,但有几个坑要注意。
第一个坑:波特率要匹配。 板子设的是115200,你这边用9600,收到的全是乱码。我刚开始做调试时,经常被这个问题搞晕。后来养成了习惯——先看板子的代码,确认波特率是多少。
第二个坑:超时设置。 timeout=1表示读数据时最多等1秒。如果不设超时,readline()会一直等下去,程序就卡死了。你想想看,要是板子突然不发了,你的程序就永远停在那了。
第三个坑:数据是字节流。 write()里传的是b'Hello',不是'Hello'。Python 3里字符串和字节串是两回事。我见过有人直接写ser.write('Hello'),结果报错TypeError。
3.5 实战:循环读取传感器数据
实际项目中,我们通常要持续读取数据。比如一个温度传感器,每秒发一次数据。代码可以这样写:
import serial
import time
ser = serial.Serial('COM3', 115200, timeout=1)
try:
while True:
# 读取一行数据
line = ser.readline()
if line:
# 去掉换行符,转成字符串
data = line.decode('utf-8').strip()
print(f"[{time.strftime('%H:%M:%S')}] {data}")
else:
# 超时了,没收到数据
print("等待数据中...")
except KeyboardInterrupt:
print("用户中断")
finally:
ser.close()
这里用try-finally保证串口一定能关闭。为什么?因为串口资源很宝贵,不关的话,下次再打开可能会报「端口被占用」。我在调试一个无人机飞控时,就因为忘了关串口,导致地面站软件连不上,排查了半天才发现是端口没释放。
3.6 常见问题与排查
串口通信出问题了怎么办?别慌,按这个顺序排查:
- 端口对不对? 用端口扫描脚本确认一下。
- 波特率对不对? 检查板子的配置。
- 接线对不对? TX接RX,RX接TX,GND接GND。我见过有人把TX接TX,结果数据发出去没人收。
- 权限够不够? Linux下记得加dialout组。
- 是不是被占用了? 关掉其他可能占用串口的软件,比如串口助手、IDE的串口监视器。
嗯,这套排查流程我用了十年,基本能解决90%的问题。
3.7 小结
这一章我们搞定了三件事:Python环境搭建、pySerial安装、端口扫描和读写操作。说白了,就是让电脑和板子能「说上话」。下一章,我们会深入解析传感器原始数据的格式,看看那些0和1背后到底藏着什么信息。
记住一句话:串口通了,调试就成功了一半。