Modbus ASCII 獲取資料

我本梁人發表於2024-08-27

根據高低溫試驗箱協議讀取資料

1.協議內容

8.1:通訊協議介紹
8.1.5 通訊設定
本通訊協議使用非同步序列通訊方式,1 個起始位、8 個資料位、2 個停止
位、無奇偶校驗資料通訊格式,其中資料位8 位,第1 位為最高位(MSB),第8
位為最低位(LSB)。
8.1.6 資料格式
通訊採用直接存取S7-200 V 儲存器資料的方式,所有的引數均放置於S7-200 V儲存器中,S7-200 中的資料型別為BYTE(位元組)、INT(有符號整數)、WORD(無符號整數)、DWORD(無符號長整)、LONG(有符號長整)、FLOAT
(浮點數)等格式,位操作按位元組方式操作,一個位元組8 個位。其中BYTE 長度
為1位元組;INT 和WORD為2位元組,先高後低;DWORD和LONG 為4位元組,
先高後低;浮點數為4位元組。詳細資料可參考西門子SIMATIC S7-200 可程式設計控
制器系統手冊。
8.1.7 讀引數命令
命令格式:>MMVDUUUUr
>:起始字元
MM:機號(在程式設計時因該轉換為16進位制資料)
VD:讀命令
UUUU:S7200 內部V 儲存器地址(在程式設計時因該轉換為16 進位制數
據)
r:回車字元

響應資料格式:<MMVDUUUUaabbccddee…r
<MMVDUUUU:響應命令頭
aabbccddee:從指定的V單元開始的128位元組,每2個字元代表一個位元組。
r:回車字元

8.1.8 PLC地址說明

引數名稱 V地址單元 資料格式 資料說明
執行狀態 904 int 0 停止 1 執行 2 暫停
溫度測量值 804 float 單位:℃
溼度測量值 860 float 單位:RH%

2.使用串列埠助手除錯

  1. 串列埠助手設定
串列埠引數 引數值
波特率 9600
資料位 8
停止位 2
校驗位
流控
  1. 除錯截圖
    img
    命令說明 要在命令後面新增回車,否則PLC無法識別命令。
>00VD0388 :獲取裝置執行狀態  返回結果: <00VD0388000000010000000200040000000000000000000000000000000000000000000000000000000000000000000000000000000000FA03B6000000FA0000FDDA0000
>00VD0324 :獲取溫度測量值    返回結果:<00VD032441EA980041EABDD541F6580041FBE0000000000044864400447EBA00000000000000000000000000000000000000000041C80000000000000000000000000000
>00VD035C :獲取溼度測量值    返回結果:<00VD035C00000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000100000002000400000000000000000000

根據命令返回結果,解析資料,獲取溫度測量值和溼度測量值。

1.由於返回結果為16進位制,需要將16進位制進行狀態。

2.溫度測量值和溼度測量值在返回結果中的位置分別為:41EA9800和00000000,需要將這兩個值轉換為float型別。
3.執行狀態在返回結果中的位置為:0000(擷取命令後4位),轉換為整數值為0。

4.溫度測量值為41EA9800(擷取命令後8位),轉換為浮點數為:29.324219。

5.溼度測量值為00000000(擷取命令後8位),轉換為浮點數為:0。

3.C# 使用 SerialPort 傳送命令接收資料

  1. 初始化串列埠資訊並開啟串列埠
        private void OpenCom()
        {

            // 建立SerialPort物件
            serialPort = new SerialPort(txtPort.Text.Trim(), 9600, Parity.None, 8, StopBits.Two);

            serialPort.ReadTimeout = 1000;   //串列埠讀取超時時間
            serialPort.WriteTimeout = 1000;   //串列埠寫入超時時間 
            // 開啟串列埠
            serialPort.Open();
        }
  1. 傳送命令並接收資料
重點:將字串轉換為ASCII碼位元組陣列 byte[] asciiBytes = Encoding.ASCII.GetBytes(request); 如果不透過ASCII碼位元組陣列傳送,則無法正確接收資料。

img

public string SendOrderToPLC(string request)
        {
            string txt = string.Empty;
            try
            {
                OpenCom();
                 
                // 將字串轉換為ASCII碼位元組陣列
                byte[] asciiBytes = Encoding.ASCII.GetBytes(request);

                // 傳送位元組陣列
                serialPort.Write(asciiBytes, 0, asciiBytes.Length);
                //等待資料接收完成 資料量小等待時間可小,資料量大等待時間長
                Thread.Sleep(1000);

                ASCIIEncoding ascii = new ASCIIEncoding();
                byte[] readBuffer = new byte[serialPort.BytesToRead];
                serialPort.Read(readBuffer, 0, readBuffer.Length);

                if (readBuffer.Length > 14)
                {
                    txt = ascii.GetString(readBuffer);

                    // 關閉串列埠
                    serialPort.Close();
                    return txt;
                }
                else
                {
                    this.Invoke(new Action(() =>
                    {
                        this.labMes.Text = "No response received";
                    }));
                    serialPort.Close();
                    return txt;
                }
            }
            catch (Exception ex)
            {
                txt = null;
                this.Invoke(new Action(() =>
                {
                    this.labMes.Text = ex.Message;
                }));
                return txt;
            }
        }
  1. 處理資料
     處理裝置執行狀態資料
    //獲取裝置執行狀態  ,取的是整數  所以16進製取4位;排除前面的<00VD0388命令  
    /*0 停止 1 執行 2 暫停 
     */
    var stringSub = result.Substring(9, 4); 
    var st = HexToDecimal(stringSub);

    處理溫度資料
    /*溫度取的是浮點數 所以16進製取8位;排除前面的 < 00VD0324命令  單位:℃
      */
    var stringSub = result.Substring(9, 8);
    var st = HexToDecimal(stringSub);


    /*溼度取的是浮點數 所以16進製取8位;排除前面的 < 00VD035C命令  單位:RH%
      */
    var stringSub = result.Substring(9, 8);
    var st = HexToDecimal(stringSub);

4.資料轉換方法

        /// <summary>
        /// 將16進位制字串轉換為浮點數
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        static double HexToDecimal(string hex)
        {
            uint intValue = Convert.ToUInt32(hex, 16);

            // 將整數值轉換為單精度浮點數
            float floatValue = BitConverter.ToSingle(BitConverter.GetBytes(intValue), 0);

            // 輸出結果
            Console.WriteLine("Hex: " + hex);
            Console.WriteLine("Float: " + floatValue);
            return floatValue;
        }

相關文章