一、对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码即可