Files
cjgc_data/ck
..
2026-03-12 17:03:56 +08:00
2026-03-12 17:03:56 +08:00
2026-03-12 17:03:56 +08:00
2026-03-12 17:03:56 +08:00
2026-03-12 17:03:56 +08:00
2026-03-12 17:03:56 +08:00

串口通信协议

一个完整的Python串口通信协议实现支持两台设备之间可靠的数据传输可传输结构化数据用户名、线路名称、站点编号等

特性

  • 完整的协议帧结构 - 包含帧头、长度、命令、数据、CRC校验、帧尾
  • CRC16校验 - 使用CRC-16/MODBUS算法确保数据完整性
  • 异步接收 - 多线程接收,不阻塞主程序
  • 多种命令类型 - 心跳、数据传输、控制命令、应答等
  • 结构化数据 - 支持JSON格式的站点数据传输用户名、线路名称、站点编号
  • 易于使用 - 简洁的API开箱即用

协议帧格式

+------+------+--------+------+--------+------+
| HEAD | LEN  |  CMD   | DATA |  CRC   | TAIL |
+------+------+--------+------+--------+------+
| 0xAA | 2B   |  1B    | N字节 |  2B    | 0x55 |
+------+------+--------+------+--------+------+

字段说明

  • HEAD: 帧头标识 (1字节, 0xAA)
  • LEN: 数据长度 (2字节, 大端序, 包含CMD+DATA)
  • CMD: 命令字 (1字节)
  • DATA: 数据内容 (N字节)
  • CRC: CRC16校验 (2字节, 大端序)
  • TAIL: 帧尾标识 (1字节, 0x55)

安装

pip install -r requirements.txt

命令类型

命令 说明
HEARTBEAT 0x01 心跳包
DATA_QUERY 0x02 数据查询
DATA_RESPONSE 0x03 数据响应
CONTROL 0x04 控制命令
ACK 0x05 应答
NACK 0x06 否定应答

站点数据模型

StationData 类

用于传输站点信息的数据模型:

from data_models import StationData

# 创建站点数据
station = StationData(
    username="张三",      # 用户名
    line_name="1号线",    # 线路名称
    station_no=5          # 第几站
)

# 序列化为字节(用于发送)
data_bytes = station.to_bytes()

# 从字节反序列化(接收后解析)
restored = StationData.from_bytes(data_bytes)

使用方法

基本示例

from serial_protocol import SerialProtocol, Command

# 创建协议实例
device = SerialProtocol(port='COM1', baudrate=115200)

# 打开串口
if device.open():
    # 发送数据
    device.send_data(b"Hello, World!")
    
    # 发送心跳
    device.send_heartbeat()
    
    # 发送控制命令
    device.send_control(0x10, b"\x01\x02")
    
    # 关闭串口
    device.close()

异步接收数据

def on_receive(cmd, data):
    print(f"收到命令: 0x{cmd:02X}, 数据: {data.hex()}")

device = SerialProtocol(port='COM1', baudrate=115200)
device.open()

# 启动接收线程
device.start_receive(on_receive)

# ... 主程序运行 ...

device.close()

完整示例

设备A (发送端)

运行 device_a.py设备A会定期发送

  • 心跳包
  • 站点数据(包含用户名、线路名称、站点编号)
  • 接收设备B的字典响应

输出示例:

============================================================
循环 1
============================================================
✓ 发送心跳包

准备发送站点数据:
  用户: 李四, 线路: 2号线, 站点: 第1站
✓ 站点数据发送成功

[设备A] 收到数据:
  命令: 0x03 (DATA_RESPONSE)

  📥 收到设备B的响应字典:
     1: "李四"
     2: "2号线"
     3: "1"
     4: "已接收"
     5: "设备B确认"

运行命令:

python device_a.py

设备B (接收端)

运行 device_b.py设备B会

  • 接收站点数据并解析显示
  • 自动应答心跳包
  • 返回统一格式的响应字典 {1:"xxx", 2:"xxx", 3:"xxx", ...}

输出示例:

============================================================
[设备B] 收到数据
============================================================
命令类型: 0x03 (DATA_RESPONSE)

📍 站点数据详情:
   用户名称: 李四
   线路名称: 2号线
   站点编号: 第1站

📤 设备B统一响应格式:
   1: "李四"
   2: "2号线"
   3: "1"
   4: "已接收"
   5: "设备B确认"

<<< 已发送响应字典

运行命令:

python device_b.py

设备B统一响应格式

设备B接收到站点数据后会返回统一格式的字典响应

{
    1: "用户名",
    2: "线路名称", 
    3: "站点编号",
    4: "已接收",
    5: "设备B确认"
}

字段说明:

  • 1: 接收到的用户名
  • 2: 接收到的线路名称
  • 3: 接收到的站点编号(字符串)
  • 4: 固定值 "已接收"
  • 5: 固定值 "设备B确认"

硬件连接

方案1: 使用两个USB转串口模块

设备A (COM1)  <---RX/TX交叉--->  设备B (COM2)
    TX  ---------------------->  RX
    RX  <----------------------  TX
   GND  <--------------------->  GND

方案2: 使用虚拟串口 (测试用)

Windows: 使用 com0com 或 Virtual Serial Port Driver Linux: 使用 socat

# Linux创建虚拟串口对
socat -d -d pty,raw,echo=0 pty,raw,echo=0
# 会创建 /dev/pts/X 和 /dev/pts/Y

API文档

SerialProtocol 类

初始化

SerialProtocol(port: str, baudrate: int = 115200, timeout: float = 1.0)

方法

  • open() -> bool - 打开串口
  • close() - 关闭串口
  • send_frame(cmd: int, data: bytes) -> bool - 发送数据帧
  • receive_frame() -> Optional[dict] - 接收数据帧(阻塞)
  • start_receive(callback) - 启动异步接收
  • stop_receive() - 停止异步接收
  • send_heartbeat() -> bool - 发送心跳包
  • send_data(data: bytes) -> bool - 发送数据
  • send_control(code: int, params: bytes) -> bool - 发送控制命令
  • send_ack() -> bool - 发送应答
  • send_nack() -> bool - 发送否定应答

静态方法

  • calc_crc16(data: bytes) -> int - 计算CRC16校验值
  • build_frame(cmd: int, data: bytes) -> bytes - 构建数据帧
  • parse_frame(frame: bytes) -> Optional[dict] - 解析数据帧

常见问题

1. 如何修改串口号?

编辑 device_a.pydevice_b.py,修改 port 参数:

  • Windows: 'COM1', 'COM2', etc.
  • Linux: '/dev/ttyUSB0', '/dev/ttyS0', etc.

2. 如何修改波特率?

修改 baudrate 参数常用值9600, 19200, 38400, 57600, 115200

3. 数据长度限制?

理论最大65535字节但建议单帧数据不超过1024字节以提高可靠性。

4. 如何处理超时?

设置 timeout 参数控制读取超时时间。

应用场景

  • 🤖 机器人通信
  • 📡 传感器数据采集
  • 🎮 设备控制
  • 📊 工业自动化
  • 🔌 嵌入式系统互联

许可证

MIT License

作者

Created with ❤️ for reliable serial communication