Łączenie bajtów do jednej zmiennej

Pytania, kody i porady dotyczące nie tylko Bascom.
Pikczu
Posty: 390
Rejestracja: 17 sie 2015, 13:46
Lokalizacja: Dublin, Ireland
Kontakt:

Re: Łączenie bajtów do jednej zmiennej

Post autor: Pikczu » 01 mar 2019, 22:05

Kod: Zaznacz cały

Czy jest możliwość zliczenia przychodzących bajtów do bufora i po weryfikacji dopiero odbierać :?:
Tak jak tu:
  1. If Ischarwaiting() > 0 Then
  2.       Znak_ = Waitkey()                                     'pobierz znka z bufora
  3.       If Znak_ = 13 Or Len(uart_komenda) > 6 Then        ' jelsi ENTER lub wiecej niz 6 znaków to call uartrx
  4.          Call Uartrx_                                       '
  5.          Uart_komenda = ""
  6.       Else
  7.          Uart_komenda = Uart_komenda + Chr(znak_)           'kluczowe budowanie bufora
  8.          Print Chr(znak_) ;                             'to jest echo zeby było widac co przychodzi
  9.       End If
Jeśli przyjdzie enter (ASCII 13) lub ilosc odebranych zanków przekroczy 6 to zrób cos czyli ten call uartrx_.
Następnie wyczyść bufor czyli uart_komenda= ""

Jeśli piszesz własną komunikację od początku to zrobił bym to na tablicy nadawanie z printbin i odbiór z inputbin
Wtedy np w komórkę pierwszą zrobił bym jako nagłówek , ilość bajtów , komenda, wartość i na końcu crc.
  1. dim tablica_tx(6) as byte
  2. tablica(1)= 'tu nagłowek
  3. tablica(2)= 'tu ilość bajtów do przesłania razem z CRC
  4. tablica (3)= 'tu komenda
  5. tablica(4)= 'tu wartosc górny bajt
  6. tablica(5) = 'tu wartosc dolny bajt
  7. tablica(6) = 'tu CRC z wszystkich

******************************edit*************************************
Wtedy będzie łatwiej przewidzieć przychodzące ramki.
Bo jeśli odebrałeś nagłówek i ilość bajtów to wiesz kiedy przestać odbierać z bufora.
Awatar użytkownika
Henryk
Posty: 348
Rejestracja: 22 sty 2018, 17:20

Re: Łączenie bajtów do jednej zmiennej

Post autor: Henryk » 01 mar 2019, 22:21

Jeśli piszesz własną komunikację od początku to zrobił bym to na tablicy nadawanie z printbin i odbiór z inputbin
Wtedy np w komórkę pierwsza zrobił bym jak nagłówek , ilość bajtów , komenda, wartość i na końcu crc.
Powoli :D pierwsze muszę "przetrawić " dzisiejsze przykłady , jutro tradycyjnie wyprawa do lasu , to będę mógł sobie rozmyślać ;)
Dziękuje za dzisiejsze przykłady i podpowiedzi , zmykam w pióra :D

Pozdrawiam Henryk
Pikczu
Posty: 390
Rejestracja: 17 sie 2015, 13:46
Lokalizacja: Dublin, Ireland
Kontakt:

Re: Łączenie bajtów do jednej zmiennej

Post autor: Pikczu » 02 mar 2019, 16:37

Henryk dziś właśnie Mark Alberts napisał na forum do jednego z użytkowników:
a string may not contain a 0 byte since it is the end of string marker.
but you can also use a byte array to store the data.
or better, use buffered serial input
tłumacząc z wolna:
Że string nie może zawierać 0 bo jest to znacznikiem końca nadawania dla stringa.
Ale możesz także użyć tablicy bajtów do przechowywania danych.
Lub lepiej, użyj buforowanego serial input.

Więc jeśli będziesz przesyłał dane jako tekst dana ta nie będzie mogła zawierać 0 bo będzie to oznaczało znacznik końca dla string.
Awatar użytkownika
Henryk
Posty: 348
Rejestracja: 22 sty 2018, 17:20

Re: Łączenie bajtów do jednej zmiennej

Post autor: Henryk » 02 mar 2019, 17:41

Witam :D

Poddaje się , nie rozumie tych stringów .
W takim razie co ja wysyłam ?
Zmienna suma jest string*4 , Dane_1 , Dane_2 to Dword , przesyłam do terminala przez print.
Terminal wysyła / odbiera jako Ascii .
Wysyłam sobie dowolne liczby , nawet same zaera , transmisja za każdym razem poprawna .
Kod poniżej działa idealnie , pod warunkiem , że wysyłam zawsze tą samą ilość znaków .
  1. $regfile = "m8def.dat"
  2. $crystal = 8000000
  3. $hwstack = 32
  4. $swstack = 16
  5. $framesize = 32
  6. $baud = 9600
  7. Config Serialin = Buffered , Size = 10
  8. Config Lcd = 20 * 4
  9. Config Lcdpin = Pin , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , Db7 = Portc.5 , E = Portc.1 , Rs = Portc.0
  10.  
  11.  
  12. Dim Suma As String * 4
  13. Dim Serial_flag As Byte
  14. Dim Dane_1 As Dword , Dane_2 As Dword
  15. Cursor Off
  16. Cls
  17. Dane_2 = 123456       'dane_2 ..?  taki kaprys :-)
  18. Enable Interrupts
  19. Do
  20.  
  21.  Serial_flag = Ischarwaiting()
  22.     If Serial_flag = 1 Then
  23.       Inputbin Suma , 4
  24.       Dane_1 = Val(suma)
  25.           Locate 1 , 1 : Lcd "Txt " ; Suma ; "    "
  26.           Locate 2 , 1 : Lcd "Dec " ; Dane_1 ; "    "
  27.            Print "odebrano dane"
  28.               Print "Dane_1.." ; Dane_1 ; "   Dane_2.." ; Dane_2 ; "    suma.." ; Suma
  29.             End If
  30.         Loop
  31.  
  32.  End
IMG_20190302_172453.jpg
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Awatar użytkownika
niveasoft
Posty: 1213
Rejestracja: 17 sie 2015, 12:13
Kontakt:

Re: Łączenie bajtów do jednej zmiennej

Post autor: niveasoft » 02 mar 2019, 20:10

Funkcja Print automatycznie zamienia dane na ASCII czyli jeśli to co wysyłasz to nie string to po wysłaniu komendą PRINT będzie już stringiem ;)
To żadna tajemnica że w ASCII zero ma wartość 48.
Znaki do wartości 32 (to jest spacja) są normalnie w terminalu niewidoczne i służą do kontrolowania pewnych rzeczy. Dlatego można dodać Enter i LF na końcu wysyłania co normalnie program ignoruje ale terminal już wie co z tym zrobić. CR to bezpośredni skrót od Carriage Return a po polsku "powrót karetki" To jeszcze z czasów maszyn do pisania. Czyli terminal grzecznie wskoczy do nastepnej linii.

Jeśli więc wyślesz poleceniem Print zmienną Dword = 12340 to Bascom ją wysyła jako 49,50,51,52,48
Napisz jakoś mniej enigmatycznie niż to masz w zwyczaju co to chcesz odebrać. Jeśli string może mieć różną ilość znaków to przecież można wykorzystać znak Enter lub nawet dodać Timeout jak przy Modbus.

Może inaczej. Im dłużej się w tym grzebie tym bardziej widać potrzebę tego żeby kod był odporny na niesprzyjające warunki. Trzeba zakładać że dojdzie tylko jedna literka i coś z tym zrobić, że przyjdzie więcej literek albo są niezrozumiałe...i też coś z tym zrobić.

Coś tam pisałeś że chcesz ostatecznie wyciągnąć z przesłanego stringa wartość do zmiennej Dword. Wtedy proponuję użyć ustawienia Valcheck ;)
  1. $regfile = "m328pdef.dat"
  2. $Crystal=16000000
  3. $hwstack = 40
  4. $swstack = 16
  5. $framesize = 64
  6. $sim
  7.  
  8. Const _valcheck = 1                                         'sprawdza poprawnosc znaków
  9.  
  10. Dim Mystr As String * 5
  11. Dim Myval As Dword , Helpd As Dword
  12.  
  13. Mystr = "1234"
  14.  
  15. Helpd = Val(mystr)                                          'używamy pomocniczej zmiennej
  16. If Err = 0 Then                                             'wartośc docelowej zmiennej
  17.  Myval = Helpd                                              'ustawiamy TYLKO jesli nie było błędu
  18.   Print Myval
  19. End If
  20.  
  21. Mystr = "45AA"
  22. Helpd = Val(mystr)                                          'używamy pomocniczej zmiennej
  23. If Err = 0 Then                                             'wartośc docelowej zmiennej
  24.  Myval = Helpd                                              'ustawiamy TYLKO jesli nie było błędu
  25.   Print Myval                                               'to się nie wydrukuje
  26. Else
  27.   Print "ERROR!"
  28. End If
  29. End
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Awatar użytkownika
Henryk
Posty: 348
Rejestracja: 22 sty 2018, 17:20

Re: Łączenie bajtów do jednej zmiennej

Post autor: Henryk » 02 mar 2019, 21:33

Witaj Bartek :D
Funkcja Print automatycznie zamienia dane na ASCII czyli jeśli to co wysyłasz to nie string to po wysłaniu komendą PRINT będzie już stringiem ;)
No i wszystko jasne co jest przesyłane .
Napisz jakoś mniej enigmatycznie niż to masz w zwyczaju co to chcesz odebrać.
Wybacz , ale nie oczekuj od amatora jasnego opisu co chce osiągnąć ;)
Chcę poznać zasady przesyłu / odbioru danych , jestem w tym kiepski , ćwiczenia rozwijają stąd temat .

Spróbuję prosto opisać ;)
Wysyłam dane z urządzenia(nadajnik) : Print Dane_1 ; Dane_2 ; Dane_3 ; Dane_4
Dane_1 , 2 zmienna Dword ...... Dane_3 , 4 zmienna byte .
Chcę odebrać je w urządzeniu(odbiornik) w tych samych typach zmiennych .
Awatar użytkownika
niveasoft
Posty: 1213
Rejestracja: 17 sie 2015, 12:13
Kontakt:

Re: Łączenie bajtów do jednej zmiennej

Post autor: niveasoft » 02 mar 2019, 22:30

Jeśli możesz zapakować dane tak by były wysyłane z przecinkami to poniższy kod powinien działać.
Wysyłasz np: Print D1 ; "," ; D2 ; "," ; B1 ; "," ; B2
Kod który to odbierze i zapakuje dane D1, D2, B1 i B2 poniżej.
Żeby móc przy starcie przetestować parsowanie wrzuciłem to sobie w Sub i wywołuję go kontrolnie. To sobie wyrzucisz.
Kod polega na tym że mamy w stringu przecinki. Spodziewany sie odebrać trzy przecinki czyli dzielimy string na cztery mniejsze.
Timeout jest po to gdyby Enter nigdy nie nadszedł.
  1. $regfile = "m8def.dat"
  2. $crystal = 8000000
  3. $hwstack = 32
  4. $swstack = 16
  5. $framesize = 32
  6. $baud = 9600
  7.  $sim
  8.  
  9. Const _valcheck = 1
  10. Config Submode = New
  11. Const String_max_len = 50
  12.  
  13. Config Serialin = Buffered , Size = 10
  14.  
  15. Config Lcd = 20x4
  16. Config Lcdpin = Pin , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , Db7 = Portc.5 , E = Portc.1 , Rs = Portc.0
  17. Cursor Off , Noblink
  18.  
  19. Dim D1 , D2 As Dword , B1 , B2 As Byte
  20. Dim Char As Byte , Command As String * String_max_len
  21. Dim Timeout As Byte , Got_str As Byte
  22. Dim Helpd As Dword , Helpb As Byte
  23. Dim Myarr(5) As String * 10
  24.  
  25.  
  26. Sub Parse_data
  27.  
  28.  Helpb = Split(command , Myarr(1) , ",")                    'powinno wyjść 4
  29.  If Helpb = 4 Then                                          'mamy cztery stringi
  30.   Helpd = Val(myarr(1))
  31.   If Err = 0 Then
  32.    D1 = Helpd
  33.   Else
  34.    Exit Sub
  35.   End If
  36.  
  37.   Helpd = Val(myarr(2))
  38.   If Err = 0 Then
  39.    D2 = Helpd
  40.   Else
  41.    Exit Sub
  42.   End If
  43.  
  44.   Helpb = Val(myarr(3))
  45.   If Err = 0 Then
  46.    B1 = Helpb
  47.   Else
  48.    Exit Sub
  49.   End If
  50.  
  51.   Helpb = Val(myarr(4))
  52.   If Err = 0 Then
  53.    B2 = Helpb
  54.   Else
  55.    Exit Sub
  56.   End If
  57.  
  58.    Print "Received:" ; D1 ; "," ; D2 ; "," ; B1 ; "," ; B2
  59.  Else
  60.   Exit Sub
  61.  End If
  62.  
  63. End Sub
  64.  
  65. Enable Interrupts
  66.  
  67. 'dla testu parsowania
  68.   Command = "12345,23456,128,200"
  69.  Call Parse_data()
  70.   Command = ""
  71.  
  72.  
  73. Do
  74.  If 0 < Ischarwaiting() Then
  75.   Char = Waitkey()
  76.  
  77.   Select Case Char
  78.    Case 10
  79.    Case 13 : Got_str = 1
  80.    Case Else
  81.     Command = Command + Chr(char)
  82.   End Select
  83.  
  84.     If Len(command) = String_max_len Then
  85.      Got_str = 1
  86.     Else
  87.      Timeout = 5
  88.     End If
  89.  End If
  90.  
  91.  If Timeout > 0 Then
  92.   Decr Timeout
  93.   If Timeout = 0 Then Got_str = 1
  94.  End If
  95.  
  96.  If Got_str = 1 Then
  97.   Timeout = 0
  98.    Call Parse_data()
  99.  
  100.   Command = ""
  101.   Got_str = 0
  102.  End If
  103.  
  104.  Waitms 1                                                   'małe opóźnienie dla Timeout, lepiej użyć Timera
  105. Loop
  106. End
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Awatar użytkownika
Henryk
Posty: 348
Rejestracja: 22 sty 2018, 17:20

Re: Łączenie bajtów do jednej zmiennej

Post autor: Henryk » 03 mar 2019, 9:02

Witam :D
Dziękuje Bartku za ten przykład . Dzisiejsza poranna kawa była baaaardzo wczesna :D
Odrobinę namieszałem w kodzie by lepiej go zrozumieć .
  1. $regfile = "m8def.dat"
  2. $crystal = 8000000
  3. $hwstack = 32
  4. $swstack = 16
  5. $framesize = 32
  6. $baud = 9600
  7.  $sim
  8.  
  9. Const _valcheck = 1
  10. Config Submode = New
  11. Const String_max_len = 50
  12.  
  13. Config Serialin = Buffered , Size = 10
  14.  
  15. Config Lcd = 20x4
  16. Config Lcdpin = Pin , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , Db7 = Portc.5 , E = Portc.1 , Rs = Portc.0
  17. Cursor Off , Noblink
  18.  
  19. Dim D1 , D2 As Dword , B1 , B2 As Byte
  20. Dim Char As Byte , Command As String * String_max_len
  21. Dim Timeout As Byte , X As Byte , Got_str As Bit
  22. Dim Helpd As Dword , Helpb As Byte
  23. Dim Myarr(5) As String * 10
  24.  
  25.  
  26. Sub Parse_data
  27.  
  28.  Helpb = Split(command , Myarr(1) , ",")       'powinno wyjść 4
  29.  If Helpb = 4 Then       'mamy cztery stringi
  30.   For X = 1 To 4
  31.   Helpd = Val(myarr(x))
  32.   If Err = 0 Then
  33.    Select Case X
  34.     Case 1 : D1 = Helpd
  35.     Case 2 : D2 = Helpd
  36.     Case 3 : B1 = Helpd
  37.     Case 4 : B2 = Helpd
  38.     End Select
  39.      Else
  40.    Exit Sub
  41.   End If
  42.   Next X
  43.  
  44.    Print "Received:" ; D1 ; "," ; D2 ; "," ; B1 ; "," ; B2
  45.  Else
  46.   Exit Sub
  47.  End If
  48.  
  49. End Sub
  50.  
  51.  
  52. Enable Interrupts
  53.  
  54. Command = "923456789,23456,128,200"
  55.  
  56. 'dla testu parsowania
  57.  Call Parse_data()
  58.  Command = ""
  59.  
  60.  
  61. Do
  62.  If 0 < Ischarwaiting() Then
  63.   Char = Waitkey()
  64.  
  65.   Select Case Char
  66.    Case 10
  67.    Case 13 : Got_str = 1
  68.    Case Else
  69.     Command = Command + Chr(char)
  70.   End Select
  71.  
  72.     If Len(command) = String_max_len Then
  73.      Got_str = 1
  74.     Else
  75.      Timeout = 5
  76.     End If
  77.  End If
  78.  
  79.  If Timeout > 0 Then
  80.   Decr Timeout
  81.   If Timeout = 0 Then Got_str = 1
  82.  End If
  83.  
  84.  If Got_str = 1 Then
  85.   Timeout = 0
  86.    Call Parse_data()
  87.     Command = ""
  88.   Got_str = 0
  89.  End If
  90.  
  91.  Waitms 1       'małe opóźnienie dla Timeout, lepiej użyć Timera
  92. Loop
  93. End
Szukam w sieci informacji na temat _valcheck z marnym skutkiem .
Wysyłając na końcu danych Enter można zrezygnować z timeout :?:
Awatar użytkownika
niveasoft
Posty: 1213
Rejestracja: 17 sie 2015, 12:13
Kontakt:

Re: Łączenie bajtów do jednej zmiennej

Post autor: niveasoft » 03 mar 2019, 9:31

O _VALCHECK można przeczytać w temacie Helpa dotyczącym funkcji VAL :arrow: LINK

Teraz chciałbym chwile popisać o tych Twoich zmianach.
Czasem może się wydawać że coś zaoszczędzisz w kodzie jak użyjesz pętli do powtarzających się zadań lub użyjesz Bitów do stawiania flag 0-1.
Otóż nie zawsze.
Pętle For-Next przydają się jeśli kod który się powtarza jest duży lub powtórzeń jest dużo.
Przy małych operacjach szybsze i generujące mniej kodu są takie wpisy jak zrobiłem ja, czyli kilka tych samych zadań Inline.

To samo z ustawianiem flag bitowych. Jeśli używam flagi Got_str As Byte to kompilator wpisuje do niej dane bardzo szybko ba ładuje sobie jedynkę do R24 po czym ją zrzuca do zmiennej pod znanym adresem.
Natomiast gdy Ty używasz Got_str As Bit to kompilator musi wczytać zmienną trzymającą flagi. Potem żeby ustawić flagę musi zrobić OR na rejestrze po czym dopiero zrzuca rejestr z powrotem do zmiennej.
Jeszcze gorzej jest przy sprawdzaniu stanu flagi. W moim rozwiązaniu kompilator sobie wrzuca jedynkę do jakiegoś wolnego rejestru i porównuje dwa rejestry czy są równe. W przypadku Bitu musi najpierw wyłuskać dany Bit przy pomocy AND potem do innego rejestru wrzucić taką przygotowaną maskę bitową i dopiero porównuje.

Efektem Twoich działań jest to że teraz teoretycznie krótszy kod zajmuje 20% flash (1646B) gdzie mój wczorajszy, robiący to samo zajmuje 18% flash (1526B) i założę się że mój wykonuje się szybciej ;)

PS. Dla tak długich stringów powinieneś zwiększyć bufor bo 10 to trochę mało ;)
  1. Config Serialin = Buffered, Size = String_max_len
Awatar użytkownika
Henryk
Posty: 348
Rejestracja: 22 sty 2018, 17:20

Re: Łączenie bajtów do jednej zmiennej

Post autor: Henryk » 03 mar 2019, 9:53

Dziękuje za opis .
Bardzo zawiły jest ten świat programowania :D chyba żaden amator nie analizuje tak głęboko tego co pisze .
Pisząc program jestem jak klient marketu budowlanego , łapie koszyk i w regały ! nazbierać klocków do budowy .
Chyba zaczynam być jak beton , odporny na wiedzę i trudny do roz....... :lol:
Czapka z głowy za Twoją wiedzę !

Edit:
O _VALCHECK można przeczytać w temacie Helpa dotyczącym funkcji VAL :arrow: LINK
Teraz rozumie skąd wzięło się w programie Err , ja błędnie myślałem o split .

Edit:
Zrzut ekranu terminala , działa ślicznie , to co przerobiłem w kodzie jest wolniejsze w działaniu .
Twoje Bartku działa szybciej , jak zwykle racja po twojej stronie :D
Bufor ustawiłem na 20 , wystarczy ?
foto01.jpg
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
ODPOWIEDZ