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 13

用 Python 做 Modbus 從站

資料區塊、伺服器上下文與模擬裝置
Interaction 25 minute(s)

Learning Objectives

  • 說明 Modbus 的 client/server(舊稱主站/從站)分工,以及什麼時候需要自己做一個從站
  • 用 pymodbus 建立資料區塊、裝置上下文與伺服器上下文,啟動 Modbus TCP 從站
  • 說出功能碼對應到哪一個資料區塊,以及請求超出範圍時從站會怎麼回應
  • 用 Python 從站模擬一台裝置,讓 HMI 或監控程式在沒有真實設備時也能測試

換個角色:讓 Python 回答別人的問題

前兩課的 Python 程式都是發問的一方:連到 PLC、送出「讀保持暫存器 0~3」,PLC 回答。 這一課反過來,讓 Python 被別人問:它開一個 Modbus TCP 的連接埠,等別的程式來讀寫,照請求回應資料。

Modbus 的兩個角色,舊的文件叫主站(master)與從站(slave);Modbus Organization 在 2020 年 7 月宣布改用 client(客戶端)與 server(伺服器)。兩組名稱的意思一樣,現在的手冊、軟體兩種都看得到:

新名稱 舊名稱 做什麼 常見的例子
client(客戶端) 主站(master) 主動送出請求 HMI、SCADA、上一課的 Python 監控程式
server(伺服器) 從站(slave) 等待請求、回應資料 PLC、變頻器、電錶、溫控器

什麼時候需要自己做一個從站?

  • 模擬裝置:HMI 畫面或監控程式寫好了,現場的設備還沒到貨。先用 Python 從站假裝成那台設備,把畫面測一遍。
  • 測試:故意讓從站回傳極端值、例外回應,看你的監控程式會不會當掉。
  • 閘道器:把別的資料來源(感測器、資料庫、另一種協定)轉成 Modbus,讓只會講 Modbus 的設備讀得到。

這一課要回答:

  1. pymodbus 的從站由哪幾層物件組成?
  2. 啟動之後,程式停在哪裡?
  3. 請求的位址超出範圍時,從站回什麼?

逐步看:一個最小的 Modbus 從站

前面幾步在準備資料,最後一步 StartTcpServer 開始等待請求。這個模擬環境照規格的時間表送來 4 個請求, 全部都發生在最後一步:看畫面下方的通訊紀錄,「收到請求」是別的程式問的問題,下一行是從站的回答。 注意第 2 秒有人把保持暫存器 1 改成 650,第 3 秒再讀,讀到的就是新的值。

資料區塊、裝置、伺服器:三層容器

pymodbus 的從站資料一層包一層:

ModbusServerContext(整台伺服器)
 └─ ModbusDeviceContext(一台裝置,對應一個站號)
     ├─ co:線圈            ← 功能碼 1 讀、5/15 寫
     ├─ di:離散輸入        ← 功能碼 2 讀
     ├─ hr:保持暫存器      ← 功能碼 3 讀、6/16 寫
     └─ ir:輸入暫存器      ← 功能碼 4 讀

收到請求時,伺服器依功能碼決定找哪一個區塊,再依位址與數量取出資料。 如果要的位址不在區塊範圍內(例如區塊只有 10 格,卻要讀位址 12),從站不會亂回一個數字, 而是回例外回應:功能碼加上 0x80,例外碼 2(Illegal Data Address,位址不合法)。第 10 課的資料模型表格就是這樣定義的。

一台伺服器也可以裝好幾台裝置:ModbusServerContext(devices={1: 裝置甲, 2: 裝置乙}, single=False), 依請求的站號分給不同的裝置,常用在一個閘道器後面接了好幾台設備的情況。

使用時要注意的地方

  • 一直等待:StartTcpServer 會佔住整個程式。要讓從站的資料自己變化(例如每秒更新溫度), 真實的程式會另外開一個執行緒,或改用非同步版本 StartAsyncTcpServer,這一課先不處理。
  • 連接埠:Modbus TCP 的標準埠是 502。在 Linux 上,1024 以下的埠需要系統管理員權限, 所以在自己電腦上練習時常改用 5020 之類的埠,客戶端也要連同一個埠。
  • 版本差異:本課的寫法適用 pymodbus 3.10 以後的 3.x 版(這個模擬環境對應 3.10)。 較舊的版本把 ModbusDeviceContext 叫做 ModbusSlaveContext、把 device_id= 叫做 slave=; 3.13 起直接讀寫資料區塊的 getValues/setValues 改由伺服器物件處理,新版也已把這三個資料類別標示為即將淘汰(v4 改用 SimData/SimDevice)。 開新專案前先查你安裝的版本與官方文件。
  • 位址加 1:pymodbus 3.x 的裝置上下文會把請求位址加 1 再去資料區塊找。範例都透過 device.setValues/getValues 存取, 兩邊用同一套規則,所以不用自己處理;如果你跳過裝置、直接讀寫資料區塊,就要記得這個差 1。

逐步看:用對照表模擬一台溫控器

做模擬裝置時,先寫一張「暫存器對照表」:哪個位址放什麼、單位怎麼換算,再用迴圈放進資料區塊。 這張表也是你交給寫 HMI 的同事的文件。注意最後一個請求要讀位址 8~11,但區塊只有 0~9,所以得到例外回應。

互動練習:讓從站回答正確的資料

模擬的 HMI 會照時間表送來 4 個請求(1 秒讀保持暫存器 0~1、2 秒寫保持暫存器 1、3 秒讀保持暫存器 12、4 秒讀線圈 0~1)。 起始程式的資料都是 0,區塊也只有 10 格。依序完成任務,每改一次就按「執行」,看通訊紀錄裡的「回應」:

  1. 直接執行,看 4 個請求與回應。
  2. 讓 1 秒的請求讀到 [215, 500](溫度 21.5 °C、轉速 500)。
  3. 讓 3 秒讀位址 12 的請求不再是例外回應,而是讀到 42。
  4. 讓 4 秒讀線圈 0~1 得到 [1, 0](線圈 0=運轉中)。
  5. 回答一個問題。

小測驗:角色與資料區塊

1.

一台 HMI 每秒向變頻器讀取轉速。用 Modbus 現在的名稱,誰是 client、誰是 server?

2.

pymodbus 從站收到功能碼 4(讀輸入暫存器)的請求,會到哪一個資料區塊找資料?

3.

程式在 StartTcpServer(...) 下一行寫了 print("啟動完成"),執行後會怎樣?

第 1 次作答

小測驗:位址與例外

1.

資料區塊從位址 0 開始、共 10 格。客戶端要讀「位址 8 開始、4 個」保持暫存器,從站會回什麼?

2.

下面的程式模擬「裝置把位址加 1 再去資料區塊找」,會印出什麼?

values = [0, 235, 600, 1]

def get(address, count):
    address += 1
    return values[address:address + count]

print(get(0, 2))
第 1 次作答

重點整理

  • Modbus 的兩個角色:client(舊稱主站)送出請求,server(舊稱從站)等待並回應;Modbus Organization 在 2020 年改用新名稱。
  • pymodbus 從站三層:ModbusSequentialDataBlock(資料區塊)→ ModbusDeviceContext(一台裝置的 co、di、hr、ir)→ ModbusServerContext(整台伺服器)。
  • setValues/getValues 用功能碼指定區塊:1→線圈、2→離散輸入、3→保持暫存器、4→輸入暫存器。
  • StartTcpServer 會一直等待請求,不會回傳;位址超出範圍時從站回例外碼 2。
  • 自己做從站的用途:模擬還沒到貨的裝置、測試監控程式、做協定閘道器。寫好暫存器對照表,同時也是給 HMI 的文件。
  • pymodbus 的 API 在 3.x 各版之間有改名,開新專案先確認版本。

下一課處理 16 位元裝不下的數值:用兩個暫存器組成 32 位元的整數與浮點數。

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