Python Serial API完全指南:从零开始掌握串口通信,轻松实现设备交互
详解pyserial库使用、高级技巧与实战案例,解决你的串口编程难题)**

(Meta Description)
想用Python控制串口设备?本文手把手教你使用Python Serial API(pyserial库),从环境搭建、基础配置到高级参数设置、多线程通信,再到完整实战案例,一文带你精通串口编程,解决硬件交互难题,提升项目开发效率。
引言:为什么Python Serial API是硬件开发者的“利器”?
在物联网、嵌入式系统开发、工业自动化以及各类硬件原型验证项目中,计算机与外部设备(如单片机、传感器、GPS模块、调制解调器等)之间的通信是至关重要的一环,在这些通信方式中,串口通信因其协议简单、连接方便、稳定性高,至今仍被广泛应用。
而Python,凭借其简洁的语法、强大的生态和丰富的库支持,成为了连接软件世界与硬件世界的绝佳桥梁。pyserial 库(即我们常说的Python Serial API)是Python进行串口通信事实上的标准,它封装了复杂的底层操作,让我们只需几行代码就能实现与串口设备的双向数据交换。
无论你是刚入门的爱好者,还是经验丰富的工程师,本文都将为你提供一份详尽的、可操作的pyserial使用手册,助你攻克串口编程的难关。
准备工作:安装与配置你的Python Serial环境
在开始编码之前,我们需要确保开发环境已准备就绪。
1 安装pyserial库
pyserial库可以通过Python的包管理器pip轻松安装,打开你的终端或命令提示符,运行以下命令:
pip install pyserial
为了验证安装是否成功,可以在Python交互式环境中尝试导入该库:
import serial print(serial.__version__) # 打印版本号,若无报错则安装成功
2 硬件准备:找到你的COM端口
你的设备需要通过串口线(或USB转串口模块)连接到计算机,在编写代码前,你必须知道设备在计算机上被识别为哪个COM端口。
- Windows系统:
- 打开“设备管理器”。
- 展开“端口 (COM和LPT)”。
- 查看你的设备对应的COM端口号(如
COM3,COM4等)。
- Linux/macOS系统:
- 通常设备会被识别为
/dev/ttyUSB0,/dev/ttyACM0或/dev/ttyS0等文件名,你可以使用ls /dev/tty*命令来列出所有串口设备。
- 通常设备会被识别为
提示:记下这个端口号,它将在我们的代码中频繁使用。
核心入门:5分钟掌握Python Serial API基础用法
pyserial的使用非常直观,核心流程可以概括为:打开串口 -> 配置参数 -> 读写数据 -> 关闭串口。
1 打开与关闭串口
serial.Serial() 是创建串口对象的核心函数。
import serial
# --- 打开串口 ---
# 假设我们的设备在Windows上是COM3,在Linux上是/dev/ttyUSB0
ser = serial.Serial(
port='COM3', # 串口号
baudrate=9600, # 波特率,必须与设备端一致
bytesize=serial.EIGHTBITS, # 数据位
parity=serial.PARITY_NONE, # 校验位
stopbits=serial.STOPBITS_ONE, # 停止位
timeout=1 # 超时时间(秒)
)
# 检查串口是否成功打开
if ser.is_open:
print(f"串口 {ser.name} 打开成功!")
print(f"当前设置: {ser}")
else:
print("串口打开失败!")
# --- 关闭串口 ---
ser.close()
if not ser.is_open:
print("串口已关闭。")
关键参数解析:
port: 串口号。baudrate: 波特率(如 9600, 115200),通信双方必须完全一致。timeout: 超时设置,这是非常重要的一个参数,它决定了read()方法等待数据的最长时间。timeout=0:立即返回,不阻塞。timeout=1:等待最多1秒,1秒后若无数据则返回已读取的数据(若无则返回空)。timeout=None:无限期等待,直到有数据到达。
2 写数据到串口
使用write()方法向设备发送数据。注意:write()方法接收的是字节流,因此字符串需要先编码。
import serial
ser = serial.Serial('COM3', 9600, timeout=1)
ser.open()
if ser.is_open:
# 发送字符串,需要编码为字节
message_to_send = "Hello, Device!"
ser.write(message_to_send.encode('utf-8'))
print(f"已发送: {message_to_send}")
# 也可以直接发送字节
# ser.write(b'\x01\x02\x03') # 发送十六进制数据
ser.close()
3 从串口读取数据
使用read()方法从设备读取数据。
import serial
ser = serial.Serial('COM3', 9600, timeout=1)
ser.open()
if ser.is_open:
# read(size=1): 读取指定大小的字节,如果timeout超时则返回已读取的部分
data = ser.read(10) # 读取10个字节
print(f"读取到数据: {data}")
# readline(): 读取一行,以换行符(\n)为结束
# ser.reset_input_buffer() # 清空输入缓冲区
# line = ser.readline()
# print(f"读取到一行: {line.decode('utf-8').strip()}")
# readall(): 读取缓冲区中所有可用数据
# all_data = ser.readall()
# print(f"读取到所有数据: {all_data}")
ser.close()
进阶技巧:玩转串口通信的“高级操作”
掌握了基础操作后,让我们来探索一些能让你的程序更健壮、更高效的技巧。
1 正确处理数据:编码与解码
串口通信的本质是字节流,当你发送文本时,需要用.encode()将其转换为字节;接收到字节后,需要用.decode()将其转换回字符串。
# 发送
text = "你好,世界!"
ser.write(text.encode('gbk')) # 使用与设备端一致的编码,如utf-8, gbk等
# 接收
received_bytes = ser.read(10)
text = received_bytes.decode('gbk', errors='ignore') # 使用errors='ignore'解码错误字节
2 智能等待:让程序“听话”
直接使用read()可能会读到不完整的数据,一个常见的模式是:先发送一个指令,然后等待设备的响应数据。
def send_and_receive(command, expected_bytes=10):
ser.write(command.encode('utf-8'))
# 等待一小段时间,让设备有时间处理并发送数据
import time
time.sleep(0.5) # 延时时间需要根据设备响应速度调整
response = ser.read(expected_bytes)
return response
# 使用示例
ser = serial.Serial('COM3', 9600)
ser.open()
response = send_and_receive("GET_DATA")
print(f"设备响应: {response}")
ser.close()
3 多线程串口通信:避免程序卡死
如果你的主程序需要同时处理其他任务(如GUI界面更新),而串口读取又是阻塞的,那么使用多线程是最佳选择。
我们将创建一个专门的线程来负责监听和读取串口数据,主线程则可以自由执行其他操作。
import serial
import threading
import time
class SerialReader:
def __init__(self, port, baudrate):
self.ser = serial.Serial(port, baudrate, timeout=1)
self.running = False
self.thread = None
def start(self):
if not self.ser.is_open:
self.ser.open()
self.running = True
self.thread = threading.Thread(target=self._read_loop)
self.thread.daemon = True # 设置为守护线程,主线程退出时自动结束
self.thread.start()
print("串口监听线程已启动。")
def stop(self):
self.running = False
if self.thread and self.thread.is_alive():
self.thread.join()
if self.ser.is_open:
self.ser.close()
print("串口监听线程已停止。")
def _read_loop(self):
while self.running:
if self.ser.in_waiting > 0: # 检查缓冲区是否有数据
data = self.ser.readline()
print(f"接收到数据: {data.decode('utf-8').strip()}")
time.sleep(0.1) # 避免CPU空转
# --- 使用示例 ---
if __name__ == '__main__':
reader = SerialReader('COM3', 9600)
reader.start()
try:
# 主线程可以做其他事情,比如模拟用户输入
while True:
cmd = input("输入指令发送 (输入 'exit' 退出): ")
if cmd.lower() == 'exit':
break
reader.ser.write(cmd.encode('utf-8'))
except KeyboardInterrupt:
pass
finally:
reader.stop()
实战案例:用Python和Arduino实现一个简易温度监控
让我们通过一个完整的案例,将所学知识融会贯通。
目标:Arduino连接一个温度传感器(如LM35),通过串口每秒发送一次温度数据,Python程序读取这些数据,并在终端实时显示。
1 Arduino端代码
将以下代码上传到你的Arduino开发板:
void setup() {
// 初始化串口,波特率设置为9600
Serial.begin(9600);
}
void loop() {
// 读取模拟引脚A0的值 (0-1023)
int sensorValue = analogRead(A0);
// 将模拟值转换为电压值 (假设是5V供电)
float voltage = sensorValue * (5.0 / 1023.0);
// 将电压值转换为摄氏温度 (LM35: 10mV/°C)
float temperatureC = voltage * 100.0;
// 将温度数据通过串口发送
// 为了方便Python解析,我们使用逗号作为分隔符,并加上换行符
Serial.println(temperatureC);
// 等待1秒
delay(1000);
}
2 Python端代码
创建一个Python脚本(temperature_monitor.py)来接收并显示数据:
import serial
import time
def monitor_temperature(port, baudrate):
try:
# 创建串口对象
ser = serial.Serial(port, baudrate, timeout=1)
print(f"正在连接 {port}...")
if ser.is_open:
print("连接成功!开始监控温度...")
while True:
# 检查是否有数据到达
if ser.in_waiting > 0:
# 读取一行数据
line = ser.readline()
try:
# 尝试解码并转换为浮点数
temperature = float(line.decode('utf-8').strip())
print(f"当前温度: {temperature:.2f} °C")
except ValueError:
print(f"接收到无效数据: {line}")
# 短暂休眠,避免CPU占用过高
time.sleep(0.1)
except serial.SerialException as e:
print(f"串口错误: {e}")
except KeyboardInterrupt:
print("\n监控已停止。")
finally:
if 'ser' in locals() and ser.is_open:
ser.close()
print("串口已关闭。")
if __name__ == '__main__':
# 根据你的系统修改端口号
PORT = 'COM3' # Windows
# PORT = '/dev/ttyUSB0' # Linux
BAUDRATE = 9600
monitor_temperature(PORT, BAUDRATE)
运行结果: 当你运行Python脚本后,终端将每秒打印一次从Arduino传来的温度数据,实现了一个实时的温度监控系统。
常见问题与解决方案 (FAQ)
Q1: SerialException: could not open port 'COM3': Permission denied 怎么办?
A: 这通常是权限问题,在Linux/macOS上,普通用户可能没有访问串口设备的权限,你需要将用户添加到dialout组(sudo usermod -a -G dialout $USER),然后注销并重新登录,在Windows上,尝试以管理员身份运行你的Python IDE或脚本。
Q2: 为什么我读取到的数据是空的或者不完整?
A: 最常见的原因是timeout设置过短,或者设备发送数据的速度比你预期的慢,尝试增加timeout的值,或者在发送指令后加入一个短暂的time.sleep()来等待设备响应。
Q3: readline()为什么一直卡住?
A: readline()会一直读取,直到遇到换行符\n,如果你的设备没有发送换行符,或者数据中不包含换行符,它就会一直等待,确保你的设备端代码在发送数据后使用了println()(Arduino)或类似的函数来添加换行符。
Q4: 如何发送十六进制数据?
A: Python中,0x开头的整数表示十六进制,你可以使用bytes()函数将其转换为字节流。
发送 0x01, 0x02, 0x03:
ser.write(bytes([0x01, 0x02, 0x03]))
总结与展望
本文系统地介绍了Python Serial API(pyserial库)的使用方法,从环境搭建、基础读写,到多线程编程和实战项目,为你提供了从入门到精通的完整路径,掌握串口通信,你将能够自由地与各种硬件设备进行交互,极大地拓展你的项目边界。
随着技术的发展,USB、蓝牙、Wi-Fi等通信方式日益普及,但串口通信因其简单可靠,在特定领域依然不可替代,希望本文能成为你探索硬件世界的坚实第一步。就动手连接你的第一个串口设备,开始你的创作之旅吧!
延伸阅读与资源
- pyserial官方文档: https://pythonhosted.org/pyserial/ (最权威的参考资料)
- Python串口通信教程 (英文): https://realpython.com/python-serial-communication/
- Arduino官方串口参考: https://www.arduino.cc/reference/en/language/functions/communication/serial/
(文章结束)
