[ESP32]ESP32 as Modbus Master and Receive Data from Gauge with Serial Port
對於既有老舊的工業或實驗設備機台,嵌入工業數顯表頭並顯示設備運作參數和數據,以讓巡檢人員或操作人員手抄記錄數據,是常見作法。然而,若可將既有設備機台的表頭更換為具備Modbus通訊功能的表頭,並連接便宜的單晶片開發板,使其自動即時顯示運作參數和紀錄數據,將可釋放巡檢和操作人力並避免手抄錯誤。甚至可進一步連結網路,讓既有老舊的設備機台升級為IIOT設備。
在建置上述系統前,先行利用Arduino IDE、一片ESP32單晶片開發板和一片RS485-TTL的USB轉接模塊來測試一個具有RS485接口數顯表頭,看是否可順利發出request和接收到相應數據。另外,在該Modbus RTU架構下,ESP32為Master,RS485接口數顯表頭為Slaver,由ESP32發出request,藉由表頭回傳相應數據。
a.首先得先解讀該RS485接口表頭的通訊協議
這是一款可顯示電流,電壓和溫度的數顯表頭,由下列協議內容可知,電壓為第3和第4字節的高低位元組合,電流為第5和第6字節的高低位元組合,溫度為第7和第8字節的高低位元組合。
b.Arduino程式碼
其中有一個部分需特別說明,因其回傳數據幀的起始位置會出現非預期位移狀態,為了確保數據的起始位置正確,利用原Modbus協議內的設備站號(01)和命令(03)作為判斷。換言之,以01 03開頭的數據才是正確的數據幀。
#include <Arduino.h>
void setup() {
Serial.begin(115200); // for PC serial port to check data
Serial2.begin(9600, SERIAL_8N1, 16, 17); // Serial2即是指定esp32的RX2(pin 16)和TX2(pin 17)接腳,Baud rate:9600
}
void loop() {
// Modbus請求數據的協議語法 for RS485設備,一般需參考設備的modbus協議規格文件
byte requestData[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x08, 0x44, 0x0C};
// 發送請求到RS485設備
Serial2.write(requestData, sizeof(requestData));
// 印出發送請求數據在監看視窗中
Serial.print("Sent request: ");
for (int i = 0; i < sizeof(requestData); i++) {
Serial.print(requestData[i], HEX);
Serial.print(" ");
}
Serial.println();
// 等待RS485回傳數據
delay(100);
//檢查從RS485回傳的數據,並尋找數據幀的起始(第一個和第二個)字節0x01 0x03,以避免數據幀位移狀態而錯誤
while(true){
if (Serial2.available()) {
byte startByte = Serial2.read();
if (startByte == 1) {
if (Serial2.available()) {
byte secondByte = Serial2.read();
if (secondByte == 3) {
break; // 找到正确的起始位置
}
}
}
}
}
// 繼續讀取剩餘的數據幀
byte receivedData[21];
receivedData[0] = 1;
receivedData[1] = 3;
Serial2.readBytes(&receivedData[2], 19);
// 印出接收的所有數據在監看視窗中,共21個字節
Serial.print("Received response: ");
for (int i = 0; i < 21; i++) {
Serial.print(receivedData[i], HEX);
Serial.print(" ");
}
Serial.println();
// 解析回傳數據
// 電壓:字節位置是 3 和 4
uint16_t voltage = (receivedData[3] << 8) | receivedData[4]; //高位元字節左移8位並與低位元字節整併(該rs485設備的modbus協議)
// 將 voltage 除以100,並將其顯示到小數點第二位
float voltageFloat = voltage/100.0;
Serial.print("電壓: ");
Serial.print(voltageFloat,2);//將其顯示到小數點第二位
Serial.print("V");
Serial.println();
// 電流:字節位置是 5 和 6
uint16_t current = (receivedData[5] << 8) | receivedData[6]; //高位元字節左移8位並與低位元字節整併(該rs485設備的modbus協議)
// 將 current 除以100,並將其顯示到小數點第三位
float currentFloat = current/100.0;
Serial.print("電流: ");
Serial.print(currentFloat,3);//將其顯示到小數點第三位
Serial.print("A");
Serial.println();
// 溫度:字節位置是 7 和 8
uint16_t temperature = (receivedData[7] << 8) | receivedData[8]; //高位元字節左移8位並與低位元字節整併(該rs485設備的modbus協議)
Serial.print("溫度: ");
Serial.print(temperature);
Serial.print("C");
Serial.println();
delay(1000); //一秒鐘讀取一次數據
}
c.建置簡易系統
若要進一步讓使用人員容易操作,則可利用前端(html 和 Javascript)和後端(PHP 和 SQL)建置一個具備基本UI、即時顯示資料和儲存於資料庫的網頁系統,如下影片。
[ESP32]Make ESP32 as Modbus RTU Master and Receive Data from Gauge with Wifi