first commit
This commit is contained in:
292
ck/README.md
Normal file
292
ck/README.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# 串口通信协议
|
||||
|
||||
一个完整的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
|
||||
Reference in New Issue
Block a user