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 14

32 位元數值與位元組順序

兩個暫存器組成整數與浮點數、字組順序
Interaction 25 minute(s)

Learning Objectives

  • 說明一個 16 位元暫存器能放的範圍,以及為什麼大的整數與小數要用兩個暫存器
  • 用 struct 把 32 位元整數與浮點數拆成兩個暫存器,再組回來
  • 說明「字組順序」的差異(ABCD、CDAB 等),從讀到的值判斷順序有沒有選錯
  • 用 pymodbus 的 convert_from_registers/convert_to_registers 讀寫 FLOAT32 與 INT32

一個暫存器只有 16 位元

Modbus 的保持暫存器與輸入暫存器都是 16 位元:當成無號整數是 0~65535,當成有號整數(二補數)是 −32768~32767。 第 10 課用「乘 10 存整數」放溫度(23.5 °C 存成 235),這招很常用,但有兩個限制:

  • 範圍不夠:流量計的累計量 100000 公升、能源表的累計 kWh,一下子就超過 65535。
  • 精度要事先決定:乘 10 只留一位小數;要三位小數就乘 1000,範圍又更小。

所以很多設備把一個數放在兩個相鄰的暫存器裡,組成 32 位元:

型別 位元 範圍或精度 佔幾個暫存器
INT16/UINT16 16 −32768~32767/0~65535 1
INT32/UINT32 32 約 ±21 億/0~約 42 億 2
FLOAT32(IEEE 754 單精度) 32 有效數字約 7 位 2
FLOAT64(雙精度) 64 有效數字約 15 位 4

這一課要回答:

  1. 一個 32 位元的數怎麼拆成兩個暫存器?
  2. 為什麼同一組暫存器,用不同的軟體讀會得到天差地遠的值?
  3. 用 pymodbus 怎麼讀寫這些型別?

逐步看:100000 拆成兩個暫存器

先用除法與餘數拆,再用 struct 拆,兩種方法得到同樣的結果。最後看負數:−2 拆出來是兩個很大的數,這是二補數。

浮點數與字組順序

小數最常用 IEEE 754 單精度浮點數(FLOAT32):4 個位元組,1 個符號位元、8 個指數位元、23 個小數位元。 它能表示很大與很小的數,但有效數字只有大約 7 位,很多十進位小數(例如 23.4)存不剛好,只能存最接近的值。

麻煩的是 4 個位元組放進兩個暫存器的順序。Modbus 規定一個暫存器裡是大端序(高位元組先送), 但兩個暫存器誰先,規格沒有規定,各廠牌自己決定。習慣用 ABCD 代表 4 個位元組由高到低:

寫法 暫存器 n 暫存器 n+1 常見的說法
ABCD A B C D 大端序、高位字組在前
CDAB C D A B 字組交換、低位字組在前
BADC B A D C 位元組交換
DCBA D C B A 小端序

順序選錯不會出錯訊息,只會得到一個看起來很怪的數(例如 4.17e-08 或 86 億)。 所以讀新設備時,先查手冊的暫存器表與字組順序;手冊沒寫清楚時,用一個你知道答案的量(例如室溫)試讀,看哪一種順序合理。

逐步看:23.4 存成浮點數

注意「組回來」那一行:拿到的不是 23.4,而是 23.399999618530273。最後一行故意把兩個暫存器對調,看會得到什麼。

逐步看:用 pymodbus 讀 FLOAT32 與 INT32

模擬的儀表把氣壓(FLOAT32)放在保持暫存器 0、1,累計流量(INT32)放在 2、3,都是高位字組在前。 注意階梯圖的 MOV 34464 → MW3:PLC 的字組是有號 16 位元,在 PLC 的監看畫面上這個值會顯示成 −31072;同樣的 16 個位元,用 Modbus 讀到的是無號的 34464。

互動練習:找出字組順序

另一台溫度變送器把溫度(FLOAT32)放在保持暫存器 0、1,手冊卻沒寫字組順序。起始程式用預設的順序讀,結果很怪。依序完成任務:

  1. 直接執行,看讀到的值。
  2. 改 word_order,印出合理的溫度(應該是 36.625)。
  3. 把設定值 55.5 用同一種字組順序轉成暫存器,寫到保持暫存器 4、5(convert_to_registers 加 write_registers),PLC 收到正確的值就會亮「設定值已接受」。
  4. 回答一個問題。

小測驗:範圍與拆分

1.

能源表的累計電量是 250000 kWh(整數),最適合用哪種型別放進 Modbus 暫存器?

2.

下面的程式會印出什麼?

value = 70000
print([value // 65536, value % 65536])
3.

下面的程式會印出什麼?

import struct
raw = struct.pack(">HH", 65535, 65535)
print(struct.unpack(">i", raw)[0])
第 1 次作答

小測驗:字組順序

1.

下面的程式模擬「設備用低位字組在前(CDAB)」,會印出什麼?

import struct
regs = list(struct.unpack(">HH", struct.pack(">f", 1.5)))
print(regs, regs[::-1])
2.

同一台設備,用監控軟體甲讀到 25.3 °C,用你的 Python 程式讀到 1.2e+12。最先該檢查什麼?

第 1 次作答

重點整理

  • 一個暫存器 16 位元:無號 0~65535、有號 −32768~32767。放不下或要小數時,用兩個暫存器組成 32 位元。
  • INT32:高位字組=商(÷ 65536),低位字組=餘數;負數是二補數。struct 的 > 是大端序,H 是 16 位元無號、i 是 32 位元有號、f 是單精度浮點數。
  • FLOAT32 只有約 7 位有效數字,23.4 讀回來是 23.399999618530273,顯示時取到需要的位數。
  • 一個暫存器內固定大端序,兩個暫存器的先後各廠牌不同(ABCD、CDAB…);選錯只會得到不合理的值,不會有錯誤訊息。
  • pymodbus:client.convert_from_registers(regs, client.DATATYPE.FLOAT32, word_order="little") 讀,convert_to_registers 寫,再用 write_registers 送出。

下一課換一種通訊方式:OPC UA 不只傳數字,還傳名稱、型別與結構。

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