Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla 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.

06 Lip 2010 13:14 4358 15
  • Poziom 9  
    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.
  • 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 ?
  • Poziom 9  
    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.
  • 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?
  • Poziom 9  
    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)
  • 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#.
  • Poziom 9  
    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
  • 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.
  • Poziom 9  
    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
  • 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
  • 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.
  • 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-
  • Poziom 9  
    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)
  • Poziom 9  
    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
  • Poziom 9  
    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
  • Poziom 15  
    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