Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[Delphi] Odczyt danych z czujnika poprzez RS232.

quine15 06 Lip 2010 13:14 4181 15
  • #1 06 Lip 2010 13:14
    quine15
    Poziom 8  

    witam, mam następujący problem: muszę napisać (najlepiej w delphi) program odczytujący wyniki z czujnika ciśnienia. Czujnik podłączony jest za pomocą RS232. Oprócz podstawowej obsługi delphi nie mam za dużych umiejętności w tej dziedzinie, dlatego każda podpowiedź mi pomoże.

    Proszę zakładać własne tematy. Rozdzieliłem. - arnoldziq.

    0 15
  • #2 06 Lip 2010 14:19
    arnoldziq
    Moderator Programowanie

    Czy wyżej wymieniony czujnik, używa jakiegoś protokołu do transmisji danych przez siebie odczytywanych?
    Jakie urządzenie/układ/uC przechwytuje dane z czujnika i wysyła go poprzez RS232 ?

    0
  • #3 07 Lip 2010 13:02
    quine15
    Poziom 8  

    czujnik wysyła sygnał analogowy i jest połączony z jakimś procesorem ale nie wiem na razie nic więcej. czujników jest pięć i razem wychodzą na rs232.

    0
  • #4 07 Lip 2010 18:33
    arnoldziq
    Moderator Programowanie

    Jak nie znasz protokołu transmisji, to będzie spory problem.
    Może się okazać, że po podłączenia do komputera, nic nie zostanie przesłane. Na większości tego typu urządzeń trzeba "wymusić" rozpoczęcie transmisji.
    Na początek podłącz urządzenie po prostu do portu, odpal jakiś terminal, otwórz port na 9600 i zobacz czy masz jakikolwiek "ruch" na porcie.

    Masz może dostęp do dokumentacji tego czujnika?

    0
  • #5 08 Lip 2010 09:49
    quine15
    Poziom 8  

    mam pełną dokumentacje czujnika, ale pojęcia nie mam jak wykonać czynności które podałeś (oczywiście wiem jak podłączyć czujnik ale pozostałe są dla mnie czarna magią)

    Dodano po 1 [godziny] 55 [minuty]:

    dobra ruch jest poprawny jeśli chodzi o wysyłanie (sprawdzone za pomocą monitora rs)

    0
  • #6 08 Lip 2010 10:29
    arnoldziq
    Moderator Programowanie

    Jeżeli masz pełną dokumentację, to na pewno jest w niej opisane : szybkość połączenia, ustawienia kontroli błędów oraz, co najważniejsze, "wygląd" pakietu danych.
    Z tymi danymi, możesz napisać aplikację, w dowolnym języku, która będzie odbierała dane z portu, przetwarzała je i wyświetlała/zapisywała w jakiś sposób.
    Proponuję poszukać na forum informacji o np. sterowaniu portem RS232 przez Delphi, np. przy użyciu komponentu ComPort. Takich tematów, wraz z kodami źródłowymi, jest tutaj bardzo dużo.
    Jeżeli nie czujesz się dobrze w Delphi, to jest na elektroda.pl, bardzo wiele tematów o sterowaniu portem COM za pomocą C++ czy C#.

    0
  • #7 09 Lip 2010 09:23
    quine15
    Poziom 8  

    co do tematów na forum i comport-u to od tego zaczęłam teraz jestem na etapie próby wysłania do czujnika konkretnej informacji z poleceniem odesłania wyniku pomiaru. Czujnik: PR-10X/0.2bar/81634.7

    Według "instrukcji" polecenie powinno być 8 bitowe i zawierać
    DevAddr | 0, Function code | n byte parameters (optional) |CRC16_H | CRC16_L

    nie wiem jak te polecenia zrealizować w delphi i w jakiej formie przesłać do czujnika.

    Dodano po 1 [godziny] 31 [minuty]:

    nie 8 a 4 bitowe

    0
  • #8 09 Lip 2010 10:03
    arnoldziq
    Moderator Programowanie

    quine15 napisał:
    nie wiem jak te polecenia zrealizować w delphi i w jakiej formie przesłać do czujnika.

    No to akurat nie jest problem.
    Tworzysz tablicę (0..3 of byte), uzupełniasz ją odpowiednimi danymi i wysyłasz bajt po bajcie.

    0
  • #9 09 Lip 2010 10:44
    quine15
    Poziom 8  

    a widzisz niby nie problem, ale ja pisałam ostatnio w delphi 4 lata temu i teraz muszę się uczyć krok po kroku, możesz mi jakiś przykład napisać?

    Dodano po 38 [minuty]:

    dobra z tablica jakoś sobie poradziłam teraz się męcze z CRC16 w instrukcji do czujników jest podany sposób obliczenia ale w c a nie w delphi czy ktoś mógłby pomóc mi to przetłumaczyć?

    Code:
    voidCalcCRC16(unsignedchar*CRC_H,unsignedchar*CRC_L)
    
    {
       //locals
       unsignedintCrc;
       unsignedcharn,m,x;
       //initialisation
       Crc=0xFFFF;
       m=SC_Amount;
       x=0;
       //loopoverallbits
       while(m>0)
       {
          Crc^=SC_Buffer[x];
          for(n=0;n<8;n++)
         {
             if(Crc&1)
            {
                Crc>>=1;
                Crc^=0xA001;
             }
             else
             Crc>>=1;
          }
          m--;
          x++;
       }
       //result
       *CRC_H=(Crc>>8)&0xFF;
       *CRC_L=Crc&0xFF;
    }//endCalcCRC16


    Proszę pamiętać o używaniu znaczników code. - arnoldziq

    0
  • #10 09 Lip 2010 21:21
    ekomont
    Poziom 16  

    Code:
    var
    
      CRC_dane:ARRAY[0..99] of BYTE;
      suma_CRC_hi,suma_CRC_lo:integer;

    function TForm1.CRC16(length:integer):integer;
    const wCRCTable: array [0..255]of WORD =($0000,$C0C1,$C181,$0140,$C301,$03C0,$0280,$C241,$C601,$06C0,$0780,
    $C741,$0500,$C5C1,$C481,$0440,$CC01,$0CC0,$0D80,$CD41,$0F00,$CFC1,
    $CE81,$0E40,$0A00,$CAC1,$CB81,$0B40,$C901,$09C0,$0880,$C841,$D801,
    $18C0,$1980,$D941,$1B00,$DBC1,$DA81,$1A40,$1E00,$DEC1,$DF81,$1F40,
    $DD01,$1DC0,$1C80,$DC41,$1400,$D4C1,$D581,$1540,$D701,$17C0,$1680,
    $D641,$D201,$12C0,$1380,$D341,$1100,$D1C1,$D081,$1040,$F001,$30C0,
    $3180,$F141,$3300,$F3C1,$F281,$3240,$3600,$F6C1,$F781,$3740,$F501,
    $35C0,$3480,$F441,$3C00,$FCC1,$FD81,$3D40,$FF01,$3FC0,$3E80,$FE41,
    $FA01,$3AC0,$3B80,$FB41,$3900,$F9C1,$F881,$3840,$2800,$E8C1,$E981,
    $2940,$EB01,$2BC0,$2A80,$EA41,$EE01,$2EC0,$2F80,$EF41,$2D00,$EDC1,
    $EC81,$2C40,$E401,$24C0,$2580,$E541,$2700,$E7C1,$E681,$2640,$2200,
    $E2C1,$E381,$2340,$E101,$21C0,$2080,$E041,$A001,$60C0,$6180,$A141,
    $6300,$A3C1,$A281,$6240,$6600,$A6C1,$A781,$6740,$A501,$65C0,$6480,
    $A441,$6C00,$ACC1,$AD81,$6D40,$AF01,$6FC0,$6E80,$AE41,$AA01,$6AC0,
    $6B80,$AB41,$6900,$A9C1,$A881,$6840,$7800,$B8C1,
    $B981,$7940,$BB01,$7BC0,$7A80,$BA41,$BE01,$7EC0,$7F80,$BF41,$7D00,
    $BDC1,$BC81,$7C40,$B401,$74C0,$7580,$B541,$7700,$B7C1,$B681,$7640,
    $7200,$B2C1,$B381,$7340,$B101,$71C0,$7080,$B041,$5000,$90C1,$9181,
    $5140,$9301,$53C0,$5280,$9241,$9601,$56C0,$5780,$9741,$5500,$95C1,
    $9481,$5440,$9C01,$5CC0,$5D80,$9D41,$5F00,$9FC1,$9E81,$5E40,$5A00,
    $9AC1,$9B81,$5B40,$9901,$59C0,$5880,$9841,$8801,$48C0,$4980,$8941,
    $4B00,$8BC1,$8A81,$4A40,$4E00,$8EC1,$8F81,$4F40,$8D01,$4DC0,$4C80,
    $8C41,$4400,$84C1,$8581,$4540,$8701,$47C0,$4680,$8641,$8201,$42C0,
    $4380,$8341,$4100,$81C1,$8081,$4040);
    var
      nTemp: BYTE;
      wCRCWord: WORD;
      CRC_licznik:integer;
    begin
      wCRCWord:=$FFFF;
      for CRC_licznik:=0 to (length-1) do
      begin
        nTemp:= CRC_dane[crc_licznik] xor wCRCWord;
        wCRCWord:= wCRCWord shr (8);
        wCRCWord:= wCRCWord xor (wCRCTable[nTemp]);
      end;
      result:= wCRCWord;
    end;




    użycie:

    Code:
     CRC_dane[0]:=Buffer_I[numer_portu,0];
    
          CRC_dane[1]:=Buffer_I[numer_portu,1];
          CRC_dane[2]:=Buffer_I[numer_portu,2];
          CRC_dane[3]:=Buffer_I[numer_portu,3];
          CRC_dane[4]:=Buffer_I[numer_portu,4];
          CRC_dane[5]:=Buffer_I[numer_portu,5];
          CRC_dane[6]:=Buffer_I[numer_portu,6];
          CRC_dane[7]:=Buffer_I[numer_portu,7];
          CRC_dane[8]:=Buffer_I[numer_portu,8];
          CRC_dane[9]:=Buffer_I[numer_portu,9];
          CRC_dane[10]:=Buffer_I[numer_portu,10];
          suma_CRC_hi:=CRC16(11);
          suma_CRC_lo:=suma_CRC_hi;
          suma_CRC_hi:=suma_CRC_hi shr(8);
          suma_CRC_lo:=suma_CRC_lo-suma_CRC_hi*256;


    Buffer_I[xx] to wartości typu Byte 0...255 odbierane z portu (w tym przypadku)
    Do tablicy CRC_dane wrzuca się bajt po bajcie, a potem CRC16(ilosc bajtów) i przelicznik na niższy i wyższy bajt - typowy dla np Modbus

    Proszę pamiętać o używaniu znaczników code. - arnoldziq

    0
  • #11 09 Lip 2010 22:23
    arnoldziq
    Moderator Programowanie

    Drogi kolego ekomont.
    Rozumiem, że chciał kolega pomóc, ale proszę mi wytłumaczyć, jak zamieszczana przez kolegę procedura ma się do procedury CRC16 zamieszczonej w języku C, w poprzednim poście ?
    Pozwolę sobie sam odpowiedzieć na to pytanie : nijak!
    Poza wspólną nazwą oraz ogólnym zastosowaniem (kontrola błędów) obie procedury nie maja nic wspólnego.
    Zamieszczona procedura może tylko wprowadzi w błąd autora tematu, a na pewno nie pomoże w trakcie połączenia z w/w urządzeniem.

    0
  • #12 11 Lip 2010 09:28
    Darom
    Specjalista elektryk

    Witam
    Odnośnie kodu podanego przez kolegę quine15. Pomijając to, że wcięło gdzieś spacje to nie widzę deklaracji zmiennej SC_Amount oraz tablicy SC_Buffer. Być może to są jakieś zmienne globalne - z kodu wynika, że są to dane wejściowe.
    Mam też wątpliwośći co do wyrażeń: Crc^ = SC_Buffer[x]; czy Crc^ = 0xA001;

    pzdr
    -DAREK-

    0
  • #13 12 Lip 2010 08:06
    quine15
    Poziom 8  

    SC_Amount i SC_Buffetr sa opisane w instrukcji w sposób następujący:

    SC_Amount amount of bytes which should be transmited or are received (without CRC16)
    SC_Buffer[] Byte-buffer for the serial interface. Type: unsigned char (8 bit)

    poza tym do instrukcji jest uprzejmie dopisane: Calculation of CRC16 checksum over an amount of bytes in the serial buffer. The calculation is done without the 2byte from crc16 (receive-mode)

    0
  • #14 13 Lip 2010 10:57
    quine15
    Poziom 8  

    Ponawiam prośbę o pomoc w przetłumaczeniu tego kodu z C++ na delphi, obecnie jest to jeden z moich głównych problemów co prawda mam już trzy wersje możliwości przetłumaczenia ale żadna nie jest dobra, ze względu na zmienne opisane w poprzednim poście

    Code:

    voidCalcCRC16(unsignedchar*CRC_H,unsignedchar*CRC_L)
    {
       //locals
       unsignedintCrc;
       unsignedcharn,m,x;
       //initialisation
       Crc=0xFFFF;
       m=SC_Amount;
       x=0;
       //loopoverallbits
       while(m>0)
       {
          Crc^=SC_Buffer[x];
          for(n=0;n<8;n++)
         {
             if(Crc&1)
            {
                Crc>>=1;
                Crc^=0xA001;
             }
             else
             Crc>>=1;
          }
          m--;
          x++;
       }
       //result
       *CRC_H=(Crc>>8)&0xFF;
       *CRC_L=Crc&0xFF;
    }//endCalcCRC16

    0
  • #15 14 Lip 2010 13:16
    quine15
    Poziom 8  

    no dobrze z kodem CRC16 jakoś mi się udało mam teraz jednak znacznie większy problem i to znów z tłumaczeniem z c++ na delphi. następujący kod:

    Code:

    // 3. Timeouts
       _COMMTIMEOUTS timeouts;

       timeouts.ReadIntervalTimeout= 400;
       timeouts.ReadTotalTimeoutMultiplier= 0;
       timeouts.ReadTotalTimeoutConstant= 500;
       timeouts.WriteTotalTimeoutMultiplier= 0;
       timeouts.WriteTotalTimeoutConstant= 200;

       if(!SetCommTimeouts(m_hPort,&timeouts))
          return nResult= COMM_NOT_SETCOMMTIMEOUTS;


    a także kod:
    Code:

    // SEND AND RECEIVE

    int CCommCtrl::TransferData(_u16 nTX,_u16 nRX)
    {
       BOOL   bRepeat;

       do {
          bRepeat= FALSE;

          if(::WaitForSingleObject(m_eventCancel,0) == WAIT_OBJECT_0)
             nResult= COMM_CANCEL;
          else
             nResult= TransferDataDirect(nTX,nRX);

          if(::WaitForSingleObject(m_eventCancel,0) == WAIT_OBJECT_0)
             nResult= COMM_CANCEL;
          
          switch(nResult) {
          case COMM_NO_RESPONSE:
          case COMM_BAD_RESPONSE:
          case COMM_BAD_LENGTH:
          case COMM_BAD_CRC:
          case COMM_BAD_ADDR:
          case COMM_BAD_EXCEPTION:
          case COMM_RX_ERROR:
             if(m_bRepeatIfError) {
                Sleep(400);         
                bRepeat= TRUE;
             }
             break;
          }
       } while(bRepeat);

       return nResult;
    }

    int CCommCtrl::TransferDataDirect(_u16 nTX,_u16 nRX)
    {
       DWORD      dw;
       _u16      n,nCrc;


    jeśli szanowni koledzy i koleżanki nie mogą pomóc to może wiedzą gdzie pomocy można szukać.
    pozdrawiam Quine15

    0
  • #16 23 Lip 2010 08:39
    elkam
    Poziom 14  

    Cześć Quine15
    Sądząc po odpowiedziach niczego się nie dowiesz tu w kwesti programowania komunikacji w Delphi. Proponuje zajrzeć do książki "RS 232C - praktyczne programowanie. Od Pascala i C++ do Delphi i Buildera" Daniluka. O ile dobrze pmiętam to były trzy wydania tych pozycji. Bardzo przystępnie napisane książki.
    Tłumaczenie kodu z C++ na Delphi także nie ma sensu dlatego, że jeden i drugi język używa tych samych referencji API. Skoncentruj się nad dobrze zaprojektowaną funkcją tworzącą uchwyt do portu, parametryzującą port komunikacyjny ( ostani listing) a następnie zapisanie i odczytanie bufora portu komunikacyjnego.
    Funkcje CRC implementowane w końcowych części ramki transmisyjnej znajdziesz np w codeguru, spróbuj wygooglować temat w przeglądarce. CRC zabezpiecza dane przed wsłaniem i oczywiście przy odbiorze należy uzyć jej do stwierdzenia poprawności przesłanych danych. Ale to tym zapewne wiesz. Ramka któą przedstawiłaś przypomina mi Modbus lub Modbus+
    pozdrawiam

    0