news 2026/10/18 1:16:20

Python连接串口并发送命令

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python连接串口并发送命令

在Python中,可以使用pyserial库来连接串口并发送命令。pyserial是一个用于串行通信的第三方库,支持多种平台。

首先,需要安装pyserial库。可以使用pip进行安装:

pip install pyserial

使用pyserial连接串口并发送命令

以下是一个示例代码,展示了如何使用pyserial连接串口并发送测试命令:

import serial import time def connect_serial(port, baudrate): try: # 创建Serial对象并打开串口 ser = serial.Serial(port, baudrate, timeout=1) print(f"成功连接到串口 {port},波特率 {baudrate}") return ser except serial.SerialException as e: print(f"无法连接到串口:{e}") return None def send_command(ser, command): if ser is not None: try: # 发送命令并添加换行符 ser.write((command + '\n').encode()) print(f"已发送命令:{command}") # 等待响应 time.sleep(1) # 读取响应数据 response = ser.read_all().decode() print(f"接收到的响应:{response}") except Exception as e: print(f"发送命令时发生错误:{e}") def close_serial(ser): if ser is not None: ser.close() print("已关闭串口") # 示例参数 port = "COM3" # Windows上的端口,例如 "COM3" # port = "/dev/ttyUSB0" # Linux上的端口,例如 "/dev/ttyUSB0" baudrate = 9600 # 波特率,根据实际情况设置 # 测试命令 command = "TEST_COMMAND" # 连接串口 ser = connect_serial(port, baudrate) # 发送测试命令 send_command(ser, command) # 关闭串口 close_serial(ser)

支持发送HEX格式的命令兼容代码参考

import serial import time def connect_serial(port, baudrate, timeout=1): """打开串口,返回 Serial 对象;失败返回 None。""" try: ser = serial.Serial(port, baudrate, timeout=timeout) print(f"成功连接到串口 {port},波特率 {baudrate}") return ser except serial.SerialException as e: print(f"无法连接到串口:{e}") return None def parse_hex(hex_str): """ 将 HEX 字符串解析为 bytes。 支持格式: "01 02 0A FF" "01020AFF" "0x01,0x02,0x0A" "01-02-0A-FF" """ # 去掉常见分隔符和 0x 前缀 cleaned = ( hex_str.strip() .replace("0x", "") .replace("0X", "") .replace(",", " ") .replace("-", " ") .replace(":", " ") ) cleaned = "".join(cleaned.split()) # 去掉所有空白 if len(cleaned) % 2 != 0: raise ValueError(f"HEX 字符串长度必须为偶数:{hex_str}") try: return bytes.fromhex(cleaned) except ValueError as e: raise ValueError(f"非法的 HEX 字符串:{hex_str}({e})") def send_command(ser, command, mode="ascii", append_newline=True): """ 向串口发送命令。 :param ser: 已打开的 Serial 对象 :param command: 命令内容。mode='ascii' 时为字符串;mode='hex' 时为 HEX 字符串 :param mode: 'ascii' 或 'hex' :param append_newline: 仅 ascii 模式有效;是否在末尾追加 '\n' """ if ser is None: print("串口未打开,无法发送。") return # ---------- 1. 把用户输入转换成字节流 ---------- try: if mode == "hex": payload = parse_hex(command) # HEX/二进制协议通常没有“换行符”概念,强制不追加 if append_newline: print("提示:HEX 模式下 append_newline 被忽略。") elif mode == "ascii": text = command + ("\n" if append_newline else "") payload = text.encode("utf-8") else: raise ValueError(f"不支持的模式:{mode},只能是 'ascii' 或 'hex'") except ValueError as e: print(f"命令解析失败:{e}") return # ---------- 2. 发送 ---------- try: ser.reset_input_buffer() # 清掉上一次残留,避免响应串台 ser.write(payload) ser.flush() # 确保数据真正写出 if mode == "hex": print(f"已发送 HEX:{payload.hex(' ').upper()}") else: print(f"已发送 ASCII:{command!r}") except Exception as e: print(f"发送命令时发生错误:{e}") return # ---------- 3. 读取响应 ---------- response = read_response(ser) if response: print(f"接收到的响应(HEX):{response.hex(' ').upper()}") # 尝试按文本显示,失败则跳过 try: print(f"接收到的响应(ASCII):{response.decode('utf-8')!r}") except UnicodeDecodeError: print("接收到的响应无法按 UTF-8 解码,仅显示 HEX。") else: print("未接收到响应(可能超时或设备无回复)。") def read_response(ser, idle_timeout=1.0, max_bytes=4096): """ 读取串口响应:在 idle_timeout 秒内没有新数据就认为读取结束。 比 time.sleep(1) + read_all() 更稳健。 """ data = bytearray() deadline = time.time() + idle_timeout last_rx = time.time() while time.time() < deadline and len(data) < max_bytes: waiting = ser.in_waiting if waiting: data.extend(ser.read(waiting)) last_rx = time.time() deadline = last_rx + idle_timeout # 每收到数据就重置空闲计时 else: time.sleep(0.01) return bytes(data) def close_serial(ser): if ser is not None and ser.is_open: ser.close() print("已关闭串口") # ==================== 示例 ==================== if __name__ == "__main__": port = "COM3" # Windows;Linux 用 "/dev/ttyUSB0" baudrate = 9600 ser = connect_serial(port, baudrate) if ser is None: raise SystemExit(1) try: # 示例 1:发送 ASCII 文本命令(自动加换行) send_command(ser, "TEST_COMMAND", mode="ascii", append_newline=True) # 示例 2:发送 HEX 命令(不带换行) # 等价于发送字节 0x01 0x03 0x00 0x00 0x00 0x0A 0xCD 0xC5 send_command(ser, "01 03 00 00 00 0A CD C5", mode="hex") # 示例 3:紧凑写法的 HEX send_command(ser, "01030000000ACDC5", mode="hex") finally: close_serial(ser)

原理说明:

原理说明

1. 串口发送的本质是字节流,不是字符串

ser.write()的参数必须是bytes/bytearray,不是str。原代码(command + '\n').encode()做的是两件事:

  • command + '\n':按文本协议的约定,在命令后追加换行符作为帧结束符;

  • .encode():按某种字符编码(默认 UTF-8)把字符串转成字节。

这套流程只适用于“人可读的文本命令”,例如AT+RST\r\n。一旦设备要求的是二进制/HEX 协议(例如 Modbus RTU 的01 03 00 00 00 0A CD C5),再走.encode()就会把字符'0'、'1'、空格等按 ASCII 编码发出去,得到的是b'01 03 ...'这串文本的 ASCII 字节,而不是真正的二进制帧。

2. HEX 模式的核心是bytes.fromhex()

bytes.fromhex()把"01 03 0A FF"这样的十六进制文本解析成真正的字节b'\x01\x03\x0a\xff'。它允许空格分隔,但不允许0x前缀、逗号、冒号等,所以parse_hex()先做一次规范化清洗:

  • 去掉0x/0X

  • 把,-:统一替换为空格

  • 去掉所有空白

  • 校验长度为偶数(每个字节两位十六进制)

这一步是 HEX 支持的关键:用户输入的是“十六进制表示”,程序要把它还原成“二进制字节”。

3. 为什么 HEX 模式不应自动追加\n

换行符是文本协议的帧分隔约定。二进制协议(Modbus、自定义帧、二进制指令)的帧边界通常由帧头、长度字段、校验码(CRC/LRC)或固定超时决定,而不是\n。如果强行在 HEX 帧后追加0x0A,会:

  • 破坏帧结构;

  • 导致 CRC 校验失败;

  • 让设备把0x0A当成下一帧的起始字节。

所以优化后的代码在mode='hex'时忽略append_newline,并给出提示。如果某些设备确实需要0x0D 0x0A结尾,应由调用者显式写进 HEX 字符串,例如"01 03 ... 0D 0A",这样语义清晰、可控。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 1:14:53

Paperless-ngx 实战指南:快速部署可全文检索的文档管理系统

Paperless-ngx 实战指南&#xff1a;快速部署可全文检索的文档管理系统 【免费下载链接】paperless-ngx A community-supported supercharged document management system: scan, index and archive all your documents 项目地址: https://gitcode.com/GitHub_Trending/pa/pa…

作者头像 李华
网站建设 2026/10/18 1:11:31

通过AgentScope在EKS部署远程沙盒与代理应用:TaoToken统一Key接入实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 1:11:16

muduo网络库--服务端视角核心流程与评价

1.核心流程 1.1.服务端视角 1.1.1.服务启动 流程 准备主EventLoop对象准备一个支持业务处理的BussinessServer&#xff0c;含TcpServer成员。TcpServer初始化。TcpServer启动 创建监听描述符注册可读监控设置新连接事件回调&#xff0c;设置收包回调TcpServer配置的线程数大于0…

作者头像 李华
网站建设 2026/10/18 1:10:12

逆向工程揭秘:Ampere GPU L2 Cache微架构探测与性能优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 1:09:37

ESP32-C3物联网开发实战:从选型到量产的工程经验总结

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华