C#通过ModbusTcp协议读写西门子PLC中的浮点数

这篇具有很好参考价值的文章主要介绍了C#通过ModbusTcp协议读写西门子PLC中的浮点数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、Modbus TCP通信概述 

MODBUS/TCP是简单的、中立厂商的用于管理和控制自动化设备的MODBUS系列通讯协议的派生产品,显而易见,它覆盖了使用TCP/IP协议的“Intranet”和“Internet”环境中MODBUS报文的用途。协议的最通用用途是为诸如PLC,I/O模块,以及连接其它简单域总线或I/O模块的网关服务的。

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

Modbus TCP协议是在RTU协议前面添加MBAP报文头,由于TCP是基于可靠连接的服务,RTU协议中的CRC校验码就不再需要,所以在Modbus TCP协议中是没有CRC校验码。(使用上的主要区别)。MBAP报文头: 识( 2字节 ) 长度( 2字节 ) 单元标识符(1字节 )

目前Modbus TCP/IP协议主要应用领域Internet或Intranet中,而以太网传输距离远、传输速度快,使得应用范围广泛传输距离远、传输速度快,使得应用范围广泛。

 二. Modbus TCP使用的功能代码

modbus的操作对象有四种:线圈、离散输入、输入寄存器、保持寄存器

线圈:PLC的输出位,开关量,在MODBUS中可读可写
离散量:PLC的输入位,开关量,在MODBUS中只读
输入寄存器:PLC中只能从模拟量输入端改变的寄存器,在MODBUS中只读
保持寄存器:PLC中用于输出模拟量信号的寄存器,在MODBUS中可读可写
根据对象的不同,modbus的功能码有:

0x01:读线圈
0x02:读离散量输入
0x03:读保持寄存器

0x04:读输入寄存器

0x05:写单个线圈
0x06:写单个保持寄存器
0x10:写多个保持寄存器
0x0F:写多个线圈

 三、nmodbus4指南

 NModbus4是一个基于C#的Modbus协议库,可用于与Modbus RTU、ASCII、TCP和UDP设备进行通信。NModbus4中文版相当于对原版进行了翻译,使得不懂英文的人能够更方便地使用这个开源库进行编程。NModbus4是用C#编写的Modbus通信协议库,它支持的Modbus协议包括Modbus RTU、ASCII、TCP和UDP,可用于编程读写Modbus设备的寄存器和线圈。它完全符合Modbus协议规范,同时通过使用的事件调用机制,能够实现断线重连的功能。

NModbus4是一个完全开源的库,可以在GitHub上免费下载和使用

四、Modbus TCP通讯应用举例 

 4.1:搭建西门子博途V15的环境

搭建西门子仿真环境,需要先前掌握这些,看本人这些博客

windows10企业版安装西门子博途V15---01准备环境

windows10企业版安装西门子博途V15---02安装软件

windows10企业版安装西门子博途V15---03安装仿真软件

windows10企业版安装西门子博途V15---04连接测试
 C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

4.2:熟悉modbusTCP环境

需要先前掌握这些,看本人这些博客

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

4.3:创建PLC仿真环境

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

4.4: 博途V15创建项目

 本文最后会提供这个项目,只要打开即可

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

 4.5:创建数据块变量

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

4.6:创建tcp连接数据块

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

4.7:创建modbustcp通信模块

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

请注意,这里为什么是BYTE 20,是因为变量mf1到mf5共10寄存器,每个寄存器占2个字节,所以是20个字节,编译完成后,下载到Plc中

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

4.8:创建监控表

 C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

以上8个步骤就完成了modbustcp服务器,接下来搞程序,来读写Plc中的浮点数

4.9:创建winform项目

打开VS2019,创建窗体项目,布局很简单,4个button按钮

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

 

4.10:添加nmodbus4库

 C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

4.11:编写“nmodbus4读取一个float”代码

 /// <summary>
        /// nmodbus4读取一个float
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            //nmodbus4读取到的数据都是ushort类型
            tcpClient = new TcpClient();
            tcpClient.Connect("192.168.1.199", 6800);//连接到主机
            master = ModbusIpMaster.CreateIp(tcpClient);//Ip 主站  
            byte slaveAddr = byte.Parse("1");//从站地址
            //ushort[] ReadHoldingRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints);表示读保持寄存器
            //slaveAddress从站地址(默认为1,通常也是1)
            //startAddress寄存器开始地址(这个地址是modbus的地址,不是Plc变量地址)
            //numberOfPoints寄存器数量(real类型占2个寄存器数量)
            ushort[] uDatas = master.ReadHoldingRegisters(slaveAddr, ushort.Parse("0"), ushort.Parse("2"));
            byte[] t = ByteArrayLib.GetByteArrayFromUShortArray(uDatas);//ushort数组转byte数组
            float[] floats = FloatLib.GetFloatArrayFromByteArray(t);//byte数组转float数组
            string fw1a = string.Join(",", floats);
            float fw1b = FloatLib.GetFloatFromByteArray(t, 0);//byte数组转float
            MessageBox.Show("方式a:" + fw1a.ToString() + ",方式b:" + fw1b.ToString());

            uDatas = master.ReadHoldingRegisters(slaveAddr, ushort.Parse("2"), ushort.Parse("2"));
            t = ByteArrayLib.GetByteArrayFromUShortArray(uDatas);
            floats = FloatLib.GetFloatArrayFromByteArray(t);
            fw1a = string.Join(",", floats);
            fw1b = FloatLib.GetFloatFromByteArray(t, 0);
            MessageBox.Show("方式a:" + fw1a.ToString() + ",方式b:" + fw1b.ToString());

            uDatas = master.ReadHoldingRegisters(slaveAddr, ushort.Parse("4"), ushort.Parse("2"));
            t = ByteArrayLib.GetByteArrayFromUShortArray(uDatas);
            floats = FloatLib.GetFloatArrayFromByteArray(t);
            fw1a = string.Join(",", floats);
            fw1b = FloatLib.GetFloatFromByteArray(t, 0);
            MessageBox.Show("方式a:" + fw1a.ToString() + ",方式b:" + fw1b.ToString());

            uDatas = master.ReadHoldingRegisters(slaveAddr, ushort.Parse("6"), ushort.Parse("2"));
            t = ByteArrayLib.GetByteArrayFromUShortArray(uDatas);
            floats = FloatLib.GetFloatArrayFromByteArray(t);
            fw1a = string.Join(",", floats);
            fw1b = FloatLib.GetFloatFromByteArray(t, 0);
            MessageBox.Show("方式a:" + fw1a.ToString() + ",方式b:" + fw1b.ToString());

            uDatas = master.ReadHoldingRegisters(slaveAddr, ushort.Parse("8"), ushort.Parse("2"));
            t = ByteArrayLib.GetByteArrayFromUShortArray(uDatas);
            floats = FloatLib.GetFloatArrayFromByteArray(t);
            fw1a = string.Join(",", floats);
            fw1b = FloatLib.GetFloatFromByteArray(t, 0);
            MessageBox.Show("方式a:" + fw1a.ToString() + ",方式b:" + fw1b.ToString());
            master.Dispose();
            tcpClient.Dispose();
        }

运行效果

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

 全部读取到了PLC中的数据

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

 nmodbus4读取到的数据都是ushort类型

 ushort[] ReadHoldingRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints);表示读保持寄存器
            slaveAddress从站地址(默认为1,通常也是1)
            startAddress寄存器开始地址(这个地址是modbus的地址,不是Plc变量地址)
            numberOfPoints寄存器数量(real类型占2个寄存器数量)

 ushort[] uDatas = master.ReadHoldingRegisters(slaveAddr, ushort.Parse("0"), ushort.Parse("2"));

这个意思是读取从站地址1中的从0开始的2个寄存器数据,即%DB4.DBD0中的数据,结果是1.1

很多人搞不清楚,这个为何是开始地址0,数量是2,这就需要明白PLC中的地址与MODBUS地址的关系,另外nmodbus4读取到的数据都是ushort类型,因此需要进行类型转换,将ushort数组转byte数组,再将byte数组转float数组

4.12:编写“nmodbus4读取全部float”代码

 /// <summary>
        /// nmodbus4读取全部
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button5_Click(object sender, EventArgs e)
        {
            tcpClient = new TcpClient();
            tcpClient.Connect("192.168.1.188", 6800);//连接到主机
            master = ModbusIpMaster.CreateIp(tcpClient);//Ip 主站  
            byte slaveAddr = byte.Parse("1");
            ushort[] uDatas = master.ReadHoldingRegisters(slaveAddr, ushort.Parse("5"), ushort.Parse("10"));
            byte[] t = ByteArrayLib.GetByteArrayFromUShortArray(uDatas);
            float[] floats = FloatLib.GetFloatArrayFromByteArray(t);
            string fw1a = string.Join(",", floats);
            MessageBox.Show(fw1a.ToString());

            master.Dispose();
            tcpClient.Dispose();
        }

运行效果

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

4.13:编写“nmodbus4写入单个浮点”代码

/// <summary>
        /// nmodbus4写入单个浮点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button7_Click(object sender, EventArgs e)
        {
            tcpClient = new TcpClient();
            tcpClient.Connect("192.168.1.199", 6800);//连接到主机
            master = ModbusIpMaster.CreateIp(tcpClient);//Ip 主站   
            //从站地址
            byte slaveAddr = byte.Parse("1");
            开始地址
            ushort startAddr = ushort.Parse("0");
            数据的值
            string vals = ("12.625");
            float[] uVals02 = vals.Split(',').Select(s => float.Parse(s)).ToArray();
            byte[] y = ByteArrayLib.GetByteArrayFromFloatArray(uVals02);
            ushort[] ushorts = UShortLib.GetUShortArrayFromByteArray(y);
            //void WriteMultipleRegisters(byte slaveAddress, ushort startAddress, ushort[] data);//写入多保持寄存器,意思是指向多个寄存器地址写入数据,也就是指同时向多个寄存器写入数据
            //slaveAddress表示从站地址,通常为1,默认也为1
            //startAddress表示寄存器开始地址,必须是ushort类型
            //data表示写入的具体数值,必须是ushort数组
            master.WriteMultipleRegisters(slaveAddr, startAddr, ushorts);//向第一个寄存器(地址是0)写入数据12.625
            MessageBox.Show("【 通过多保持寄存器】写入正数成功!");

            float floatValue = 12.625f;
            startAddr = ushort.Parse("2");
            byte[] byteArray = ByteArrayLib.GetByteArrayFromFloat(floatValue);
            //将字节数组中第0个开始的2个字节转换成ushort类型,即0,1
            ushort ua = UShortLib.GetUShortFromByteArray(byteArray, 0, DataFormat.ABCD);
            master.WriteSingleRegister(slaveAddr, startAddr, ua);//向从站地址1中的第3个寄存器(地址为2)写入数据ua
            //将字节数组中第2个开始的2个字节转换成ushort类型,即2,3 
            ushort ub = UShortLib.GetUShortFromByteArray(byteArray, 2, DataFormat.ABCD);
            startAddr = ushort.Parse("3");
            master.WriteSingleRegister(slaveAddr, startAddr, ub);//向从站地址1中的第4个寄存器(地址为3)写入数据ub
            MessageBox.Show("【 通过单保持寄存器】写入正数成功!"); 

            vals = ("-18.326");
            startAddr = ushort.Parse("8");
            uVals02 = vals.Split(',').Select(s => float.Parse(s)).ToArray();
            y = ByteArrayLib.GetByteArrayFromFloatArray(uVals02);
            ushorts = UShortLib.GetUShortArrayFromByteArray(y);
            master.WriteMultipleRegisters(slaveAddr, startAddr, ushorts);
            MessageBox.Show("【 通过多保持寄存器】写入负数成功!");

            master.Dispose();
            tcpClient.Dispose();
        }

 运行效果

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

 4.14:编写“nmodbus4写入多个浮点"代码

 /// <summary>
        /// nmodbus4写入多个浮点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button6_Click(object sender, EventArgs e)
        {
            tcpClient = new TcpClient();
            tcpClient.Connect("192.168.1.199", 6800);//连接到主机
            master = ModbusIpMaster.CreateIp(tcpClient);//Ip 主站  

            //从站地址
            byte slaveAddr = byte.Parse("1");
            //开始地址
            ushort startAddr = ushort.Parse("0");
            //数据的值
            string vals = ("4.9635,6.9635,-1.28,67,-902");
            float[] uVals02 = vals.Split(',').Select(s => float.Parse(s)).ToArray();
            byte[] y = ByteArrayLib.GetByteArrayFromFloatArray(uVals02);
            ushort[] ushorts = UShortLib.GetUShortArrayFromByteArray(y);
            master.WriteMultipleRegisters(slaveAddr, startAddr, ushorts);
            MessageBox.Show("【 多保持寄存器】写入成功!");
            master.Dispose();
            tcpClient.Dispose();
        }

 运行效果

C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

浮点数包括整数,小数,也包括正数或负数,所以正整数,负整数,正小数,负小数都可以写入

五:modbustcp协议小结

MODBUS TCP 结合了以太网物理网络和网络标准 TCP/IP 以及以 MODBUS 作为应用协议标准的数据表示方法。MODBUS TCP 通信报文被封装于以太网 TCP/IP 数据包中,MODBUS 协议规范一帧数据的最大长度为 256 个字节。

MODBUS TCP/IP 的通信系统中有两种类型的设备:MODBUS TCP/IP 客户端和服务器设备。

1.MODBUS 客户端

客户端(TCP Client)主动向服务器(TCP Server)发起连接请求,连接建立成功,仅允许客户端主动发起通讯请求。

以太网机型作为 MODBUS TCP 客户端时,通过 S_OPEN 指令建立 TCP 连接,通过 M_TCP 指令发起 MODBUS 请求。

2.MODBUS 服务器

服务器主动监听 502 端口,等待客户端连接请求,连接建立成功,响应符合 Modbus TCP 协议规范的数据通讯请求。

3.优势 

优势: 免费、简单、容易使用,Modbus协议是现在国内工业领域应用最多的协议,不只PLC设备,各种终端设备,比如水控机、水表、电表、工业秤、各种采集设备,

4.特点

  1. 采用主从问答方式进行通信

  2. Modbus TCP是应用层协议,基于传输层TCP协议实现C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序

  3. Modbus TCP端口号默认为502,但在本案例中修改成6800,当然你也可以改成别的

六:代码下载

 链接:https://pan.baidu.com/s/1mARLDATOBphLKbecj4sW8g 
提取码:lggv  

 C#通过ModbusTcp协议读写西门子PLC中的浮点数,C#上位机开发笔记,NMODBUS4,MODBUSTCP,c#,TCP通信,winform程序文章来源地址https://www.toymoban.com/news/detail-697176.html

到了这里,关于C#通过ModbusTcp协议读写西门子PLC中的浮点数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#与西门子PLC通讯——手搓S7通讯协议

    本文将尝试从源码角度,使用Tcp/Ip的方式直接与西门子PLC进行交互通讯。 往期博客参考 C#与西门子PLC通讯——新手快速入门 C#与西门子PLC通讯——熟手快速入门 建议先看一下这两篇,了解预设背景。 知其然,知其所以然。 这篇文章,我们就尝试重复造一个轮子。通过对通讯

    2024年02月04日
    浏览(45)
  • C++上位软件通过LibModbus开源库和西门子S7-1200/S7-1500/S7-200 PLC进行ModbusTcp 和ModbusRTU 通信

            一直以来上位软件比如C++等和西门子等其他品牌PLC之间的数据交换都是大家比较头疼的问题,尤其是C++上位软件程序员。传统的方法一般有OPC、Socket 等,直到LibModbus 开源库出现后这种途径对程序袁来说又有了新的选择。           1 )使用简单, 利用MUDBUS库文件

    2024年02月03日
    浏览(55)
  • C#通过S7.NET库与西门子PLC数据交互

    拉了换一个简单的界面 我新建了一个DB数据块【DB1】,右键【DB1】,点击【属性】项,【优化的块访问】默认是勾选,要想显示数据块中地址偏移量,需要把【优化的块访问】勾选取消 1、右键项目名,选择图中【管理NuGet程序包】 2、在搜索框输入【S7netplus】,我安装的是第

    2024年02月12日
    浏览(44)
  • .net通过S7.net读写西门子PLC中,字符串,bool,整数,小数及byte型

    注:.net中通过TCP/IP方式通过S7.net.dll动态库,连接到西门子PLC,西门子程序中许勾选优化块,程序读取需要 db块号+偏移量 一。使用VS项目,在项目中添加S7.net动态库 代码中引用S7.net动态库 using S7.Net; 实例化PLC服务名 /// /// 实例化PLC /// Plc S71500; 连接PLC按钮时间编写: 以上代码

    2023年04月15日
    浏览(96)
  • Python-OPCUA 读写西门子PLC设备的数据

    Python版本:3.9 在python中,通过opc ua 通讯方式向PLC中读写数据 首先安装一下opcua: pip install opcua 我们可以通过导入文件的方式,实现plc设备数据的批量读取与写入 首先 我们可以通过KEPserve软件来实时监控到PLC设备的数据,这样方便我们待会读取的时候能够更加直观 ①:右键点

    2024年02月09日
    浏览(43)
  • C#和西门子PLC使用Udp通信

    目录 一、PLC程序工程创建 1、硬件配置 2、程序编程 3、添加监控表 二、C#程序工程创建 1、界面UI 2、代码编写 (1)创建本地Udp (2)读PLC的线程函数 (3)定时器 (4)上位机写寄存器操作 (5)StringToByte()方法封装 (6)窗口关闭 3、C#和PLC测试 (1)C#上位机写操作1 (2)C#上位

    2024年02月04日
    浏览(45)
  • C#上位机与西门子PLC数据交互

    拉了换一个简单的界面 我新建了一个DB数据块【DB1】,右键【DB1】,点击【属性】项,【优化的块访问】默认是勾选,要想显示数据块中地址偏移量,需要把【优化的块访问】勾选取消 1、右键项目名,选择图中【管理NuGet程序包】 2、在搜索框输入【S7netplus】,我安装的是第

    2024年02月13日
    浏览(52)
  • C# 读取西门子S7系列PLC教程及源码

    若要创建驱动程序的实例,需要使用此构造函数: CPU:这指定您要连接到的  CPU 。支持的 CPU 包括: ip :指定 CPU 或外部以太网卡的 IP 地址 机架:它包含PLC的 机架 ,您可以在Step7的硬件配置中找到 插槽 :这是CPU的插槽,您可以在Step7的硬件配置中找到 例: 此代码为 IP 地

    2024年02月08日
    浏览(52)
  • C#语言使用EasyModbus做客户端和西门子1511PLC通信

    之前一直使用开源库NModbus,它是一个非常优秀的Modbus通信类库,偶然机会下我发现了EasyModbus,发现EasyModbus的代码非常精炼、间接,一两行代码就可以创建一个Modbus TCP Client。 EasyModbus官网:http://easymodbustcp.net/en/ 在官网下载DLL文件,在项目中添加引用。 代码如下(示例):

    2023年04月11日
    浏览(36)
  • 【西门子PLC S7-200smart与汇川变频器通过通讯控制】

    一,变频器通讯设置部分 先查看汇川变频器的使用说明书,将FD组“通讯参数设置”设置好对应波特率,数据格式,本机地址,通讯协议 FD-00 波特率设置   0:300bps 1:600bps 2:1200bps 3:2400bpd 4:4800bps 5:9600bps9:115200bps FD-01 数据格式    1:偶校验  2:奇校验  3:无校验 FD-02 本机地

    2024年02月04日
    浏览(77)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包