2023年10月26日 星期四

[ESP32]如何透過Modbus和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、即時顯示資料和儲存於資料庫的網頁系統,如下影片。

 


沒有留言:

張貼留言