Funkcja Copy dla stringa pobranego z portu szeregowego

Funkcja Copy dla stringa pobranego z portu szeregowego
AD
  • Rejestracja:około 14 lat
  • Ostatnio:4 miesiące
  • Postów:85
0

Odbieram dane z wagi poprzez komponent ComPort w następujący sposób:

Kopiuj
procedure TForm1.ComPortRxChar(Sender: TObject; Count: Integer);
var
  Str,waga: String;
begin
ComPort.ReadStr(Str, Count);
waga:=Copy(Str,10,5);
Memo.Text:=Memo.Text+waga;
end;

Waga wysyła ramkę danych w postaci 'SI 0.00 kg', z której potrzebuję wyciąć samą wagę. Napisana powyżej funkcja Copy działając na danych wysyłanych z portu z prędkością 9600 zwraca w Memo ten sam string).

Uruchomienie funkcji Copy w następujący sposób zwraca prawidłowy wynik.

Kopiuj
procedure TForm1.Button1Click(Sender: TObject);
var Str:string;
begin
str:='SI         0.00 kg'; //ciąg skopiowany z terminala
Memo.Text:=Copy(Str,10,4);
end;

Wg dokumentacji wagi wysyłany string ma postac

S _ _ _ _ - _ _ _ _ _ _ 8 . 5 _ kg _ _ CR LF //podkreśliniki to spacje

Próba usunięcia znaków końca linii w ten sposób również nic nie daje.

Kopiuj
procedure TForm1.ComPortRxChar(Sender: TObject; Count: Integer);
var
  Str,str2,waga: String;
begin
ComPort.ReadStr(Str, Count);
Str2:=StringReplace(Str,#13#10,'add',[rfReplaceAll]);
waga:=Copy(Str2,12,5);
Memo.Text:=Memo.Text+waga;
end;

dodanie znaczników <code class="delphi"> i `` - Furious Programming

edytowany 2x, ostatnio: flowCRANE
KA
Azarien
"potrzebuję wyciąć samą wagę"
flowCRANE
@adnix - wstawiaj kod w odpowiednie dla danego języka znaczniki kolorujące składnię;
MA
  • Rejestracja:prawie 17 lat
  • Ostatnio:minuta
0

Problem z odczytem ramki wysyłanej przez wagę może być związany z tym, że gdy dostajesz zdarzenie OnRxChar, to nie koniecznie musi ci przyjść CAŁA ramka wysyłana przez wagę, a tylko jej część. Brakująca część przyjdzie w następnym zdarzeniu OnRxChar, tak więc najpierw kompletujesz całą ramkę (której długość jest ci znana), a dopiero ją przetwarzasz, np.:

Kopiuj
Var
 Ramka: String;

procedure TForm1.ComPortRxChar(Sender: TObject; Count: Integer);
var
  S, waga: String;
begin
  ComPort.ReadStr(S, Count); //odczyt całej lub części ramki
  Ramka:=Ramka+S; //łączenie kolejnych części ramki w jedną całość
  if length(Ramka)=Dlugosc_ramki then //za Dlugosc_ramki podstawiasz ilość znaków ramki 'S _ _ _ _ - _ _ _ _ _ _ 8 . 5 _ kg _ _ CR LF'
  begin 
    waga:=Copy(Ramka, 10, 5);
    Memo.Text:=Memo.Text+waga;
    Ramka:='';
  end; 
end;
abrakadaber
abrakadaber
  • Rejestracja:prawie 13 lat
  • Ostatnio:9 miesięcy
  • Postów:6610
0

dane przychodzą w paczkach po max 8 bajtów. Jeśli chcesz to możesz albo zrobić jak @marogo napisał(a) (z tym, że to nie zadziała w takiej postaci - zamiast sprawdzać czy masz odpowiednią ilość znaków sprawdzaj czy odebrałeś CR LF i jako ramkę traktuj wszystko to co jest pomiędzy kolejnymi CR LF albo użyj TComDataPacket ustawiając jako koniec danych CR LF - wtedy odwali on za Ciebie całą robotę z kompletowaniem ramki


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
Zobacz pozostały 1 komentarz
MA
"Jeśli chcesz to możesz albo zrobić jak @marogo napisał(a) (z tym, że to nie zadziała w takiej postaci" - zaskakujące rzeczy piszesz, bo używam takiego mechanizmu w kilku programach dla ramek o stałej długości i działa elegancko :) Oczywiście sposób z wykrywaniem CRLF jest jak najbardziej dobry, szczególnie gdy ma się do czynienia z ramką o różnej długości, np. ramki GPS-u. W przypadku opisywanym przez pytającego mamy do czynienia ze stałą długością ramki.
abrakadaber
abrakadaber
1. z doświadczenia - być może zależy to od konkretnej implementacji portu (sprzętowej) ale wszystkie, z którymi miałem do czynienia słały po 8 bajtów
abrakadaber
abrakadaber
2. wystarczy, że z jakiegoś powodu zgubi Ci się parę bajtów jednej ramki (bo się urządzenie przywiesi, bo ktoś kabel ruszy, bo zupa była za słona) i jesteś w czarnej dupie - każde kolejne odczyty będą obarczone błędem wadliwej ramki. Natomiast składanie ramki od CRLF do CRLF ma tą zaletę, że wadliwe ramki są po prostu ignorowane ale kolejne są już odczytywane poprawnie
MA
Zgadzam się, rozdzielanie ramek wg CRLF jest pewniejsze, dlatego stosuje je w nowszych programach, a w przypadku sprawdzania tylko po długości ramki, to nie prawda, że "nie zadziała w takiej postaci", bo zadziała, ale jest obarczone ryzykiem utraty synchronizacji programu z urządzeniem nadawczym, czego się nie obawiałem w moich programach, w których to stosowałem, bo jest tam timer odmierzający limit czasu na pojawienie się prawidłowej ramki i w sytuacji nie pojawienia się jej, dotychczas odebrane dane (niekompletne lub nieprawidłowe) były kasowane.
GS
@ abrakadaber , implementacja portu nie ma tu żadnego znaczenia . Port COM dostanie na wejściu dokładnie tyle bajtów ile wyśle podpięte do niego urządzenie . Być może urządzenia z którymi se spotkałaś słały zawsze osmiobajtowymi paczkami, ale to dość szczególny przypadek. Przykładowo , drukarki fiskalne Elzabu odsyłają status na jednym bajcie
lofix
  • Rejestracja:około 23 lata
  • Ostatnio:19 dni
  • Lokalizacja:Wdzydze
0

Wg mnie powinna zadziałać metoda opisana przez usera Abrakadaber.
Użyj TComDataPacket i przed połączeniem się z portem ustaw mu właściwości

Kopiuj
ComDataPacket.StartString = '';
ComDataPacket.StopString = '';

Poza tym sprawdź, czy nie łatwiej operować Ci na stringu jaki zwraca TComDataPacket.OnPacket


Pozdrawiam. Karol
edytowany 1x, ostatnio: lofix
abrakadaber
abrakadaber
jak już to ComDataPacket.StopString = #13#10;
lofix
Dzięki za celną uwagę...
AD
  • Rejestracja:około 14 lat
  • Ostatnio:4 miesiące
  • Postów:85
0

Pomogło ustawienie StopStringa z poziomu kodu.
Dzięki za pomoc.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.