Modbus串口【03】读取线圈功能码02H

本文详细介绍了Modbus协议中02H功能码的作用,用于读取从设备的离散输入状态(DI)。文章通过解析询问和响应报文的格式,提供了一个编码示例来演示如何实现读取线圈状态,并给出了调试结果。内容适合于熟悉Modbus协议的读者,帮助他们更好地理解和应用该功能。
摘要由CSDN通过智能技术生成

新芽,破土生长.png

在破土而出的那刻,小草就做好了拼尽全力成长的准备,加油,永远热情向前!
本文主要介绍了Modbus读取输出线圈的状态02H功能码的询问报文和响应报文的格式以及含义,也通过编码实现读取线圈状态示例,希望对你理解Modbus如何读取线圈状态有点帮助。欢迎点赞 + 关注,第一时间了解更多Modbus信息。

1、02H功能码干什么用?

1.1、一个问题:02H功能码是干什么用?

02H功能码用于读取从设备的离散输入(开关量),即DI(Discrete Input)的ON/OFF状态。根据消息帧格式,我们可以知道需要读取的离散输入寄存器的起始地址和数目,Modbus支持读取1-2000个连续的离散量输入状态。如果从设备接受主设备的请求则回复功能码02,并返回离散量且输入各变量的当前状态。如果返回的离散输入数量的个数不是8个整数倍,将用0填充最后的数据字节的剩余位。

2、02H功能码格式:

主站询问报文格式:

从站地址功能码起始地址(高位)起始地址(低位)线圈数量(高位)线圈数量(低位)CRC
0x110x020x000xC40x000x1DXXXX

主站询问报文格式:【从站地址】+【功能码】+【起始地址(高位)】+【起始地址(低位)】+【线圈数量(高位)】+【线圈数量(低位)】+CRC ;

从站应答报文格式:

从站地址功能码字节计数线圈状态20-27线圈状态28-35线圈状态36-43线圈状态44-46CRC
0x110x020x040xCD0x6B0xB20x05XXXX

从站应答报文格式:【从站地址】+【功能码】+【字节计数】+【线圈状态(根据实际确定数量)】+【CRC校验】

3、代码示例:

【注】Modbus串行链路是一个专题,有些通用方法,前面写过的不再在进行编写,请参考【03】之前的文章。

目的:我们是想实现读取线圈的输入状态,即是DI量的值。DI的开关量状态只有两种ON/OFF,对应我们现实中的开关就是true和false,对应bit位的值就是1和0,那就是根据报文具体要求读取字节中位的值。

3.1、在ModbusRTU实体类中创建读取线圈状态的方法

思路:读取线圈的状态:拼接报文===>>>发送报文===>>>接收报文===>>>判断,解析报文===>>>截取报文===>>>返回字节数组;

//读取线圈状态的方法:ReadCoilInputStatus
public byte[] ReadCoilInputStatus(int iDeviceAdd, int ininiAddress, int iReadLength)
        {
            //【01】发送的报文拼接,此处用到我们实体类中ByteArray中的方法
            ByteArray SendCommand = new ByteArray();
            SendCommand.Add(new byte[] { (byte)iDeviceAdd, 0x02, (byte)(iniAddress / 256), (byte)(iniAddress % 256) });
            SendCommand.Add(new byte[] { (byte)(iReadLength / 256), (byte)(iReadLength % 256) });
            SendCommand.Add(Crc16(SendCommand.array, 6));

            //【02】发送报文 接收报文
            int byteLength = 0;
            if (iReadLength % 8 == 0)
            {
                byteLength = iReadLength / 8;
            }
            else
            {
                byteLength = iReadLength / 8 + 1;
            }
            //思考一下:为什么是5+byteLength===>>>【由返回报文的格式决定的】;
            byte[] resByteArray = new byte[5 + byteLength];
            if (SendData(SendCommand.array, ref resByteArray))
            {
                //【03】解析报文://验证:功能码+字节计数
                if (resByteArray[1] == 0x02 && resByteArray[2] == byteLength)
                {
                    //调用截取字节数据的方法
                    return BoolGetByteArray(resByteArray, 3, byteLength);
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }


//截取字节数组的方法
private byte[] BoolGetByteArray(byte[] dest,int offset,int count)
{
     byte[] res = new byte[count];
    //我们的目标数组的长度一定要大于:偏移量+读取长度;
     if (dest != null && dest.Length >= offset + count)
     {
         for (int i = 0; i < count; i++)
         {
              res[i] = dest[offset + i];
          }
          return res;
     }
     else
     {
        return null;
      }    
}

3.2、UI后台代码

// 在UI后台代码中的btn_Read_Click方法中我们修改相关读取线圈状态的相关代码:case VarType.Bit:
//创建读取线圈状态的字节数组===>>>改写了上次读取线圈输出状态的字节数组变量
            byte[] stateresult = null;
            switch (varType)
            {
                case VarType.Bit:
                    switch (storeArea)
                    {
                        case StoreArea.输入状态1x:
                            stateresult = objModbus.ReadCoilInputStatus(DevAdd, Address, Length);
                            break;
                        case StoreArea.输出线圈0x:
                        case StoreArea.输出寄存器4x:
                        case StoreArea.输入寄存器3x:
                            AddLog(1,"读取失败,存储区类型不正确");
                            return;
                    }
                    //  binarystring ,最终二进制的结果====>>>>我们就是针对这个进行解析的
                    string binarystring = string.Empty;
                    if (stateResult != null)
                    {
                        foreach (var item in stateResult)
                        {
                            //将位数据进行颠倒,将字节转换成二进制,Padleft:是补足8位,不足的话用0代替;
                            char[] charvalue = Convert.ToString(item, 2).PadLeft(8, '0').ToCharArray();
                            Array.Reverse(charvalue);
                            binarystring += new string(charvalue);
                        }
                        AddLog(0, "读取成功,结果为:"+binarystring.Substring(0,Length));
                    }
                    else
                    {
                        AddLog(1,"读取失败,请检查地址、类型或者连接状态");
                    }
                    break;

4、调试结果:

在这里插入图片描述

作者:小羊,软件开发/技术写作者,欢迎关注,我们一起探讨有趣的编程历程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昆腾码头羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值