C++与PLC通过Modbus TCP协议进行PLC内部寄存器的值的读取/写入总结

本文介绍了使用C++对松下PLC进行数据读写的方法。包括对PLC中16位和32位DT值的读取与赋值,采用ModbusTCP协议,阐述了正负数处理思路和计算方法;还说明了ASCII码在PLC寄存器中的传值与读取,给出了具体示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、对PLC中一个DT值(16位)进行读取、赋值(正、负整数)

(本文中所有数据验证基于松下PLC)

(PLC一个DT最大支持十进制有符号整数±32768,无符号整数66536)

(PLC一个DT最大支持十进制正整数0 - 32767,负整数(-1) -(-32768))

思路:

  1. 采用ModbudTCP协议(或者其他协议)
  2. 其中每个DT值对应协议中的两个8位的十六进制,如00 0A
  3. 两个8位的十六进制最大能够传送正/负整数32768,以内的十进制转换成的两个8位的十六进制数。
  4. 读取负数的处理:负数的读取目前已经有了现有的代码,其中16位整数的读取无论是正数还是负数都可以通过现有的代码进行读取判断其正负值。
  5. 对PLC寄存器16位负数的赋值

         5.1、保证负数在 -32768内

         5.2、将要传送的负数 += 65536

         5.3、将得到的值转换为十六进制

二、上位机对PLC中一个DT值(32位)进行读取、赋值(正、负整数)

思路:

  1. 采用ModbudTCP协议(或者其他协议)
  2. 其中每个DT值对应协议中的4个8位的十六进制,如00 0A 00 0B
  3. 读取PLC的32位DT值:

步骤:3.1、将PLC中的DT值设置为有符号或者无符号的32位

           3.2、和读取16进制一样,以每个8位的十六进制位单位去解析PLC传上来的值

         (其中低十六位不判断正负。高十六位才判断正负)

          3.3、将解析后的十进制数值,按照以下公式进行计算

           寄存器(0007H) * 10000H + 寄存器(0006H) = 数据1*100H + 数据2 + 数据3*1000000H +    数据4*10000H

( 数据1:寄存器06H(高8位)、  数据2:寄存器06H(低8位)  、

    数据3:寄存器07H(高8位)、  数据4:寄存器07H(低8位)      )

4、写入PLC中32位寄存机的值

步骤:4.1、正值写入

          4.2、整个思路分为两个部分,高十六位 与 低十六位

         4.3、得要要传送的值后,先对其进行判断,是否大于65535。

如果不大于,则直接转换为十六进制,得到的十六进制位地十六位,高十六位直接为00 00;

如果大于再对其进行解析,用这个值除以65536得到商的值的十六进制就是高十六位的最终结果,然后在用需要传的值与 65536取余数(%)的到的余数的值的十六进制就是低十六位的值。

例:str = "00 00 00 00 00 CF 01 10 13 88 00 02 04 86 A0 00 01"; //输出32位的值100000

 其中02为:为起始地址寄存器的数量为2,     04为字节数为4

86 A0 00 01:为十进制100000,  86 A0位低十六位;   00 01为高十六位

(86A0的十进制为34464    00 01的十进制为 1 * 65536 = 65536;     相加为 34464 + 65536 = 100000)

5、负32位的值的写入

步骤:

(

方向1:00 00   ff ff    PCL显示为 -65536       

00 01   ff ff    PCL显示为 -65535;        

00 02   ff ff    PCL显示为 -65534;

方向2:00 00  ff fe PCL显示为 -131072(-65536的两倍);

00 01  ff fe PCL显示为 -131071(-65535的两倍);

00 02  ff fe PCL显示为 -131070(-65534的两倍);

方向3:00 00  ff fd PCL显示为 -196608(-65536的三倍);

)

由以上规律可知:直接将C++的代码放在下面,欢迎大家提出好的建议,以下是我自己的一个规律理解:

int TemporaryVariable = ui->spinBox->value();
    if(TemporaryVariable >= 0)   //正值传送
    {
        if(TemporaryVariable > 65535)
        {
            THEKERNEL->k3_PLC1WriteData[0] = TemporaryVariable % 65536;  //低十六位 取余
            THEKERNEL->k3_PLC1WriteData[1] = TemporaryVariable / 65536;  //高十六位 取商
        }
        else
        {
            THEKERNEL->k3_PLC1WriteData[0] = TemporaryVariable; //(低十六位)
            THEKERNEL->k3_PLC1WriteData[1] = 0;  //(高十六位)
        }
    }
    else  //负值传送
    {
        int TestValue = 0;
        TestValue = abs(TemporaryVariable);   //负数传值运算
        if((TestValue / 65536) > 0)
        {
            if((TestValue % 65536) == 0)
            {
                THEKERNEL->k3_PLC1WriteData[0] = 0;
                THEKERNEL->k3_PLC1WriteData[1] = 65536 - (TestValue / 65536);  //高位
            }
            else
            {
                THEKERNEL->k3_PLC1WriteData[0] = 65536 - (TestValue % 65536);
                THEKERNEL->k3_PLC1WriteData[1] = 65535 - (TestValue / 65536);  //高位
            }
        }
        else
        {

            THEKERNEL->k3_PLC1WriteData[0] = 65536 - TestValue;
            THEKERNEL->k3_PLC1WriteData[1] = 65535;
        }
    }
//其中:ui->spinBox->value()为界面要传送至PLC的值
//THEKERNEL->k3_PLC1WriteData[0]:传值至PLC的中间变量容器
//THEKERNEL->k3_PLC1WriteData[0]:低十六位
//THEKERNEL->k3_PLC1WriteData[1]:高十六位

三、ASCII码的传值与读取

  1. 将ASCII码写入到PLC寄存器中。其方式与16位整数一样,直接给出例子

str = "00 00 00 00 00 CF 01 10 13 88 00 01 02 4e 4d";

 //DT5000 显示ASCII(16位)的字符:  N M    (十六进制 4e = n(ASCII); 4d = m)

以上例子是将PLC中寄存器DT5000中传入ASCII码,

  1. 读取PLC传来的16进制ASCII码

   将读出来的十六进制进过程序转换为ASCII码即可

### Java读取西门子PLC的方法 对于通过Java程序读取西门子PLC中的数据,可以采用S7通信协议库之一——JCo (Java Connector),不过更常用的是使用开源项目如 snap7 或者 js7comm 来实现 S7系列 PLC 的连接[^1]。 下面是一个基于js7comm库的简单例子用于建立到PLC的连接并从中获取特定地址处的数据: ```java import de.re.easymodbus.modbusclient.ModbusClient; public class ReadFromPLC { public static void main(String[] args) throws Exception{ ModbusClient modbusClient = new ModbusClient("192.168.0.1", 502); // 创建客户端实例,指定IP和端口 try { modbusClient.Connect(); // 尝试连接至PLC int result = modbusClient.ReadHoldingRegisters(400, 1)[0]; // 假设要读取保持寄存器起始编号为400的一个整数数 System.out.println("Value from Holding Register: "+result); } catch(Exception e){ throw(e); } finally{ if(modbusClient.isConnected()){ modbusClient.Disconnect(); } } } } ``` 此代码片段展示了创建Modbus TCP/IP 客户端对象的过程,并尝试连接到位于局域网内的某台PLC设备上。一旦成功建立了TCP会话,则可以通过调用相应API函数执行诸如`ReadHoldingRegisters()`之类的操作来访问存储于目标装置内部的不同类型的变量或内存区域。 得注意的是,在实际应用环境中可能还需要考虑更多因素比如安全性设置、异常处理机制以及性能优化等方面的内容;此外不同型号之间的接口细节也可能存在差异因此建议参照具体产品的官方文档来进行开发工作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值