Modbus 協議中的記憶體
Modbus 協議中的記憶體規劃如下:
- 線圈(Coils):線圈是一個包含單個位元的可讀寫數據區域,通常用於控制輸出設備(如繼電器、燈光等)。每個線圈的狀態可以是開(ON)或關(OFF)。
- 輸入線圈(Input Coils):輸入線圈是一個包含單個位元的只讀數據區域,通常用於表示輸入信號(如開關狀態、傳感器狀態等)。
- 保持寄存器(Holding Registers):保持寄存器是一個包含 16 位元資料的可讀寫數據區域,用於存儲控制器的參數、配置等信息。
- 輸入寄存器(Input Registers):輸入寄存器是一個包含 16 位元資料的只讀數據區域,用於表示輸入信號的狀態、測量值等。
這些內存區域的地址範圍從 0 開始,每個區域都有自己的地址空間。通常,線圈和輸入線圈的地址範圍是從 0 到 65535,而保持寄存器和輸入寄存器的地址範圍也是從 0 到 65535。
通過這種內存規劃,Modbus 協議可以簡單而高效地管理不同類型的數據,並提供了對這些數據的讀取和寫入操作。
PLC的實體Input接線端通常對應到Modbus協議中的「輸入線圈(Input Coils)」或「輸入寄存器(Input Registers)」。這取決於PLC和Modbus裝置之間的通信配置和數據交換方式。
- 如果PLC的實體Input接線端代表的是開關狀態或二進制信號,則通常對應到Modbus協議中的「輸入線圈(Input Coils)」。這些輸入線圈的狀態可以是開(ON)或關(OFF),並且可以由Modbus Master訪問和讀取。
- 如果PLC的實體Input接線端代表的是模擬量(如溫度、壓力等)或其他數值型信號,則通常對應到Modbus協議中的「輸入寄存器(Input Registers)」。這些輸入寄存器中存儲的是16位元的數值資料,可以由Modbus Master訪問和讀取。
因此,PLC的實體Input接線端對應的Modbus記憶體規劃取決於具體的應用場景和通信配置。
PLC的實體Output接線端通常對應到Modbus協議中的「線圈(Coils)」或「保持寄存器(Holding Registers)」。同樣地,這取決於PLC和Modbus裝置之間的通信配置和數據交換方式。
- 如果PLC的實體Output接線端用於控制開關類型的設備(如繼電器、閥門等),則通常對應到Modbus協議中的「線圈(Coils)」。這些線圈的狀態可以是開(ON)或關(OFF),並且可以由Modbus Master寫入和控制。
- 如果PLC的實體Output接線端用於輸出數值型信號(如控制閥門的開度、調節器的設置值等),則通常對應到Modbus協議中的「保持寄存器(Holding Registers)」。這些保持寄存器中存儲的是16位元的數值資料,可以由Modbus Master寫入和控制。
因此,PLC的實體Output接線端對應的Modbus記憶體規劃也取決於具體的應用場景和通信配置。
Data Addresses | Read | Write Single | Write Multiple |
Discrete Output Coils 0xxxx 繼電器 | FC01 | FC05 | FC15 |
Discrete Input Contacts 1xxxx ON/OF | FC02 | NA | NA |
Analog Input Registers 3xxxx 感測器數值 | FC04 | NA | NA |
Analog Output Holding Registers 4xxxx | FC03 | FC06 | FC16 |
如果有接硬體的話,一些開關類的裝置會接在PLC的DI處,對應Discrete Input Contacts 1xxxx 記憶體區塊。如果需要推動繼電器等裝置會對應Discrete Output Coils 0xxxx 記憶體區塊。
因為目前情境並沒有實際與硬體接線,故會以讀寫Analog Output Holding Registers 4xxxx來進行模擬。
競賽主題 5.1 機台磨損
Adress | 作用 |
15 | 蓋印頭不足燈號 |
24 | 料件:蓋印頭數量 |
25 | 蓋印頭警示數量 |
26 | 蓋印頭剩餘數量 |
Node-Red 流程可以分為三個區塊:
- 輪訊Modbus Memory
- 寫入Modubs Memory
- 寫入Global Memory
Manual Getter FC3 Node | 作用 |
Address指定讀取的開始位址 Quantity指定讀取的長度 |
如何調整Dashboard UI 元件的Layout?
Function Node | 作用 |
global.set(‘address_24’, msg.payload);return msg; | 程式一執行紿於初始值10, 並將10設定給Global.address_24變數 |
let val = global.get(‘address_24’);msg.payload = { value: val, ‘fc’: 6, ‘unitid’: 1, ‘address’: 24 , ‘quantity’: 1 };return msg; | 蓋印頭數量寫回 modbus memory |
Function Node | 作用 |
global.set(‘address_25’, msg.payload);return msg; | 程式一執行紿於初始值4, 並將4設定給Global.address_25變數 |
let val = global.get(‘address_25’);msg.payload = { value: val, ‘fc’: 6, ‘unitid’: 1, ‘address’: 25 , ‘quantity’: 1 };return msg; | 蓋印頭警示數量寫回 modbus memory |
Function Node | 作用 |
let val = global.get(‘address_26’);if (val > 0) { val -= 1; global.get(‘address_26’, val);}msg.payload = { value: val, ‘fc’: 6, ‘unitid’: 1, ‘address’: 26 , ‘quantity’: 1 };return msg; | 蓋印頭數量 – 1 後並寫回modbus memory |
Function Node | 作用 |
let val = global.get(‘address_24’);msg.payload = { value: val, ‘fc’: 6, ‘unitid’: 1, ‘address’: 26 , ‘quantity’: 1 };return msg; | 將使用者在GUI上設定的蓋印頭數量,寫入modbus中 GUI上的蓋印頭數量是同步設定在Global.address_24變數 |
Function Node | 作用 |
<div style=”border: 1px solid black; border-radius: 100%; background-color: {{msg.payload}}; width: 20px; height: 20px;margin:10px auto”></div> | 這個寫法是網頁的寫法:圓: border-radius: 100%;圓的邊框:border: 1px solid black;圓的顏色:動態指定由前面的Node的回傳值圓的大小:width 20px; height 20px; |
if (msg.payload[26] > msg.payload[25]) { msg.payload = ‘lime’;} else { msg.payload = ‘red’;}return msg; | msg.payload[26] => 印頭的剩餘數量msg.payload[25] => 警示數量 印頭的剩餘數量 > 警示數量 大於: 綠色 小於或等於:紅色 |
let val = 0;if (msg.payload === ‘red’) { val = 1;}msg.payload = { value: val, ‘fc’: 6, ‘unitid’: 1, ‘address’: 15, ‘quantity’: 1 };return msg; | 當數量小於或等於時,就將modbus address 15的設為1 modbus adderss 15:蓋印頭不足燈號 |
Function Node | 作用 |
let max = msg.payload[24];msg.payload = msg.payload[26]; msg.ui_control = { “min”: 0, “max”: max };return msg;max 值為 7msg.payload 值為 6 | msg.payload[24] => 料件:蓋印頭數量msg.payload[26] => 蓋印頭剩餘數量 源頭的msg是每秒讀出的modbus memory目的端msg是要給Guage Node的值msg.payload = 蓋印頭剩餘數量 msg.ui_control 的寫法是重點,指定Guage Node元件的上、下限。 |
Adress | 作用 |
0 | 待生產數量 |
2 | 製造時間,秒 |
5 | 生產數累計 |
6 | 良品數累計 |
7 | 不良品數累計 |
虛擬產線示意圖
- 紅色區塊:每秒讀Modbus Memory Address 0 ~ 29
- 藍色區塊:將Modbus Memory值,設定給Glbal變數
- 綠色區塊:將Modbus Memory的值,更新到GUI
Function Node | 作用 |
let in_process = global.get(‘in_process’);if (in_process == false){ let total = msg.payload[5]; let good = msg.payload[6]; msg.payload = Math.floor((good / total) * 100); return msg;} | msg.playload[5] => 已生產數量msg.playload[6] => 良品數量 Math.floor() 函式會回傳小於等於所給數字的最大整數。console.log(Math.floor(5.95));// Expected output: 5 console.log(Math.floor(5.05));// Expected output: 5 console.log(Math.floor(5));// Expected output: 5 console.log(Math.floor(-5.05));// Expected output: -6 |
將 text node 所要顯示的值指定為 msg.payload[0], 讀取address 0的值料。
- 紅色區塊:初始化Text Input Node及Global.address_0變數
- 綠色區塊:將Global.address_0變數的值寫入Modbus Memory Address 0
- 紅色區塊:開始累計加工時間
- 綠色區塊:更新待生產數量及生產數量
Function Node | 作用 |
let val = global.get(‘address_0’);if (val > 0) { global.set(‘in_process’, true); return msg;} else { global.set(‘in_process’, false); return null;} | 判斷待生產數是否 > 0 是: 設定生產中 否:設定未產產 |
Function Node | 作用 |
拫據Switch Node的開關,設定Global.AOI變數,並更新GUI。if (msg.payload) { msg.payload = ‘良品’; global.set(‘aoi’, true);} else { msg.payload = ‘不良品’; global.set(‘aoi’, false);}return msg; | 使用者切換檢測判定結果的Switch,並將Switch的值寫入Global.aoi變數中。 |
Function Node | 作用 |
let val = global.get(‘in_process’);if (val) { return msg;} else { return null;} | 判斷是否在生產中,如果不是就跳開。 回傳 null 就是跳開後面的邏輯。 |
global.set(‘break_timer’, 1);global.set(‘in_process’, false);return msg; | 停止累計加工時間的變數設為1 生產中的變數設為False |
let aoi = global.get(‘aoi’);if (aoi) { let val = global.get(“address_6”); val += 1 msg.payload = { value: val, ‘fc’: 6, ‘unitid’: 1, ‘address’: 6, ‘quantity’: 1 };} else { let val = global.get(“address_7”); val += 1 msg.payload = { value: val, ‘fc’: 6, ‘unitid’: 1, ‘address’: 7, ‘quantity’: 1 };}return msg; | 依據 檢測結果 aoi == True, 良品, address 6, +1 aoi == False, 不良品, address 7, +1 |
Function Node | 作用 |
msg.payload = { value: 0, ‘fc’: 6, ‘unitid’: 1, ‘address’: 0, ‘quantity’: 1 };return msg; | address 0:待生產數量 |
msg.payload = { value: 0, ‘fc’: 6, ‘unitid’: 1, ‘address’: 2, ‘quantity’: 1 };return msg; | address 2: 加工累計時間 |
let val = [0, 0, 0];msg.payload = { value: val, ‘fc’: 16, ‘unitid’: 1, ‘address’: 5, ‘quantity’: 3 };return msg; | address 5, 6, 7: 生產累計、良品累計、不良品累計 |
Function Node | 作用 |
msg.payload = msg.payload[1];return msg; | 依address_1為例,其它的作法一樣將modbus address 1的值指定給GUI LED Node |
LED Node 外觀 | LED Node 設定值 |
- 紅色區塊:從Modbus Memory讀出數據,指定給GUI Node
- 緣色區塊:當GUI Node被切換時,會將其值寫入Modbus Memory
Function Node | 作用 |
msg.payload = msg.payload[1];return msg; | 依address_1為例,其它的作法一樣將modbus address 1的值指定給GUI LED Node |
let val = msg.payload;msg.payload = { value: val, ‘fc’: 6, ‘unitid’: 1, ‘address’: 1, ‘quantity’: 1 };return msg; | 這段是將GUI Node的值指定給val let val = msg.payload; 將val值寫入modbus memory |