logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[AT32] Jak poprawnie sparsować datę i godzinę z UART w AT32?

tomson5 15 Sty 2016 18:16 3561 31
  • #1 15337549
    tomson5
    Poziom 16  
    Witam
    odbieram przez uart taki string
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Próbuje w ten sposób wydobyć z niego godzinę i datę

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Niestety nie działa mi to.
    Prawdopodobnie z powodu spacji.
  • Pomocny post
    #2 15337580
    grko
    Poziom 33  
    Funkcja strcmp zwróci zero jeżeli stingi sa takie same (tzn maja takie same znaki i oba konczą sie null terminatorem w tym samym miejscu). Jezeli chcesz tylko czesc stringa porównac użyj funkcji strncmp. A tak wogóle to najlepiej tutaj się sprawdzi sscanf.
  • Pomocny post
    #3 15337616
    BlueDraco
    Specjalista - Mikrokontrolery
    A po co się tak męczyć, jeśli łańcuch ma stały format? Po sprawdzeniu, że zaczyna się od "AT+CIPNTP? Time:" po prostu sięgasz pod stałe i znane pozycje w buforze i masz tam to, czego potrzebujesz.
  • #4 15337838
    tomson5
    Poziom 16  
    Cytat:

    Po sprawdzeniu, że zaczyna się od "AT+CIPNTP? Time:" po prostu sięgasz pod stałe i znane pozycje w buforze i masz tam to, czego potrzebujesz.


    Właśnie to próbuje zrobić.

    Poniższy kod mi działa jeżeli odbieram dane w postaci:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Ale gdy dane są w formacie
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    to już nie działa
  • Pomocny post
    #5 15337988
    BlueDraco
    Specjalista - Mikrokontrolery
    A konkretnie, to w czym masz problem? Po sprawdzeniu przy użyciu strncmp(), że na początku masz to, co trzeba, dalej wyłuskujesz znaki ze STAŁYCH pozycji, nie trzeba niczego szukać, używać strtok itp.

    Godzinę masz pod bufor[8] i bufor[9], minuty pod 11 i 12 itd.
  • #6 15338186
    tomson5
    Poziom 16  
    Ruszyłem z miejsca. Miałem problem z wielkością bufora RX.

    Po sprawdzeniu przy użyciu strcmp() otrzymałem:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Teraz próbuję zrozumieć twoją koncepcję.


    EDIT: Po wielu próbach udało mi się uzyskać dwie tablice

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Gdzie kopiuje uzyskany czas i datę.
    Zrobiłem to z użyciem strtok()
  • Pomocny post
    #7 15339152
    Konto nie istnieje
    Konto nie istnieje  
  • Pomocny post
    #8 15339745
    Andrzej__S
    Poziom 28  
    Spróbuję podać Ci przykład kodu z wykorzystaniem strtok():
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Nie jest to na pewno najlepsze rozwiązanie, chciałem Ci tylko pokazać przyklad, jak używać strtok().

    Przy założeniu, że ciąg znaków ma zawsze tę samą długość i cyfry mają ustaloną stałą pozycję w ciągu, można też bez strtok(), tak jak radził kolega BlueDraco, czyli (dla tego samego ciągu) coś w stylu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #9 15339977
    tomson5
    Poziom 16  
    Dziękuję za zastrzyk wiedzy.
    Wieczorem wezmę się za analizę tego.
    Nawet nie myślałem żeby to tak bardzo rozbijać. wystarczyło by na dwie tablice gdzie w jednej mamy czas GG:MM:SS a w drugiej MM/DD/YYYY
    Oczywiście tak jest lepiej bo można tych danych użyć np: do aktualizacja zegara RTC. Rewelacja.
  • #10 15341258
    BlueDraco
    Specjalista - Mikrokontrolery
    Może szybciej i prościej:

    time.hour = str[17] * 10 + str[18] - 11 * '0';

    ;)
  • Pomocny post
    #11 15341329
    grko
    Poziom 33  
    Nie wiem skąd opór używania funkcji, które są STANDARDEM. Nie ma nic bardziej denerwującego jak spotkam jakieś hieroglify w legacy code bo autor myślał że jest cool i napisał skanowanie stringa ręcznie.

    Parsowanie tej AT komendy to po prostu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    I proszę nie mówić ile to sscanf zajmuje bo uproszczonych implementacji na githubie jest mnóstwo. Zresztą w samym avr-libc sscanf zajmuje całe 2KB.
  • Pomocny post
    #12 15341377
    BlueDraco
    Specjalista - Mikrokontrolery
    Może stąd, że w pewnych sytuacjach taka akcja zajmuje mniej miejsca i czasu niż samo wywołanie funkcji standardowej (printf, sscanf), że o samej funkcji (zajętości pamięi i czasie wykonania) już nie wspomnę.

    Można tu zapytać, czy przypadkiem sscanf nie zajmuje więcej miejsca niż cała reszta kodu. Nie sądzę również, by dało się użyć sscanf np. na ATtiny 13.
  • Pomocny post
    #13 15341420
    grko
    Poziom 33  
    Temat dotyczy wersji 32 KB więc miejsce jest. Jakąś uproszczoną wersję dałoby się pewnie zmieścić w 1KB.

    Cytat:

    Można tu zapytać, czy przypadkiem sscanf nie zajmuje więcej miejsca niż cała reszta kodu


    No i co z tego? A nawet jeżeli to byłaby prawda program będzie zajmował całe 4KB. Cięzko to upchnąć w Atmega32.

    Argument odnoszący się wydajności jest po prostu śmieszny. Ile razy do MCU będzie przychodziła ramka z data i godziną i jaki narzut będzie miał sscanf na wykonanie całego programu?


    printf oczywiście pomijamy w naszym przypadku.
  • #14 15342150
    BlueDraco
    Specjalista - Mikrokontrolery
    Zanim tacy jak Ty uznali taki argument za śmieszny, komputery z 32 K słów pamięci obsługiwały ośmiu użytkowników siedzących przy ośmiu terminalach (Mera 400). Od kiedy argument zaczął być śmieszny, taka możliwość przestała istnieć.
  • #15 15342184
    grko
    Poziom 33  
    Wiki:
    Cytat:

    SOM-3 w trzech wersjach (w tym wersja EXTENDED - wielozadaniowy z dynamicznym przydziałem pamięci);
    CROOK – oparty na ideach systemu Unix.


    Z tego co wiem to nie jesteś fanem ani dynamicznej alokacji ani abstrakcji związanej z plikiem w Unixie. Nadal Twoje argumenty są niedorzeczne.
  • #16 15342268
    BlueDraco
    Specjalista - Mikrokontrolery
    Ja mam w zasadzie jeden argument: nie należy bezsensownie i bez opamiętania marnować pamięci ani czasu procesora, niezależnie od tego, ile mamy pamięci i jaką moc obliczeniową.

    Troszkę marnować można, ale bez przesady. ;)

    Nie ma sensu używać sscanf ani atoi, jeśli w całym programie mamy do czynienia wyłącznie z konwersją liczb 1- i 2-cyfrowych i w dodatku wiemy z góry, ile cyfr ma każda konwertowana liczba - to polowanie z armatą na wróbla.

    Co jest niedorzecznego w tym argumencie?
  • #17 15342335
    grko
    Poziom 33  
    Cytat:

    Ja mam w zasadzie jeden argument: nie należy bezsensownie i bez opamiętania marnować pamięci ani czasu procesora, niezależnie od tego, ile mamy pamięci i jaką moc obliczeniową.


    Nie rozumiesz jednej rzeczy, która jest bardzo ważna w programowaniu embedded (w zasadzie to wogóle w programowaniu). Chodzi o kontekst wywołania funkcji. W naszym przypadku funkcja sscanf nie jest wywoływana w co 1ms w przerwaniu. Jej wywołanie ogranicza sie do przypadku synchronizacji czasu. Ile to może być? Jedna godzina? Niech będzie to jedna minuta. Ile prądu zaoszczędzisz w takim przypadku? Odnośnie zajętości pamięci: wybacz ale nie mam fetyszu aby 80% dostępnej pamięci FLASH miało wartość 0xFF.

    Cytat:

    Nie ma sensu używać sscanf ani atoi, jeśli w całym programie mamy do czynienia wyłącznie z konwersją liczb 1- i 2-cyfrowych i w dodatku wiemy z góry, ile cyfr ma każda konwertowana liczba - to polowanie z armatą na wróbla.

    Co jest niedorzecznego w tym argumencie?


    Nic z góry nie wiemy co przyjdzie po UART. Funkcja sscanf dodatkowo sprawdza sprawdza format przesyłanych danych i zwraca wartość (ilość zeskanowanych parametrów). Można odpowiednio zareagować na sytuacje wyjątkowe w takim wypadku. Poza tym wyobraź sobie, że mamy różnych 50 komend AT do parsowania. Jak zaczniesz dla każdej komendy pisać parsowanie ręcznie to kod ostatecznie więcej zajmie w pamięci FLASH niż użycie jednej, uniwersalnej, standardowej funkcji sscanf.
  • #18 15342699
    BlueDraco
    Specjalista - Mikrokontrolery
    Jeśli nie wiemy, co przyjdzie po UART, to sscanf nie pomoże - trzba napisać parser w postaci automatu - żadna sztuka. Użycie sscanf byłoby w takim przypadku poważnym błędem, bo przy 50 możliwych odpowiedziach być może zadziałałoby dopiero 50-te wywołanie sscanf. Wiem, są tacy amatorzy co tak piszą, ale to chore.

    Moim skromnym zdaniem w dobrze napisanym programie dla uC bez RTOS wszystkie funkcje są wywoływane wyłącznie w przerwaniach.
    ;)
  • Pomocny post
    #19 15342827
    Konto nie istnieje
    Konto nie istnieje  
  • #20 15342851
    grko
    Poziom 33  
    Cytat:

    Jeśli nie wiemy, co przyjdzie po UART, to sscanf nie pomoże - trzba napisać parser w postaci automatu - żadna sztuka.


    Czemu nie pomoże? Jeżeli podamy do sscanf ramkę ze stringiem zakończoną NULL inc się takiego nie stanie. Cały automat odbierający czeka na '\n' i wstawia null terminator na koniec ramki. Tak, to takie proste. Nic się nie zepsuje. I jak ktos wyśle np cos takiego:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    To sscanf wykryje, że jest błąd. Zresztą w wielu innych przypadkach też wykryje błąd. Poza tym co będziesz robił dla 50 takich AT komend? 50 oddzielnych maszyn stanów ?
  • Pomocny post
    #21 15342862
    Konto nie istnieje
    Konto nie istnieje  
  • #22 15342913
    grko
    Poziom 33  
    Do te pory w temacie parsowanie porządnie zostało zrobione przez sscanf (z kontrolą każdego typu elementu zawartego w stringu). Może zaproponuj jak powinna wyglądać taka maszyna stanów dla 50 AT komend i czy rzeczywiście to mniej zajmie miejsca w pamięci FLASH niż wywołanie 50 razy funkcji sscanf.
  • #23 15343061
    Konto nie istnieje
    Konto nie istnieje  
  • #24 15343112
    BlueDraco
    Specjalista - Mikrokontrolery
    Prosty parser odpowiedzi modułu GSM - Elektronika Praktyczna 08'2015. Każdy parser - automat będzie lepszy niż sscanf. Taki parser może działać w przerwaniu bez gromadzenia nadchodzących danych i zmieniać stan po każdym odebranym znaku - łatwo w ten sposób zrobić też wyjście z sytuacji awaryjnych i timeouty.

    sscanf w takim zastosowaniu to czysta amatorszczyzna
  • #25 15343182
    Konto nie istnieje
    Konto nie istnieje  
  • #26 15343470
    grko
    Poziom 33  
    @BlueDraco Mógłbyś pokazać taki parser? Bo hasła typu "każdy parser będzie lepszy" albo "nie użyje bufora i zaoszczędzę 30 bajtów" jakoś do mnie nie przemawiają. Wklej ten kod z EP to porozmawiamy co lepsze.


    Cytat:

    sscanf w takim zastosowaniu to czysta amatorszczyzna


    Dla mnie hieroglify + magic numbers typu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    to amatorszczyzna

    @Piotrus_999
    Cytat:

    @GrzegorzKostka - prosta sprawa : masz komende "A liczba" przy czym liczba moze byc w dowolnym formacie (int, float, exp) to scanf polega z marszu.


    Oczywiście bzdury. Ale skoro Ci sie myli scanf oraz sscanf to nie będę od Ciebie wymagał więcej. Widać, że jesteś na bakier z biblioteką standardową.

    Cytat:

    Inny przyklad - zrób kalkulator RPN - ciekawe jak uzyjesz scanf?


    Przez to, że sie nie da zrobić tego za pomocą sscanf mam już nigdy nie użyć tej funkcji? Niedorzeczne.
  • #27 15343810
    Konto nie istnieje
    Konto nie istnieje  
  • #28 15343853
    grko
    Poziom 33  
    Cytat:

    PS oczywiscie integera do floata wczytasz poprawnie - ale jest tylko jeden malutki problemik - jak ma 2k to nie skanuje floatów - a jak skanuje to juz ma 5k+
    Do integere wskanujesz floata np: sscanf("1.99","%d",&x); - ale wynik raczej Cie nie zadowoli. Inny przykład sscanf("12w2","%d",&x); - jak myslisz Kolego jaki bedzie wynik tego skanowania? Jakie jest zachowanie sscanf przy overflow?


    Wynik to 1 oraz 12. Mógłbyś podać przykład AT komendy z którą sscanf będzie miał problem? Nie wiem o co Ci chodzi.

    Przypominam, że zaczynaliśmy od:
    Cytat:

    "AT+CIPNTP? Time: 22:22:42 12/02/2015 GMT+02"


    Gdzie tu widzisz problem jak użyjemy sscanf w zaproponowany sposób?


    Cytat:

    Jakie jest zachowanie sscanf przy overflow?


    A jakie jest zachowanie Twojego, nieistniejącego parsera przy overflow? można użyć formatu %lu albo %llu. Do bezpiecznej konwersji służą też funkcje z rodziny strto**.
  • #29 15343947
    Konto nie istnieje
    Konto nie istnieje  
  • #30 15343979
    grko
    Poziom 33  
    Tyle że komenda przedstawiona przez autora jest w znanym formacie i do tego sscanf (nie scanf) nadaje się idealnie.
REKLAMA