先寫再讀是這個功能的重點
需要修改設定並讀回一段資料時,可以先查設備是否支援十六進位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章例外回覆。