National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 10

Modbus 資料模型

線圈、離散輸入、輸入暫存器、保持暫存器與位址
Interaction 25 minute(s)

Learning Objectives

  • 分辨線圈、離散輸入、輸入暫存器、保持暫存器的大小、讀寫權限與功能碼
  • 把設備手冊的編號(例如 40001)正確換算成程式裡的位址,避免差一錯誤
  • 用 16 位元暫存器表示負數與小數(二補數、乘以 10)
  • 說明本課程模擬 PLC 的 I、Q、IW、MW 對應到哪一種 Modbus 資料

Modbus 只認得四種資料

上一課用功能碼 03 讀到了 PLC 的資料。Modbus 不管對方是 PLC、電力錶還是變頻器,一律把資料看成四張表:

資料表 大小 client 能不能寫 讀的功能碼 寫的功能碼 常放什麼
離散輸入(discrete input) 1 位元 唯讀 02 無 按鈕、限位開關、感測器的開關狀態
線圈(coil) 1 位元 可讀寫 01 05(單一)、15(多個) 輸出、啟停命令
輸入暫存器(input register) 16 位元 唯讀 04 無 量測值:溫度、壓力、電流
保持暫存器(holding register) 16 位元 可讀寫 03 06(單一)、16(多個) 設定值、參數、各種狀態

「線圈」這個名字來自繼電器的線圈,也就是輸出。很多設備把幾乎所有資料都放在保持暫存器裡, 所以 03 與 06 是最常用的功能碼;拿到一台新設備,第一件事是找手冊裡的暫存器對照表(register map)。

這一課要回答:

  1. 四張表怎麼對應到 PLC 的 I、Q、IW、MW?
  2. 手冊寫「40001」,程式裡的位址要填多少?
  3. 16 位元的暫存器怎麼放負數與小數?

本課程模擬 PLC 的對應

Modbus 位址 模擬 PLC
線圈 0~15 Q0.0~Q1.7(線圈 0=Q0.0、線圈 8=Q1.0)
離散輸入 0~15 I0.0~I1.7
輸入暫存器 0~7 IW0~IW7(類比輸入原始值)
保持暫存器 0~31 MW0~MW31

超出範圍會收到例外碼 2(非法資料位址)。各廠牌 PLC 的對應方式都不一樣,有的要在軟體裡自己設定,以手冊為準。

逐步看:四張表各讀一次

對照畫面上 PLC 的輸入、輸出燈與字組,看每一次讀取拿到的是哪一部分。最後試著寫保持暫存器;離散輸入與輸入暫存器沒有寫入的功能碼。

位址從 0 開始,編號從 1 開始

Modbus 規格裡有兩種數法:

  • 訊框(PDU)裡的位址:從 0 開始,0~65535。pymodbus 的 address 參數就是這個。
  • 資料模型的編號:每張表的元素從 1 開始編號。規格寫明:編號 X 的元素,在訊框裡的位址是 X − 1。

很多設備手冊還沿用一種 5 位數(或 6 位數)的寫法,用第一個數字表示哪一張表:

手冊寫法 資料表 程式裡的位址
00001~ 線圈 編號 − 1
10001~ 離散輸入 編號 − 10001
30001~ 輸入暫存器 編號 − 30001
40001~ 保持暫存器 編號 − 40001

所以手冊的「40002」要寫成 read_holding_registers(1, …)。直接填 40002 會讀到完全不同的位址(多半超出範圍,收到例外碼 2); 只差 1 的錯誤更麻煩:不會出錯,只是讀到隔壁的值。有的手冊直接寫從 0 開始的位址,有的用 16 進位,拿到手冊先確認它用哪一種, 再拿一個已知的值(例如型號代碼)讀讀看。

逐步看:40002 要填多少

看通訊紀錄裡第一筆請求的位址欄位 9C 42:那是 40002 的 16 進位,PLC 沒有這麼大的位址,回了例外碼 2。

16 位元能放什麼數字

一個暫存器只有 16 個位元,在訊框裡高位元組在前(大端序,big-endian):250 傳成 00 FA。

  • 無號整數:0~65535。
  • 有號整數:用二補數表示 −32768~32767。−50 存成 65486(0xFFCE),讀回來時,最高位元是 1 就減 65536。
  • 小數:很多設備把數值乘以 10 或 100 存成整數,例如 25.0 °C 存成 250,手冊會寫「單位 0.1 °C」或「比例 ×10」。

Modbus 本身不知道暫存器裡是有號還是無號,怎麼解讀由手冊決定。 pymodbus 回傳的 registers 一律是 0~65535 的無號數,負數要自己轉換。 需要更大的整數或浮點數時,要用兩個暫存器組成 32 位元,第 14 課會專門介紹(也會用到 convert_from_registers)。

一次能讀的數量也有上限:讀暫存器最多 125 個、讀線圈或離散輸入最多 2000 個(因為一個 Modbus PDU 最多 253 個位元組)。

逐步看:寫入負數的補正值

階梯圖每次掃描都算 MW3=MW1+MW2。Python 把 −5.0 °C 的補正值寫到 MW2,PLC 用有號整數計算,得到 20.0 °C;但 Python 讀回來的 MW2 是 65486,要自己轉回負數。

互動練習:照對應表組請求

這次站號固定 1。組出下面四個請求(每組好一個,說明欄會告訴你對應到模擬 PLC 的哪個位址),最後回答一個問題:

  1. 讀 PLC 的輸入 I0.0~I0.7。
  2. 讀類比輸入 IW0。
  3. 把 MW5 寫成 300。
  4. 打開輸出 Q1.0。

互動練習:遠端調整加熱的設定值

這台 PLC 的階梯圖:溫度原始值 IW0 小於設定值 MW0、而且門關上(I0.1)時,打開加熱器 Q0.0。 設定值一開始是 0,所以加熱器不會動。用 Python 經 RS-485 完成任務:

  1. 直接執行起始程式,讀到目前的設定值。
  2. 讀溫度原始值(輸入暫存器 0)並印出來。
  3. 把設定值(保持暫存器 0)寫成 3000,用 time.sleep(1) 等 1 秒,再寫回 0:加熱器要打開過,程式結束時要是關的。
  4. 讀離散輸入 0~7,印出門開關(離散輸入 1)的狀態。
  5. 回答一個問題。

小測驗:四張表

1.

要讀一台變頻器的「目前輸出頻率」(唯讀的 16 位元量測值),最可能用哪一個功能碼?

2.

在本課程的模擬 PLC 上,線圈 10 對應哪個輸出?

3.

手冊寫「40010:馬達速度設定」。程式要寫哪個位址?

第 1 次作答

小測驗:16 位元的數字

1.

下面的程式會印出什麼?

v = 65436
if v >= 0x8000:
    v -= 0x10000
print(v / 10)
2.

暫存器的值 300,在 Modbus 訊框裡是哪兩個位元組?

第 1 次作答

重點整理

  • 四張表:離散輸入(1 位元、唯讀、02)、線圈(1 位元、讀寫、01/05/15)、輸入暫存器(16 位元、唯讀、04)、保持暫存器(16 位元、讀寫、03/06/16)。
  • 訊框裡的位址從 0 開始;手冊的 4xxxx 寫法從 1 開始數,位址=編號 − 40001。先用已知的值確認。
  • 暫存器 16 位元、高位元組在前;有號數用二補數,讀回來 ≥ 32768 就減 65536;小數常用「乘以 10」存成整數。
  • 本課程模擬 PLC:線圈=Q、離散輸入=I、輸入暫存器=IW、保持暫存器=MW;各廠牌的對應以手冊為準。
  • 要改變設備的行為,寫保持暫存器裡的設定值;輸入類的資料只能讀。

下一課換到乙太網路:Modbus TCP 的訊框多了 MBAP 標頭、少了 CRC,用法幾乎一樣。

這一課完成了!
Next lesson:Modbus TCP 與 pymodbus
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。