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

[C++] Qt - Program do obsługi portu szeregowego

cyco22 24 Maj 2012 09:41 5509 28
  • #1 24 Maj 2012 09:41
    cyco22
    Poziom 8  

    Witam,

    mam dość spory problem. Napisałem program do obsługi portu szeregowego i komunikacji z mikrokontrolerem, który wysyła 9bajtową ramkę. Dane wysyłane są w bardzo dużej ilości i z prędkością 9600 bps. Program niby działa tak jak powinien i no właśnie pojawia się jedno ale:
    do odczytu używam timera, który żeby nadążyć z odbieraniem danych, musi być ustawiony na wartość od 1 do 2 ms, co niestety strasznie obciąża procesor. Dodatkowo próbowałem użyć do obsługi zczytywania danych, wątków gdzie główny wątek czeka aż pojawi się określona ramka na wątku zczytującym po czym wątek poboczny wraca do głównego. Niestety to rozwiązanie okazało się dużo wolniejsze niż timer. Dostałem podpowiedź żeby spróbować wykorzystać sygnały, i czekać na znak aż się znajdzie w buforze. Niestety nie mam pojęcia jak to zrobić i jakiego sygnału użyć.

    Poniżej załączam kod programu(oczywiście nadmiar zakomentowanych poleceń od sprawdzania wszelkich rozwiązań :)):

    Kod: cpp-qt
    Zaloguj się, aby zobaczyć kod

    0 28
  • #2 24 Maj 2012 10:49
    maly_elektronik
    Poziom 23  

    A po co timer :?:
    Nie lepiej zrobić wątek :?: Przecież od tego one są :)
    Tworzysz nowy wątek rozpoczynasz go podczas startu transmisji, tworzysz jakąś tablica i do niej ładujesz odebrane dane. Później jakieś buforowanie żeby nie zaśmiecać pamięci kompa (chodź przy obecnych komputerach to nie jest konieczne jednak optymalizuje program).

    P.S Zawsze możesz spróbować QextSerialPort (darmowa multiplatformowa biblioteka do obsługi RS232 w QT)

    Pozdrawiam maly_elektronik

    0
  • #3 24 Maj 2012 10:53
    cyco22
    Poziom 8  

    Właśnie o to chodzi że jak tworzę wątek, to nie wyrabia i gubi prawie 3/4 danych

    0
  • #4 24 Maj 2012 11:10
    maly_elektronik
    Poziom 23  

    Z programu wynika że robisz QTimerEvent a zrób QThread to dwie inne rzeczy

    0
  • #5 24 Maj 2012 11:20
    cyco22
    Poziom 8  

    Wątki próbowałem robić wcześniej przy użyciu

    Kod: cpp-qt
    Zaloguj się, aby zobaczyć kod


    Ale jeszcze spróbuję za pomocą QThread i zobaczę jak się będzie zachowywać

    0
  • Pomocny post
    #6 24 Maj 2012 11:51
    maly_elektronik
    Poziom 23  

    QThread jest znacznie lepsze ze względu na to iż jest optymalizowane pod kątem QT i oczywiście korzystajac pthead_t należy przy konsolidacji dołączyć bibliotekę libc

    0
  • #7 24 Maj 2012 12:39
    gaskoin
    Poziom 38  

    Ten kod w ogóle nie wygląda jakby miał coś wspólnego z C++

    0
  • #8 24 Maj 2012 15:53
    LED5W
    Poziom 32  

    Kod: cpp
    Zaloguj się, aby zobaczyć kod
    Odczyt po jednym bajcie to nie jest dobry pomysł...

    0
  • Pomocny post
    #9 25 Maj 2012 20:38
    tymon_x
    Poziom 30  

    Kiedyś coś takiego napisałem, to były początki z Qt. Bazuje to na QThread (Wątek) oraz QQueue (FIFO). Dane odbierasz i wysyłasz asynchronicznie z dowolnego miejsca aplikacji i nie zależnie od wątku. Akurat ta klasa jest przystosowana do odbierania danych w formacie ASCII. Czyli do FIFO zapisuje się cały string bez specjalnego znaku rozdzielającego stringa (CHAR_END_MESSAGE). Możesz to przerobić, żeby zapisywał i odczytywał gołe bajty i przerabiał z FIFO do innej klasy dane. Tak, żeby uniezależnić część obsługującą sprzęt od protokołu i takich tam. W README powinno być w miarę jasno napisane co i jak. Możesz wykorzystać samą ideę.

    0
    Załączniki:
  • #10 25 Maj 2012 22:15
    cyco22
    Poziom 8  

    Co do przerobienia na hex-a to nie będę miał problemu, ale dzięki tymon_x za koncepcję po weekendzie dam znać co z tego wyszło :)

    0
  • #12 01 Cze 2012 07:06
    cyco22
    Poziom 8  

    niestety ten program również za bardzo obciąża procesor, zjada cały jeden rdzeń :/
    [C++] Qt - Program do obsługi portu szeregowego

    0
  • #13 01 Cze 2012 11:14
    gaskoin
    Poziom 38  

    Bo w whilu powinieneś uśpić wątekna chwilę. a tak to on nadupcza tę pętlę jak szybko może :)

    0
  • #14 02 Cze 2012 13:10
    cyco22
    Poziom 8  

    więc próbowałem usypiać pętle i nic już mój sposób był bardziej wydajniejszy bo zjadał 78% rdzenia a ten zjada równą 100. Ma ktoś jakiś pomysł jak to zoptymalizować do mniej więcej 50 % ?

    0
  • #15 02 Cze 2012 13:34
    tymon_x
    Poziom 30  

    cyco22 napisał:
    więc próbowałem usypiać pętle i nic już mój sposób był bardziej wydajniejszy bo zjadał 78% rdzenia a ten zjada równą 100. Ma ktoś jakiś pomysł jak to zoptymalizować do mniej więcej 50 % ?

    Nie usypiasz wątku, o to dowód.

    :arrow: Wątek bez usypiania:
    [C++] Qt - Program do obsługi portu szeregowego

    :arrow: Dodana metoda msleep(1):
    [C++] Qt - Program do obsługi portu szeregowego

    0
  • #16 02 Cze 2012 13:46
    cyco22
    Poziom 8  

    że jeszcze zadam głupie pytanie: w którym miejscu to umieścić(tylko chodzi mi o miejsce,metodę sobie sam rozgryzę), bo aż taki dobry w programowaniu to jeszcze nie jestem ;)

    0
  • #18 02 Cze 2012 21:09
    gaskoin
    Poziom 38  

    No tak, tymon dał makro forever więc moja wskazówka dotycząca pętli while mogła być trochę myląca :)

    0
  • #19 04 Cze 2012 11:12
    cyco22
    Poziom 8  

    to teraz kolejne moje głupie pytanie, jak to zaimplementować do mojego programu? jak próbuję wywołać read po otwarciu portu to wywala mi SIGABRT.

    Ok z tym już sobie poradziłem. Teraz jest problem konwersji na hexa, chodzi mi dokładnie o odczyt tak jak miałem wcześniej, np w postaci chara i żeby zapisał do tablicy. Bo potem najłatwiej będzie mi sprawdzić ramkę po poszczególnych bitach niż żeby analizować całość.

    0
  • #20 05 Cze 2012 22:18
    tymon_x
    Poziom 30  

    cyco22 napisał:
    Ok z tym już sobie poradziłem. Teraz jest problem konwersji na hexa, chodzi mi dokładnie o odczyt tak jak miałem wcześniej, np w postaci chara i żeby zapisał do tablicy. Bo potem najłatwiej będzie mi sprawdzić ramkę po poszczególnych bitach niż żeby analizować całość.

    Ta zmiana jest prosta, zmieniasz rodzaj typu w FIFO z QString na QChar i skracasz parsowanie QString w wątku na pojedynczy zapis do FIFO z portu szeregowego. I tyle, masz wersję na odczyt i zapis w postaci Hex, bajtowej. Zmiana jest naprawdę kosmetyczna.

    0
  • #21 11 Cze 2012 11:41
    cyco22
    Poziom 8  

    No i podczas zamiany napotkałem kolejny problem:
    obecnie odczyt danych wygląda w ten sposób:

    Kod: cpp-qt
    Zaloguj się, aby zobaczyć kod
    .

    Problem w tym że duplikuje mi przy odczycie dane. Ramka zaczyna się od 21 a kończy na 0a, natomiast tutaj mam praktycznie aby sam bajt zakończenia ramki. W dodatku jest ona za długa gdyż powinna się składać z 9 bajtów a czasem wychodzi tego o wiele więcej lub na poszczególnych bajtach pojawiają się informacje, których urządzenie nie wysyła.

    Wygląda to tak:
    [C++] Qt - Program do obsługi portu szeregowego

    0
  • #22 08 Sty 2013 23:23
    uzi18
    Poziom 23  

    pPort->read(bufferString, &numberOfBytesRead, BUFFER_READ_MAX);

    bywa true albo false
    gdy jest true to znaczy ze cos przyszlo i wtedy przekazujemy dalej

    W QtCom mozna jeszcze dodac (w sumie ttyS* tez powinno tam sie znalezc):

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #25 09 Sty 2013 07:16
    tymon_x
    Poziom 30  

    Dobra, zaczynamy zabawę, wrzuciłem na Google Code, wersja ta ostatnia z postu, opatrzyłem tylko wszystkie pliki licencją BSD New. Korzystam mercurial. Lecę już do roboty bo świta :) Wieczorem wrzucę potrzebne zmiany, enjoy:

    http://code.google.com/p/qtcom/

    Na pewno dodam jeszcze skrypt w pythonie do automatycznego tagowania. Jak ktoś korzysta z Windows może skorzystać z tego: http://tortoisehg.bitbucket.org/

    0
  • #27 09 Sty 2013 12:57
    tymon_x
    Poziom 30  

    uzi18 napisał:
    Nie znam hg ;) zwykle uzywam git/cvs/svn (w takiej kolejnosci) :D

    Zawsze coś nowego :)
    Jest prosty w obsłudze, clone, po commit, push, a zaciągasz update, pull tak w najprostszej wersji:
    http://hginit.com/
    http://mercurial.selenic.com/wiki/Tutorial

    Ja sobie chwalę hg. Jak używasz git, to jest podobny do niego. W historii to właśnie hg miał służyć do wersjonowania kernela Linux, a że właśnie Git wyszedł z pod ręki Linusa, to było już wiadomo z góry co zostanie wybrane :)

    0
  • #29 15 Kwi 2013 22:21
    ginar
    Poziom 21  

    Witam
    Przeglądam kod z paczki QtCom.tar.gz i zastanawia mnie
    dlaczego np. linika którą oznaczyłem jako **(1)** nie jest chroniona mutexem tak, jak jest to zrobione w **(2)**.
    Zakładam taki scenariusz:
    precondition: w QueueWrite znajdują się dane
    1. funkcja run() odczytuje dane z pQueueWrite - (zakładam, że odczyt jest nie atomowy), tutaj przychodzi contex switch
    2. Inny wątek jest w akcji i wywołuje funkcje writeClear. Kolejka jest dostępna bo poprzedni wątek nie zblokował kolejki mutexem
    3. Powrót do wykonywania funkcji run() - gdzie mozliwe jest wczytanie 'uciętego' stringu
    ----------------
    Jest to jeden z pierwszych programów jaki widze w QT także byłbym wdzięczny za wyprowadzenie ze ewentualnego błędnego rozumowania.


    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0