2012-03-14 14 views
6

Próbuję wysłać polecenia FINS przez UDP z komputera (C# .NET) do modułu PLC Ethernet (Omron), ale nie otrzymuję żadnych odpowiedzi od PLC i nie mam pojęcia, gdzie jestem można rozpocząć rozwiązywanie problemów.Wyślij polecenie FINS z C# do PLC

PLC ma bardzo prostą logikę drabiny następująco: Jeśli DM100 ma wartość #0001, a następnie wywołać na wyjściu 101.00. (Tutaj „wyzwalania” to tylko nazwa symbol obszaru pamięci D100 i „Wyjście” jest symbolem wyjścia 101.00) enter image description here

Potem napisałem kawałek C#, który wykonuje polecenia płetw „obszar pamięci Write” który ma kod komend: 01 02, po którym następuje adres początkowy, liczba elementów do zapisania i dane. Kod C# powinien zapisać wartość # 0001 w obszarze D100 sterownika PLC, aby wyzwolić ON na 101.00.

[usunięty kod, który nie działa] ..

Wyjście 101.00 nie uzyskać wyzwolone, ani ja nie otrzymują żadnego wyjątku. Zrobiłem pewien, co następuje:

  1. Port węzła i adres poprawnie skonfigurowane jako potwierdzone przez "Work Online" w CX-Programmer. Mam również ping do każdego IP, aby upewnić się, że węzły są połączone.
  2. Kod UdpClient jest ważny, ponieważ napisałem bardzo prosty kod serwera/klienta, który pomyślnie wysyła i odbiera pakiety.
  3. Logika drabiny nie ma problemu. Przesłałem drabinę do PLC i przetestowałem przez Work Online w trybie monitorowania i ręcznie ustawiłem wartość.

Podejrzewam, że jest błąd w tablicy fins_cmnd, ale jak widać w moim kodzie, skomentowałem tak szczegółowo, jak to możliwe, dla każdej wartości; Nie mogę chyba niczego przegapić. Podejrzewam, że mogę nie poprawnie przetwarzać szesnastkowego, ale znowu nie mam żadnego wyjątku, który by mnie poprowadził.

Nie mam pojęcia, gdzie i jak mogę rozwiązać problem. Mam nadzieję, że ktoś z pomocą programowania FINS lub doświadczenia PLC może mi pomóc.

[Odpowiedź]
Dzięki Porge za link - że dostał mi się znaleźć problem. Po kilku szlakach wreszcie działa. Zobacz poniżej działający kod.

string SERV_IP_ADDR = "192.168.250.1"; 
const int FINS_UDP_PORT = 9600; 

byte[] sendPacket = new byte[] 
{ 
    // Full UDP packet: 80 00 02 00 00 00 00 05 00 19 01 02 82 00 64 00 00 01 00 01 

    // Header 
    0x80, //0.(ICF) Display frame information: 1000 0001 
    0x00, //1.(RSV) Reserved by system: (hex)00 
    0x02, //2.(GCT) Permissible number of gateways: (hex)02 
    0x00, //3.(DNA) Destination network address: (hex)00, local network 
    0x00, //4.(DA1) Destination node address: (hex)00, local PLC unit 
    0x00, //5.(DA2) Destination unit address: (hex)00, PLC 
    0x00, //6.(SNA) Source network address: (hex)00, local network 
    0x05, //7.(SA1) Source node address: (hex)05, PC's IP is 192.168.250.5 
    0x00, //8.(SA2) Source unit address: (hex)00, PC only has one ethernet 
    0x19, //9.(SID) Service ID: just give a random number 19 

    // Command 
    0x01, //10.(MRC) Main request code: 01, memory area write 
    0x02, //11.(SRC) Sub-request code: 02, memory area write 

    // PLC Memory Area 
    0x82, //12.Memory area code (1 byte): 82(DM) 

    // Address information 
    0x00, //13.Write start address (2 bytes): D100 
    0x64, 
    0x00, //15.Bit address (1 byte): Default 0 
    0x00, //16.No. of items (2 bytes): only one address which is D100 
    0x01, 

    // Write Data 
    0x00, //18.Data to write (2 bytes): value is 1 
    0x01, 
}; 

UdpClient client = new UdpClient(); //create a UdpClient instance 

try 
{ 
    client.Send(sendPacket, sendPacket.Length, SERV_IP_ADDR, FINS_UDP_PORT); 
} 
catch (SocketException se) 
{ 
    Console.WriteLine(se.ErrorCode + ": " + se.Message); 
} 

client.Close(); 

Odpowiedz

6

Żaden z tych ciągów nie zostanie sparsowany jako szesnastkowy. NumberStyles.AllowHexSpecifierzezwala na szesnastkowy prefiks "0x", ale nie analizuje liczby jako heksadecymalnej, chyba że jest obecna.

Więc chcesz (char)Int16.Parse("0x64", NumberStyles.AllowHexSpecifier).

Jednak literały numeryczne w języku C# mogą być w postaci szesnastkowej, więc zamiast robić wszystko, co można, wystarczy wpisać 0x64.

Właśnie przyjrzałem się protokołowi this page as a reference, a byłoby lepiej utworzyć wiadomość bezpośrednio jako bajty, zamiast określać punkty kodu Unicode i dekodować je jako bajty ASCII. Można również użyć składni specyfikacji tablica usunąć dużo bałaganu:

var message = new byte[] 
{ 
    // header 
    0x80, //(ICF) Display frame information: 1000 0001 
    0x00, //(RSV) Reserved by system: (hex)00 
    0x02, //(GCT) Permissible number of gateways: (hex)02 
    0x00, //(DNA) Destination network address: (hex)00, local network 
    0x00, //(DA1) Destination node address: (hex)00, local PLC unit 
    0x00, //(DA2) Destination unit address: (hex)00, PLC 
    0x00, //(SNA) Source network address: (hex)00, local network 
    0x05, //(SA1) Source node address: (hex)05, PC's IP is 192.168.250.5 
    0x00, //(SA2) Source unit address: (hex)00, PC only has one ethernet 
    0x19, //(SID) Service ID: just give a random number 19 

    // command 
    0x01, //(MRC) Main request code: 01, memory area write 
    0x02, //(SRC) Sub-request code: 02, memory area write 

    // data 
    0x82, //Memory area code, 2 bytes: 82(DM) 
    0x00, //Write start address DM100 
    0x64, 
    0x00, 
    0x00, //Word write: only one address 
    0x01, 
    0x00, //Write value of 1 to address DM100 (0000 0000 0000 0001) 
    0x01, // - this value is 0xaabbccdd -> cc dd aa bb 
    0x00, 
    0x00, 
}; 

wygląda też jak istnieją pewne problemy z sekcji danych - zgodnie z połączonego dokumentu na adres pamięci powinien być 4 bajty, write długość 2 bajty i wartości 4 bajty każda. Nie pasują one do tego, co masz, więc rozszerzyłem tę sekcję.

+0

Pamięć jest, tak, 4 bajty, stąd mam dwa elementy tablicy jeden 0x00 i 0x64 razem 4 bajty. ponieważ każda "sekcja" zajmuje tylko 16 bitów. – KMC

+0

@KMC: Rozszerzyłem część "danych" na podstawie tego, jak myślę, że ma wyglądać na podanej stronie. Czy to pomaga? – porges