ETJava Beta | Java    注册   登录
  • 搜索:
  • Modbus ASCII 获取数据

    发表于      阅读(1)     博客类别:Crawler     转自:https://www.cnblogs.com/wofeiliangren/p/18383057
    如有侵权 请联系我们删除  (页面底部联系我们)  

    根据高低温试验箱协议读取数据

    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;
            }