先確認設備真的提供檔案記錄
File Record是一種用檔案編號與記錄編號定位資料的Modbus模型。它不是直接存取Windows檔案,也不代表能指定SD卡上的CSV檔名。設備即使支援03讀取Holding Registers,也未必實作14讀取File Record。開始組包前,先取得設備文件中的功能碼支援表、檔案編號、記錄配置、資料型態與存取限制。少了其中一項,就先做離線規劃,不要猜檔案號。
本文把功能碼寫為0x14與0x15,十進位分別是20與21。封包每個十六進位欄位都以兩位表示,避免與十進位14、15混淆。檔案記錄使用自己的尋址欄位,不套用40001減一的顯示規則;設備文件寫record 12時,仍須確認其欄位定義,不能自行從12改成11。
| 資料模型 | 定位欄位 | 本篇處理方式 |
|---|---|---|
| Holding Register | 功能碼與暫存器起點 | 不能拿其位址直接填檔案編號 |
| File Record | 檔案號、起始記錄、長度 | 按設備檔案模型逐項核對 |
| 電腦或SD卡檔案 | 檔名、路徑、格式 | 沒有標準一對一映射 |
| 事件內容 | 時間、事件碼、值等 | 由設備定義字序、型態與更新規則 |
自訂教學設備有檔案1與檔案2:檔案1從記錄4取三個16位元字,檔案2從記錄10取五個字。這只是組包練習,不是任何PLC、儀表或QJ71C24N的內建檔案表。先把「資料在哪裡」與「收到後代表什麼」分成兩份紀錄,就能避免封包正確卻解讀成錯誤事件。
0x14請求 每一組子請求七個位元組
讀取子請求依序包含一位元組Reference Type、兩位元組File Number、兩位元組Record Number,以及兩位元組Record Length。此標準格式的Reference Type為06。注意長度計的是16位元字數;外層Byte Count計的是後續子請求的位元組數。兩種長度不能交換。多位元組欄位按高位元組在前排列。
| 子請求 | Reference | File | Record | Length |
|---|---|---|---|---|
| A | 06 | 00 01 | 00 04 | 00 03 |
| B | 06 | 00 02 | 00 0A | 00 05 |
兩組各七位元組,因此請求Byte Count=14,也就是0E。完整教學PDU為14 0E 06 00 01 00 04 00 03 06 00 02 00 0A 00 05,共16位元組。這裡沒有RTU站號、CRC或TCP的MBAP,不能把此字串直接稱作完整RTU訊框。
審查時把兩組子請求分別框出來,再逐欄轉回十進位確認。若把第二組起點十進位10寫成00 10,就變成十進位16,設備仍可能正常回傳錯誤區域;CRC也抓不到這種合法但選錯位置的請求。資料來源頁碼與十進位/十六進位表示法應一起保留。
檔案號的規範欄位範圍為1至65535,起始記錄欄位為0至9999,但這只是格式邊界,不表示設備真的建立了所有檔案與記錄。規範也提醒舊設備對大於10的檔案號可能有互通限制。每組的起點加長度仍要落在實際設備可存取範圍內。
回覆長度要由內往外核對
正常0x14回覆不是把檔案號與記錄號逐一送回。它按請求次序帶回子回覆,所以解析程式必須保留原請求清單,才能知道每段資料屬於哪個檔案。每段先有一個File Response Length,再有Reference Type和資料。段長包含Reference Type及資料,不含段長欄位本身。
| 子回覆 | 資料量 | 段長欄位 | 段的實際大小 |
|---|---|---|---|
| A:三字 | 6 bytes | 1+6=7,填07 | 1+7=8 bytes |
| B:五字 | 10 bytes | 1+10=11,填0B | 1+11=12 bytes |
| 外層合計 | 8字共16 bytes | Response Data Length填14 | 8+12=20 bytes |
自訂回覆A三字為0001、0002、0003,B五字為0010、0011、0012、0013、0014。PDU可寫成14 14 07 06 00 01 00 02 00 03 0B 06 00 10 00 11 00 12 00 13 00 14。第一個14是功能碼,第二個14是十六進位20的外層資料長度;PDU總長為22位元組。先辨認位置,再解讀相同數字。
收到資料時先核對外層總長,再依原請求的三字、五字預期檢查兩段長度、Reference Type及資料邊界;多一段、少一段、剩餘位元組或截斷都要拒收。本例期望第一段07、第二段0B,若第一段填09卻仍只附六個資料位元組,解析器不得把第二段的欄位誤當資料。
讀取的請求短,不代表回覆一定能放進協定長度。多組讀取要預先算回覆大小,遵守253-byte PDU及該功能的欄位限制,再與設備自身更小的上限取交集。不能直接沿用03功能碼的125字上限,因File Record另有每段的控制欄位。
寫入與一致性要另做確認
0x15寫入子請求在七個控制位元組後加入資料,每個字兩位元組。自訂向檔案1記錄4寫入三字,後續資料長度為7+6=13,外層填0D;PDU總長1+1+13=15。正常回覆回送請求內容,需逐欄核對;收到正常回聲也不能推定資料已永久寫進非揮發記憶體或設備已套用到製程。持久化與套用條件由原廠定義。
事件記錄可能在讀取期間更新或循環覆寫。即使一次請求讀到兩個檔案,也不能自行宣稱兩段來自同一時刻。若設備有凍結、快照編號、版本或讀取前後序號機制,按手冊使用;若沒有,報告要說明一致性限制。不可自行挑一個保留位元作鎖定,也不可為了確認讀取而試寫事件區。
| 失敗徵象 | 先查位置 | 預期處理 |
|---|---|---|
| 94 01例外 | 功能與檔案存取支援 | 保存原回覆,停止猜碼 |
| 94 02例外 | 檔案號、起點及整段範圍 | 對照該韌體的檔案表 |
| 正常回覆但事件不對 | 原請求配對、型別、字序 | 保留原字與解析版本 |
| 兩段時間不一致 | 更新或循環覆寫規則 | 使用原廠快照或標記限制 |
離線驗收用一份固定樣本和三份反例:正常兩段、第二段截斷、段長錯誤、例外回覆。正常樣本應輸出A三字與B五字,所有反例均不得更新現有事件資料。另保存原始PDU、交易識別、檔案與記錄號、解析版本及拒收原因,方便別人用同一份資料重現問題。
若寫入回覆遺失,保留「結果待確認」而非直接填失敗或成功。設備可能已修改記錄,重新送出可能再次觸發附帶動作。先依原廠允許方式讀回或查狀態,只有在確認操作可重複且滿足寫入權限時才重試。
FAQ與適用限制
FAQ1:File Record等於讀PLC SD卡嗎?不等於。必須由設備文件明確定義檔案號映射和功能支援,不能把Windows路徑塞進請求。
FAQ2:Record Length填資料位元組數嗎?不是,這裡填16位元字數;外層及子回覆長度才按各自規則計算位元組。
FAQ3:正常回覆為何沒有每段檔案號?它依子請求次序回傳,所以必須保存原請求,不能只存回覆就丟掉交易背景。
FAQ4:03能讀的設備一定能用14嗎?不能推論。先找支援表與檔案模型,未支持時不要靠改位址碰運氣。
本篇只做離線讀取審核與寫入格式解說,不對真實機台發送寫入。Q06UDVCPU、QJ71C24N或其他平台是否能用此功能,取決於實際通訊實作與對端支援;沒有原始專案與設備檔案表,就不能指定可執行的PLC位址或聲稱已完成實機驗證。
參考:Modbus Application Protocol V1.1b3,6.14、6.15及第7章:File Record格式、長度與例外回覆。