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