# 串口通信协议 一个完整的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) ## 安装 ```bash pip install -r requirements.txt ``` ## 命令类型 | 命令 | 值 | 说明 | | ----------- | ---- | -------------- | | HEARTBEAT | 0x01 | 心跳包 | | DATA_QUERY | 0x02 | 数据查询 | | DATA_RESPONSE | 0x03 | 数据响应 | | CONTROL | 0x04 | 控制命令 | | ACK | 0x05 | 应答 | | NACK | 0x06 | 否定应答 | ## 站点数据模型 ### StationData 类 用于传输站点信息的数据模型: ```python 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) ``` ## 使用方法 ### 基本示例 ```python 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() ``` ### 异步接收数据 ```python 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确认" ``` 运行命令: ```bash 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确认" <<< 已发送响应字典 ``` 运行命令: ```bash python device_b.py ``` ## 设备B统一响应格式 设备B接收到站点数据后,会返回统一格式的字典响应: ```python { 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 ```bash # Linux创建虚拟串口对 socat -d -d pty,raw,echo=0 pty,raw,echo=0 # 会创建 /dev/pts/X 和 /dev/pts/Y ``` ## API文档 ### SerialProtocol 类 #### 初始化 ```python 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.py` 和 `device_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