您遇到的數據順序錯亂問題是由于**TCP協議本身的無邊界性和PLC緩沖區處理機制**共同導致的。以下是具體原因和解決方案:
---
### **問題根源分析**
1. **TCP流式協議特性**
TCP是字節流協議,不保證應用層消息的邊界。若客戶端快速連續發送多組數據,PLC可能將多次發送的數據合并到同一接收緩沖區(如網絡延遲或PLC處理速度慢時)。
2. **PLC緩沖區覆蓋機制**
S7-1200的`TRCV`指令默認采用**循環緩沖區**(FIFO機制)。當新數據到達時,會從緩沖區的當前指針位置開始覆蓋舊數據,導致看似"亂序"。
3. **字節對齊差異**
如果客戶端發送時未顯式指定字節序(如大端/小端),而PLC默認按大端序解析,可能引發分段錯誤(但您的案例中實際是整體偏移,非字節反轉)。
---
### **解決方案**
#### **(1) 顯式定義應用層協議**
在數據包中加入**幀頭**和**幀尾**標識,例如:
```plaintext
[頭標識:0xAA][數據長度:1字節][數據:N字節][校驗和:1字節][尾標識:0x55]
```
PLC側通過循環檢查緩沖區匹配完整幀后再處理。
#### **(2) 修改TRCV參數配置**
```pascal
TRCV(
REQ := TRUE, // 持續使能
CONT := TRUE, // 保持連接
DATA := #ReceiveBuf, // 接收緩沖區
LEN := 20, // 預期接收長度
RCVD_LEN=> #ActualLen, // 實際接收長度輸出
BUSY => #BusyFlag);
```
關鍵點:
- 設置`LEN`與發送方嚴格一致(您已設為20字節)。
- 監控`RCVD_LEN`確認每次接收的實際字節數。
#### **(3) 強制單次接收同步**
在客戶端每次發送后增加延遲(如100ms),或通過PLC程序控制:
```pascal
IF #FirstReceive THEN
TRCV(REQ := TRUE); // 首次觸發
#FirstReceive := FALSE;
ELSE
TRCV(REQ := NOT #BusyFlag); // 上次接收完成后再請求
END_IF;
```
#### **(4) 使用`TRCV_C`替代`TRCV`**
`TRCV_C`集成連接管理,可減少緩沖區沖突:
```pascal
TRCV_C(
CONT := TRUE,
LEN := 20,
DATA := #ReceiveBuf,
RCVD_LEN=> #ActualLen);
```
---
### **您的數據案例分析**
- **原始發送數據**(16進制):
```plaintext
15 3E 14 24 54 26 4E 28 51 29 53 AA 56 B0 2D 2D 5C 75 2F C8
```
- **PLC接收數據**:
```plaintext
2D 2D 5C 75 2F C8 15 3E 14 24 54 26 4E 28 51 29 53 AA 56 B0
```
**現象解釋**:
數據被**環形偏移6字節**,說明PLC緩沖區中殘留了之前未及時讀取的6字節數據,新數據從緩沖區第7字節開始寫入,形成"拼接"效果。
---
### **終極調試建議**
1. **清空緩沖區**
在建立連接后、首次接收前,調用`TRCV`連續讀取直到`BUSY`=FALSE,丟棄舊數據。
2. **Wireshark抓包驗證**
過濾PLC的IP和端口,確認客戶端是否真正按預期順序發送(排除調試助手本身問題)。
3. **PLC側診斷**
在線監視`TRCV`的`RCVD_LEN`和`STATUS`,正常時應返回`16#7000`(無錯誤)。
4. **代碼示例(清空緩沖區)**
```pascal
// 初始化階段清空緩沖區
#TempBuffer := ARRAY[1..100] OF BYTE; // 臨時緩沖區
WHILE TRUE DO
TRCV(
REQ := TRUE,
DATA := #TempBuffer,
LEN := 100,
BUSY => #IsBusy);
IF NOT #IsBusy THEN EXIT; END_IF;
END_WHILE;
```
---
通過以上方法,您應該能解決數據錯序問題。如果仍有異常,請檢查:
- 客戶端是否啟用了Nagle算法(建議禁用)
- PLC的OB1循環時間是否過短(建議≥50ms)
- 是否有多余的`TRCV`調用覆蓋了緩沖區