Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Builder C++] BCB6 problem z TComPort i odbiorem danych

tavo 27 Mar 2009 14:22 2566 9
  • #1
    tavo
    Level 12  
    Witam forumowiczów

    Piszę program do obsługi miernika, ale utknąłem na samym początku, czyli na komunikacji po RS232. Korzystam z darmowego komponentu TComPort. Mam spięte dwa komputery. I jak wysyłam ciąg znaków z programu na terminal, to wszystko działa jak należy. Natomiast jak odbieram znaki przez zdarzenie ComPort1RxChar to nie dostaje kompletnego ciągu. Na początku mój kod wyglądał tak samo jak w przykładowym programie.

    Code:

    AnsiString Str;

    ComPort1->ReadStr(Str, Count);
    Memo1->Text=Str;


    W Memo pojawiał sie jedynie ostatni znak łańcucha, np. jak wysłałem "1234567" to pojawiało sie tylko "7". Pomyślałem, że trzeba dać dziadziusiowi czas na przetrawienie obiadu i dodałem opóźnienie 10 ms

    Code:

    AnsiString Str;

    ComPort1->ReadStr(Str, Count);
    Sleep(10);
    Memo1->Text=Str;




    Teraz w Memo wyświetla mi wszystkie znaki prócz pierwszego, czyli z ciągu "1234567" wyświetla "234567". Kolejno zmodyfikowałem polecenia dla dziadziusia

    Code:

    AnsiString Str;

    ComPort1->ReadStr(Str, Count);
    Sleep(10);
    Memo1->Lines->Add(Str);


    Tym razem wyświetla komplet znaków, ale pierwszy znak jest w pierszym wierszu, natomiast reszta w drugim wierszu.

    W zwiazku z powyższym mam prośbę, czy mógłby mnie ktoś nakierować na takie rozwiazanie abym odbierał całość jako jeden łańcuch? Na obu urządzeniach parametry transmisji ma ustawione identycznie.

    I mam jeszcze jedną prośbę, aby wizualnie kontrolować stan połączenia pomiędzy urządzeniami wymiścliłem sobie, aby literka O miała kolor zielony przy połączaniu, a kolor czerwony przy jego braku, co miał realizować kod w Form1

    Code:

    if (ComPort1->Connected)
    Label1->Font->Color=clGreen;
    else
    Label1->Font->Color=clRed;


    No i jakoś to nie bardzo działa, tz. świeci na czerwono cały czas. (domyślnie jest szare).

    ps. Szukałem już rozwiazań kwesti na forum, ale nie znalazłem...
  • #3
    tavo
    Level 12  
    Całość wygląda tak

    Code:

    //---------------------------------------------------------------------------

    #include <vcl.h>
    #pragma hdrstop

    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma link "CPort"
    #pragma link "CPortCtl"
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    ComPort1->ShowSetupDialog();
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
    ComPort1->Open();
    Button2->Enabled=FALSE;
    Button4->Enabled=TRUE;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ComPort1RxChar(TObject* Sender, int Count)
    {
    AnsiString Str;

    ComPort1->ReadStr(Str, Count);
    Sleep(10);
    ShowMessage(Str);
    Memo1->Text=Str;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button3Click(TObject *Sender)
    {
    Application->Terminate();
    }
    //---------------------------------------------------------------------------

    void __fastcall TForm1::Button4Click(TObject *Sender)
    {
    ComPort1->Close();
    Button2->Enabled=TRUE;
    Button4->Enabled=FALSE;
    }
    //---------------------------------------------------------------------------

    void __fastcall TForm1::Button5Click(TObject *Sender)
    {
    AnsiString mikro;
    mikro = Memo2->Text;
    ComPort1->WriteStr(mikro);

    }
    //---------------------------------------------------------------------------


    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
    StringGrid1->Cells[0][0]="Lp.";
    StringGrid1->Cells[1][0]="Ip";
    StringGrid2->Cells[0][0]="Lp.";
    StringGrid2->Cells[1][0]="Id";


    if (ComPort1->Connected)
    Label1->Font->Color=clGreen;
    else
    Label1->Font->Color=clRed;

    }
    //---------------------------------------------------------------------------


    Plik nagłówkowy

    Code:

    //---------------------------------------------------------------------------

    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include "CPort.hpp"
    #include "CPortCtl.hpp"
    #include <Grids.hpp>
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:   // IDE-managed Components
            TComPort *ComPort1;
            TButton *Button1;
            TButton *Button2;
            TMemo *Memo1;
            TButton *Button3;
            TButton *Button4;
            TMemo *Memo2;
            TButton *Button5;
            TLabel *Label1;
            TGroupBox *GroupBox1;
            TStringGrid *StringGrid1;
            TStringGrid *StringGrid2;
            void __fastcall Button1Click(TObject *Sender);
            void __fastcall Button2Click(TObject *Sender);
            void __fastcall ComPort1RxChar(TObject* Sender, int Count);
            void __fastcall Button3Click(TObject *Sender);
            void __fastcall Button4Click(TObject *Sender);
            void __fastcall Button5Click(TObject *Sender);
            void __fastcall FormCreate(TObject *Sender);
    private:   // User declarations
    public:      // User declarations
            __fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif


    a ustawienia komponentu tak
    [Builder C++] BCB6 problem z TComPort i odbiorem danych
  • #4
    Dżyszla
    Level 42  
    a eventy? Trochę dziwne, że odebrane dane nie są przez nagłówek funkcji obsługi zdarzenia przekazywane :| Może warto byłoby się się rozejrzeć za innym komponentem? ;) Generalnie to najczęściej albo jest możliwość jednorazowo odebrania pojedynczego znaku, albo względnie całego bufora, który ma jednak zawsze ograniczoną wielkość. Nie ma w zasadzie możliwości odebrania dowolnego ciągu "na raz", gdyż specyfikacja RS nie przewiduje czegoś takiego (co nie oznacza, że może to zostać zrealizowane programistyczne)

    Edit:
    Choć to może ja używam jakiejś innej ciekawszej wersji :)
  • #5
    tavo
    Level 12  
    Co do eventów mógłbyś tak bardziej mi po chłopsku, ja Buildera, że tak powiem, trochę na czuja obsługuję i nie do końca rozumiem co dokładnie jeszcze ci podać.

    Co do innego komponentu to tak nie bardzo, bo ten jest dla mnie najłatwiejszy do zastosowania i do tego darmowy, dlatego wolalbym z niego za szybko nie rezygnować.
  • #6
    Jerzy_W
    Level 14  
    Witam!

    Używam Comport z sukcesem już dosyć długo, ale nigdy nie korzystałem z ReadStr, no i uzywam go w Delphi, ale mam nadzieję że się dogadamy :D:
    Stan portu masz sprawdzany tylko na początku programu w zdarzeniu FomCreate, a otwierasz go pózniej. Wrzuć na fomę komponent ComLED, w inspektorze obiektów ustaw jego właściwośc Comport na Comport1, LedSignal na IsConn i sygnalizacja stanu portu załatwiona bez linijki kodu.

    Zdarzenie OnRXChar jest generowane po każdym odebranym znaku. O ile dobrze pamiętam to odbieranie tekstu z GPS robiłem tak:
    l
    Code:

    procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
    var
      i: Integer;
      Znak:Char;
    begin
      for i := 1 to Count do
      begin
        Comport1.Read(Znak,1);
        if Znak=CR then
        begin
          Memo1.Lines.Add(LiniaOdbioru);
          LiniaOdbioru:='';
        end
        else LiniaOdbioru:=LiniaOdbioru+Znak;
      end;
    end;

    LiniaOdbioru typu String powinna byc zadeklarowana jako globalna w module, lub jako pole w Form1 w sekcji private lub public.
    CR - stała typu char - znak końca lini, niestety nie wiem który wysyła terminal i nie pamiętam kodu (10,12,13???).
  • #8
    tavo
    Level 12  
    Jerzy_W wykorzystałem twój kod i problem jest, że po wysłaniu danych program się wiesza, wiem, że błąd tkwi u mnie teraz ze znakiem stopu. Chodzi o to, że nie mogę zrobić przypisania w BCB typu

    Code:
    char CR = #13#10


    więc warunek zatrzymania trochę nie do końca działa tak jak powinien, a nie mam pojęcia jak dla C++ zadeklarować inaczej te znaki.

    A kod odczytu wygląda teraz tak
    Code:

    //zmienne globalne
    char* CR = "n"; //bo taki znak byl na końcu kazdej lini tak czy siak.
    AnsiString LiniaOdbioru;




    Code:

    //zmienne lokalne
    int i;
    char* Znak;



     for (i=1;Count;i++)
      {
        ComPort1->Read(Znak,1);
        Sleep(10);
        if (Znak==CR)
        {
          Memo1->Lines->Add(LiniaOdbioru);
          LiniaOdbioru="";
        }
        else
        LiniaOdbioru = LiniaOdbioru + Znak;
       }

  • #10
    tavo
    Level 12  
    Dobra, obadałem dogłębniej sprawę, problem nie leży w znaku kiedy ma sie zatrzymać, tylko w pętli for. Wpisane do zdarzenia takiego cuda powoduje tak naprawdę wywołanie pętli nieskończonej. Zmienna Count dynamicznie zmienia wartość i po przesyle osiąga tak jakby zero, więc warunek końca nigdy się nie spełni i jak pętla ruszy to już nie stanie. Przynajmniej tak mi to u mnie działa (albo mi się wydaje, że tak działa, w każdym razie to pętla for wiesza aplikacje)...

    EDIT:

    Problem się częściowo rozwiązał, podszedłem do sprawy łopatologicznie i czytam teraz tak:

    Code:

    ComPort1->ReadStr(Str, Count);
    Memo1->Text=Memo1->Text+Str;


    Zostaje mi tylko problem podziału większej ilości odczytów naraz, ale z tym już powinienem sobie dać radę, dziękuję wam Panowie za poświęcenie swojego czasu na czytanie moich postów i podsunięcie rozwiązań, jestem bardzo zobowiązany.