← 所有文章

Modbus 0x16 Mask Write Register 位元遮罩寫入何時比讀改寫安全

· 站長

以000Ah與bit4案例拆解0x16的AND/OR mask,對比0x06讀改寫競態。

0x16先理解遮罩目的

Modbus 0x16(22)Mask Write Register讓伺服器在一個Holding Register內依AND mask與OR mask處理位元。它適合只改某些bit並保留其他bit;先讀、修改、再用0x06寫回,讀寫之間可能被另一控制器改掉。標準列出功能碼,不代表每台設備都支援,必須查寄存器文件。

欄位 自訂案例 意義
原始內容 000Ah 不是寄存器位址
目標位 bit4 假設1為啟用
AND FFEFh 清bit4、保留其餘
OR 0010h 最後設bit4

假設原值00A3h,結果=(00A3 AND FFEF) OR (0010 AND NOT FFEF)=00A3h OR 0010h=00B3h。這是教學計算,不是任何型號的寄存器語意。AND與OR不是新值,而是兩個運算遮罩。

正式設計先核對寄存器位址、存取權限、bit定義、0x16支援和例外行為。命令bit、狀態bit與保留bit要分開記錄。

若某個保留bit由設備週期性更新,客戶端即使只想設bit4,也不能把讀回整字不同視為寫入失敗。審查表應同時保存寫前值、請求遮罩、伺服器回覆、寫後回讀與設備狀態時間戳。這些證據能區分遮罩公式錯誤、寄存器權限錯誤和設備自身狀態變化。

AND與OR用真值表核對

對bit4而言,AND=1保留原值,AND=0先清除;最後要固定為1時,OR通常在該位放1。保留位通常AND放1、OR放0。若需求是toggle,不能直接把Mask Write當成通用翻轉指令,仍要查設備對該bit的定義。

目的 AND bit4 OR bit4 原0 原1
保留 1 0或1 0 1
強制0 0 0 0 0
強制1 0 1 1 1

真值表能抓出把AND和OR方向寫反的錯誤。測試還要保存原值、遮罩與結果,因為某些狀態bit會由硬體掃描自動更新,整字比較可能誤報。

位址表示方式也要固定。Modbus PDU的寄存器位址是零基準欄位時,文件所稱40011可能要換算成PDU位址10;不能把人機畫面的40001編號直接塞進封包。本文不指定任何廠牌位址換算,正式實作應依設備手冊確認。

若同一寄存器同時包含狀態和命令,寫入整個Mask Write前要確認狀態位不是唯讀或硬體鎖定。設備可能接受交易卻忽略唯讀位,回讀時應按每一位的控制語意分別判斷。

如果需求是清除bit4,案例可使用And=FFEFh、Or=0000h;若原值001Ah,結果為000Ah。這個反向案例能確認測試工具沒有把Or mask直接當成最終寄存器值,也能抓出And mask方向相反的程式。

文章中的PDU欄位、公式和數字都是教學材料,沒有對任何PLC、閘道或伺服器編譯、模擬或接線。實機驗證仍需使用指定設備、隔離測試寄存器和可回復的維護窗口。

0x06讀改寫的競態窗口

假設Current=000Ah。控制器A讀到000Ah後準備設定bit4;控制器B先設定bit0,將000Ah改成000Bh;A再依舊值計算並用0x06寫回001Ah,B的更新被覆蓋。0x16的價值是把遮罩運算交給伺服器處理同一寄存器,縮小這個讀寫窗口。

時間 A B 結果
t0 讀000A 共同起點
t1 計算bit4 讀000A
t2 寫000B B生效
t3 寫001A A覆蓋bit0

0x16不保證跨寄存器、跨設備或硬體掃描的原子性。若設備不支援0x16,只能使用單一寫入者、命令佇列或維護模式降低競態,不能自行發明廠商指令。

若0x16回覆正常但實際輸出沒有變,先查該bit是不是命令觸發位、設備是否在遠端模式、是否需要解鎖或停止狀態,再查遮罩。不要先把同一請求重送多次,因為某些命令bit可能造成重複動作。

AND mask與OR mask的關係可以用每個bit獨立驗證:當AND為1且OR為0,結果等於原bit;當AND為0且OR為1,結果固定為1;當兩者都為0,結果固定為0。若兩者都為1,OR項會被NOT AND遮掉,結果仍保留原值;因此AND為1的位元,OR是無關值。

客戶端應在逾時、CRC錯誤或連線中斷時避免盲目重試命令。若設備的0x16只改設定位,重試可能看似安全;但若bit代表脈衝或觸發,第二次可能產生不同效果。重試策略必須按寄存器文件和設備狀態設計。

若B先把值改成000Bh,再由A送出AND=FFEFh、OR=0010h的遮罩,按當時000Bh計算得到001Bh,可保留B剛設的bit0。這個比較的前提是伺服器依公式處理當時內容;其他寫入者若稍後又整字覆寫,遮罩仍無法阻止。應同時定義誰擁有各命令位,以及其他客戶端可使用哪些寫入方式。

回讀與型號限制

自訂PDU位址0020h,用FFEFh與0010h設定bit4,請求為16 00 20 FF EF 00 10,共七位元組。正常PDU回送相同位址與兩個遮罩,而不是直接回傳新內容001Ah。須再以允許的讀取方式取得內容;例外回覆功能碼為96h。本文只列PDU,不含RTU站號CRC或TCP MBAP。

交易成功後保存請求、回覆和回讀值,至少比對目標bit、保留bit與狀態bit。型號限制包括寄存器唯讀、命令只在停止模式有效、寫入後被掃描程序改回,這些不能由標準單獨推定。異常碼要連同位址、權限、模式和原始封包記錄。

審查 正常 異常先查
功能碼 回覆0x16 是否只支援0x06
目標bit 成為需求值 bit位序與語意
保留bit 未意外改變 硬體自動更新
完成狀態 另有回讀確認 不能只看交易回覆

NOT必須限制為16位。對16bit Current,NOT(FFEFh)=0010h;不可用無界整數的補數直接代入,以免高位影響公式。案例000Ah、AndMask=FFEFh、OrMask=0010h,Result=(000A AND FFEF) OR (0010 AND NOT FFEF)=000A OR 0010=001A。這是設定bit4並保留其餘位的教學例。

計算時將NOT限制成FFFFh XOR AndMask即可得到16位補數。例如NOT(FFEFh)=0010h,再與OrMask做AND。這個邊界對PLC或腳本實作都重要,因為無界整數可能產生FFFFFFFFFFF等高位,最後轉型時又截斷到不同結果。

異常碼03代表資料值或結構不合法的可能性要依標準與設備文件確認;不能只看到例外回覆就修改遮罩。先比對功能碼、位址、AndMask、OrMask和寄存器允許寫入的模式,再重新送出最小測試。

核對表要保存Current、AndMask、OrMask、Result、回讀與狀態,方便換工具後重算。

每次測試也要保存設備型號與韌體版本,避免保留位定義改變後誤用舊遮罩。

FAQ與官方來源

遮罩設計還要檢查位元編號從最低有效位開始,不能把文件中的bit4誤當成第五個輸入端子。封包審查時把16位值寫成二進位,逐位標記保留、清除和設定位,能避免十六進位心算造成漏位。

測試案例要包含原值bit4為0與1兩種情況。原值000Ah的bit4本來是0,套用設定遮罩後為001Ah;若原值001Ah再套用同一遮罩,仍應為001Ah。兩個結果相同表示設定bit4是冪等的,卻不代表機械輸出已完成。

正式上線前應把寄存器文件版本、韌體版本、遮罩計算表和回讀證據一起保存。若設備換版後保留位重新定義,原來的FFEFh可能不再安全;遮罩不是跨型號永久有效的常數。

FAQ1:0x16每台伺服器都支援嗎?答:不一定,必須查型號文件。

FAQ2:AND=0就是清除該位嗎?答:還要看OR mask,必須套入16位公式與真值表。

FAQ3:0x16保證跨交易或跨寄存器原子嗎?答:不保證,功能碼主要處理指定單一寄存器。

FAQ4:回覆正常代表機械動作完成嗎?答:不一定,仍需回讀狀態或設備明確完成訊號。

來源:Modbus Application Protocol Specification V1.1b3,0x16(22)Mask Write Register章節。

參考:Modbus protocol specification V1.1b3

來源:Modbus Organization規格索引。

參考:Modbus specifications index

延伸閱讀


使用 PLC 工具箱 →