← 所有文章

Modbus功能17先寫後讀與重疊區域驗證

· 站長

以讀0010h起四word、寫0011h起兩word的重疊案例,驗算功能17的欄位、長度、回覆與完成限制。

先寫再讀是這個功能的重點

需要修改設定並讀回一段資料時,可以先查設備是否支援十六進位17,也就是十進位23的Read Write Multiple Registers。它在同一交易內先寫Holding Registers,再讀Holding Registers,回覆帶的是讀取範圍的資料。這個順序是功能的核心;不要因英文名稱Read排在前面,就把它理解為先讀舊值再寫入。

欄位 意義 標準範圍
讀取起點 要回傳的Holding Register起點 PDU位址0000h至FFFFh
讀取數量 回覆中有幾個word 1至125
寫入起點 本次要改動的位置 PDU位址0000h至FFFFh
寫入數量 後面跟隨幾個word 1至121
Write Byte Count 只計寫入資料的bytes 兩倍寫入word數

兩個範圍可以分開,也可以重疊,但各自都要連續而且有效。讀取數量與寫入數量不是同一欄;表中的上限也不相同。實際設備可能限制更小的長度,或完全不支援17,不能因支援03和10就認定一定支援17。

本篇只示範離線PDU,不含RTU站號CRC或TCP MBAP,所有位址與資料用途均為自訂測試假設。先準備可回復的測試資料區,確認沒有命令副作用與其他寫入者,再用範例理解欄位,不能直接套在實體機台的未知位址。

用四個word看出重疊區域的新值

自訂可讀寫資料區0010h至0013h,原值依序為10、20、30、40。這次讀四個word,從0010h開始;同時把0011h和0012h寫成200與300。假設設備在交易期間沒有其他程序改動資料,也沒有特殊轉換,先寫後讀的預期回覆便是10、200、300、40。

PDU位址 交易前十進位 本次寫入 預期讀回
0010h 10 不在寫入範圍 10
0011h 20 200 200
0012h 30 300 300
0013h 40 不在寫入範圍 40

寫入的兩個word只是讀取四個word的中間部分,所以這張表也能抓出起點差一碼。如果讀回變成200、300、30、40,應先檢查是否錯把寫起點設成0010h;如果回覆只有200、300,先查客戶端是否把讀取數量誤設為二。不要看到部分數字正確就認定整筆交易正確。

回覆不攜帶讀起點,客戶端必須從原請求知道第一個word對應0010h。經TCP時用連線與TID配對,經RTU則按單筆交易、站號與功能碼等條件核對。位址、型別、倍率與資料順序應保存在請求描述中,不能收到一串bytes後再憑畫面欄位猜測。

第二個離線練習把讀起點改成0012h、讀數量改成二,寫範圍仍是0011h起兩word。預期只讀回300與40,正常PDU為17 04 01 2C 00 28。此例確認解析器依讀取範圍排列結果,不把寫入的200硬塞進回覆,也不把原來四word的快取當成本次資料。

把完整PDU拆成長度可驗算的欄位

本例請求是17 00 10 00 04 00 11 00 02 04 00 C8 01 2C。從左到右依序為功能碼、讀起點、讀數量、寫起點、寫數量、Write Byte Count與兩個寫入值。功能碼佔一byte,四個位址與數量欄各兩byte,再加一byte計數與四byte資料,總共十四byte。

欄位 十六進位 本例解釋
Function 17 先寫後讀Holding Registers
Read start / count 00 10 / 00 04 從0010h讀四word
Write start / count 00 11 / 00 02 從0011h寫兩word
Write Byte Count 04 兩word乘二
Write values 00 C8 01 2C 十進位200、300
正常回覆 17 08 00 0A 00 C8 01 2C 00 28 四word資料,共八byte

正常回覆的08只計四個讀回word,不計功能碼和Byte Count本身,因此正常PDU總長為十byte。回覆不是請求的原樣回送,也沒有額外一組寫起點和寫數量。若沿用功能10的解析器,把前兩個資料byte當位址,便會把000Ah錯看成回送地址而拒絕正常結果。

練習先遮住預期回覆,自己把10、200、300、40換成十六進位,再按高byte先傳排列。接著故意把請求Byte Count改成02,確認檢查程序能在傳送前抓到寫入兩word卻只宣告兩byte的矛盾。這種離線檢查不需要對設備發送錯誤寫入。

哪些完成條件還要另外確認

功能17提供先寫後讀的交易順序,不能把它擴大成跨設備同步、實體輸出已動作或所有暫存器對外完全原子更新的保證。設備的掃描程序可能重寫資料,也可能在寫入設定後才逐步產生結果。若讀的是運轉狀態區,讀到舊狀態不一定表示寫入失敗,要依設備的完成條件判斷。

即使讀寫範圍重疊,也要先確認寄存器是否讀寫同一語意。有些產品寫入是命令、讀出是當前狀態;同一位址讀回不同數字可能是有意設計。不能在沒有映射表時,用「我寫300就一定讀300」作所有設備的驗收規則。本篇重疊範例刻意假定普通測試記憶體。

故障情境 失敗時先查 收尾方式
例外97 01 是否支援17與目前模式 改用文件支援流程,另評估競態
例外97 02 讀寫兩段的起點與尾端 排除保留洞與越界
例外97 03 讀寫數量及寫入byte數 離線重新驗算
逾時或斷線 寫入可能已發生 標記結果待確認,不盲重送
正常但讀回不符 位址、型別與設備更新語意 分辨記憶體值與動作完成

若17不支援,退回先10寫入再03讀取是兩筆交易,中間可能有其他寫入者介入。應明確列出差異,必要時採單一寫入權或設備提供的流程;不能把替代流程命名為相同保證。寫入逾時後重連,也不能單靠新連線建立就把前次寫入標成失敗或成功。

完成練習應留下原值表、兩段範圍、請求十四byte、回覆十byte及逐word比對。測試結束前檢查原設定是否仍可還原;如果其他人已更新設定,先協調寫入權,不要無條件覆蓋回舊值。

尾端位址按起點加數量減一計算。即使起點本身合法,整段超過設備區域仍不能送出;讀區和寫區須各算一次,不能只驗證較短的那一段。

FAQ與適用限制

FAQ1:為什麼讀上限125,寫只有121?兩邊的PDU欄位占用不同,標準為此功能各列一個上限。不要把功能10的123word寫入上限搬過來,也不要拿讀取上限當寫入量。

FAQ2:一定要讀寫同一範圍嗎?不用。請求分別帶兩組起點與數量,彼此可不同;但各段內仍是連續位址,整段都要有權限且可存取。

FAQ3:回覆是讀到寫入前的值嗎?標準順序為先寫後讀。本篇普通記憶體假設下應看到更新後的200與300;實際設備若有命令語意或背景更新,則需依文件解釋。

FAQ4:功能17正常就可以直接顯示動作完成?只有設備明定回讀狀態等於完成且條件成立時才行。交易完成、設定符合與物理動作完成應分別判斷。

本文適用於支援Modbus Holding Registers且能取得完整映射表的封包設計。未選定PLC指令、通訊函式或專用模組設定,不能推論Q06UDVCPU或QJ71C24N原生提供相同API。所有範例均為離線計算,沒有宣稱編譯、模擬或實體讀寫驗證通過。

參考:Modbus Application Protocol V1.1b3,第6.17節Read Write Multiple Registers及第7章例外回覆。

延伸閱讀


使用 PLC 工具箱 →