大致解釋完 Modbus portocol 後,接下來就是實作的部分。記得過去在談 Modbus protocol 第一篇的時候有提到,這次要實現系統架構的長相如下圖,客戶希望可以用 PC 透過指定某個特定 IP 的 Modbus TCP Slave 使其再去控制底下的 Modbus RTU Slave。
比方說,總共有 3 組同網域中不同的 IP (即 Mobus TCP Slave,eg. 192.168.1.3 and .4 and .5),接著 PC (Modbus TCP Master) 透過 Modbus TCP 傳輸自定義的 data content 給特定 IP (eg. 192.168.1.3) 的 Modbus TCP Slave,而 Modbus TCP Slave 接到訊息後根據自定義的 spec 去 decode 來自 Master 的 data content,接著 decode 完的資訊 Modbus RTU Master (和 Modbus TCP Slave 是同一人) 利用 Modbus RTU 透過 RS485 傳送資料給特定 address 的 Modbus RTU Slave,完成控制。
圖片出處:Fun and Easy Modbus RTU protocol
而實作的 (上) 篇,就會從上圖的右半邊 Modbus TCP (Slave) <——Ethernet——> Modbus TCP (Master) 的部分開始說起,而 (下) 篇就會接續實作剩下左半邊,也就是 Modbus RTU (Master) 對 Modbus RTU (Slave) (即這次的主角 – 電子標籤)。為了更清楚的展示要實驗的內容,我做了簡圖以幫助大家快速理解:
整個硬體配置就如同上圖所述,因為我是用我的雷蛇筆電做開發,其本身不包含 RJ45 的網路孔,因此有兩個選擇,第一是利用 USB 外接網路卡神器,第二則是利用 WiFi,由於在同個網域底下測試,所以 WiFi 是完全可行的。
另一邊 ENC28J60 本身就是一個 Arduino 用來使用 Ethernet 很好的外掛 module,那當然就是利用它搭起 AP 和 Uno 之間 Ethernet 的橋樑。
至於軟體方面,透過點亮 or 熄滅 UNO 上外掛的一顆 LED 作為實驗 Modbus TCP 的依據,用 LED 來評判 Modbus protocol 是否被打通。畢竟一條 IP 打通了,客戶要接個 10 條也不是問題,只要 AP (或用 switch) LAN 孔夠多就行。
Modbus TCP Slave – UNO R3
那我們就從 Modbus TCP slave 端開始吧。slave 端我是利用 mac 作為開發環境。
ENC28J60 在網路上有相當多的資源可以參考,在此附上我使用的 github repo 連結:EtherCard。repo README.md 中還清楚的附上硬體接線,利用 SPI 和 UNO 做溝通,這部分我想照著做應該是不會出現太大的問題。當然,還要準備 RJ45 網路線將 EtherCard 和家裡的 AP 接上。
軟體部分,我建議若是 Mac 開發者,直接利用 Arduino 內建的 library manager 下載 EtherCard 這個 library 即可。下載後開啟 library 底下的 testDHCP sample code,編譯燒錄,打開 console 看看是否有抓到 MAC address 和 My IP,如下圖:
這個資訊很重要,是等等要作為 Modbus TCP slave 的資訊並讓 TCP Master 辨別的依據。
確定 ENC28J60 可以順利運作後,接著是重頭戲 – Modbus protcol library for Arduino。由於網路上也滿多資源,再經過測試後我認為最好用的 library 也在此附上其 github repo:modbus-arduino。這個 library 包山包海,不過我們只會用到 ModbusIP_ENC28J60 這個 directory 裡面的東西,此 dir 底下有四個 sample,我們會利用 Lamp 做實驗,看能不能順利透過 Modbus protocol (的 single bit coil) 將 LED 點亮。
Lamp 的 sample code 中,可以看到 setup function 內的 mac 和 ip byte array,如下圖:
將這兩個 byte array 內容改成剛剛在 testDHCP sample 中得到的 MAC address 和 My ip,這是等等要註冊給 Modbus object (如圖片中最後那行 configuration) 的資訊。
另外在 Lamp sample code 中也有一個值得分享的東西 – LAMP1_COIL 這個常數。如同上篇介紹 Modbus protocol 時,提到 registers type 的概念,00001 – 09999 屬於 Coils 的部分,code 中 LAMP1_COIL default 是 100,事實上在有效的範圍要設多少都是沒問題的。
slave 端的最後是最簡單的 LED,我將 GPIO 7 作為我的 LED pin,編譯燒錄後一切就緒,保持接電狀態,接著搞定 Master 端後就萬事俱備了。
Modbus TCP Master – Razer blade
由於客戶打算自己設計 PC 端程式,而我只是為了打通 Modbus over TCP,因此便在網路上尋找是否有免費的 Modbus 軟體能讓我做打通的測試,結果發現還不少,最終在眾多選擇中找到了一個比較好用的,稱作 simply Modbus。
在 simply Modbus 官網上,可從裡面看到許多先前在第二篇提到的名詞 (eg. RTU, ASCII, TCP),我們在這裡要選用 TCP Client 的版本作為我們實驗的媒介,在此附上下載連結:SimplyModbusTCPclient7.1.2。
(注意!目前 simply Modbus 的軟體只有支援 Windows,Mac 並不支援喔!)
如上述 slave 的部分中提到,slave 端利用 single bit coil 對 Modbus 註冊 LED 的狀態,由於 LED 也就兩個狀態 ON (HIGH) or OFF (LOW),用 coil 綽綽有餘,而在 Master 端直接 Write Coils 即可控制 LED 亮滅!對原理比較沒興趣的人也不用了解沒關係,因為 simply Modbus 有提供 UI 介面 (雖然頗不好看),選一選就可以了。
下載後打開 Modbus TCP client 會看到下圖:
在此僅說明必要操作的部分,其他部分有興趣的可以自行研究。首先,在 IP address 的 textbox 輸入剛剛在準備 Modbus TCP slave 端時,利用 testDHCP sample code 所獲得的 My IP (我的是 192.168.0.20),port 502 是 Modbus default port 不用動,即可按下 CONNECT,若無誤,會如上圖顯示,變為 DISCONNECT,表示確實連上了 Modbus TCP slave (即 UNO R3)。
然而,這個 UI 介面是給 read function 使用的,而我們要做的是 Write Coil,因此得按下如上圖紅圈圈起來的 Write 的鍵,看到的畫面如下:
在分享 Modbus TCP slave 時有提到,由於 00001 – 09999 皆屬於 Coil 之有效範圍,所以我在這也做了一個小更改,將原先 default 的 100 改成如上圖圈圈內的 11 (即 First Register 的 textbox),另外,其旁的 values to write 並不為對某個 register 進行值的設定,而是要對多少個 register 進行動作 (詳見 function code 介紹的部分),而在此我只對 number 11 這個 Coil 動作,因此設為 1。
接著就是比較需要注意的地方,如圖可以看到我有圈 minus offset 的部分,必須為 0,若有值會導致位置錯誤而不會動。
最後就是真正的 value to write (最接近底部的圈圈),設定要 write 進 coil 的值,非 0 即 1,在此我設定了 1 準備要寫進去,終於,萬事備齊了,只差按下下方的 SEND 鍵,看到底會不會動。
幸好…能夠如我所願控制 LED 亮滅,Modbus TCP 的部分順利打通了。
在此給一個小提醒,若是照著上方所有的步驟一步步將 Modbus 打通,在使用 simply Modbus 按下 SEND 的瞬間,LED 就會動作沒錯,不過 simply Modbus 會顯示 error,說是 connection 的問題,這是正常的!因為 arduino uno 內的 sample code 所使用的 library 是 default 一旦收到東西就會先 close 那次的 connection。
談完整個 Modbus TCP 實作的過程後,下篇將介紹本次專案主角的部分 – Modbus RTU 實作,近請期待。
本文同步刊登於 MakerPRO