Snap7 writing to a S7-1200 PLC

2019-08-11 22:54发布

问题:

I'm trying to write something to my Siemens PLC with a C++/CLI application.

Reading is ok (except the first time it reads it gives odd values).

But writing is doing something completely different then what I want.

below you can find the code:

    private: void WriteSiemensDB()
    {
        byte* buffer;

        if (ConnectToSiemensPLC()) //Check if you are connected to PLC
        {
        String^ msg;
        int DBNumber = 2;
        bool NDR;

        //Getting the values 1 time so buffer has a value
        buffer = sPLC->ReadDB(DBNumber);

        //give variables a value to write it to the PLC
        NDR = true;

        sPLC->SetBitAt(buffer, 0, 0, NDR); //Convert a bool to a bit

        msg = sPLC->WriteDB(DBNumber, buffer); //write to the Datablock in Siemens

        MessageBox::Show(msg); //Show if it worked or not
    }
}

The sPLC->SetBitAt method:

void SiemensPLC::SetBitAt(byte buffer[], int Pos, int Bit, bool Value)
{
    byte Mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
    if (Bit < 0) Bit = 0;
    if (Bit > 7) Bit = 7;

    if (Value)
    {
        buffer[Pos] = (byte)(buffer[Pos] | Mask[Bit]);
    }
    else
    {
        buffer[Pos] = (byte)(buffer[Pos] & ~Mask[Bit]);
    }
}

WriteDB method:

System::String^ SiemensPLC::WriteDB(int DBnumber, byte buffer[])
{
    int Result;
    String^ msg;
    Result = MyClient->DBWrite(DBnumber, 0, 80, buffer);

    if (Result == 0)
    {
        msg = "Gelukt!"; //success
    }
    else
    {
        msg = "Mislukt, error:" + Result; //failed
    }
    return msg;
}

I actually get the message "Gelukt", but it still writes the rwong values. So something goes wrong with filling my buffer. Am I doing something wrong in with the buffer?

In C# I have the same kind of application except the buffer is a byte buffer[];

My questions are:

  • Whats the difference between a byte* buffer;in C++ and a byte buffer[]; in C#?
  • When I mouse over on my buffer when I'm debugging, it says buffer* = 0 ''. Does that mean it's empty? if so, why does it still send random numbers to my PLC?

回答1:

Whats the difference between a byte* buffer;in C++ and a byte buffer[]; in C#?

Assuming you have typedef unsigned char byte;:

In C++/CLI, byte* buffer; declares a buffer variable which is a pointer to a byte. In C# you write it as: byte* buffer; in an unsafe context. The syntax is the same.

In C#, byte[] buffer; declares a buffer variable which is a managed array of byte values. The C++/CLI syntax for this is array<byte> buffer;.

Note that byte buffer[N]; is C++ syntax for a native array, which is not the same thing. That one can decay to a byte* pointer.

Looks like your code uses a native memory buffer, but there's no way to tell that for sure without the source of ReadDB.

When I mouse over on my buffer when I'm debugging, it says buffer* = 0 ''. Does that mean it's empty? if so, why does it still send random numbers to my PLC?

It means the first byte in your buffer is 0. If your buffer is supposed to contain C string data, it means it contains the empty string.

Am I doing something wrong in with the buffer?

Most probably. But I can't say exactly what's wrong, because you didn't post the source of ReadDB.

There are a couple of red flags though:

  • What's the buffer size? Your code doesn't know what ReadDB returns, so how are you supposed to ensure you're not overflowing it?
  • Who's the owner of the buffer, meaning: who's supposed to free it? It presumably lives on the heap, so your code is leaking memory. If it lives on ReadDB's stack you have a memory corruption issue. Either way, this code is wrong.