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

Nextion - NodeMCU 8266 - Przekształcanie ciągu odebranych danych

Adrian1978 19 Mar 2021 14:51 636 11
REKLAMA
  • #1 19328355
    Adrian1978
    Poziom 11  
    Szanowni koledzy, napotkałem problem którego nie potrafię rozgryźć, może któryś z bardziej doświadczonych programistów podpowie jak można rozwiązać problem ? Będę bardzo wdzięczny za wszelkie sugestie. Dziś bez prezentacji kodu, bo chciałbym zapytać o samą ideę interpretacji danych odbiorczych i jak to "przetworzyć".

    W wyświetlaczu Nextion mam zapamiętywane kilka adresów MAC modułów ESP12 które mają być odpytywane i sterowane poprzez nodeMCU (bezprzewodowo, protokół espNOW) za pośrednictwem prostego GUI tego podłączonego wyświetlacza. Wygodnie i szybko z Nextionem.

    Wyświetlacz umożliwia łatwe wprowadzanie i zapamiętywanie adresów MAC poszczególnych modułów, więc jest to wygodne aby różne MAC-adresy współpracujących modułów tam właśnie wpisywać i zapamiętywać. Każdorazowa operacja sterowania lub odpytania modułu ESP12 powoduje że Nextion wypluwa poprzez UART ten wprowadzony i zapamiętany wcześniej przez użytkownika adres MAC, i rozkaz (czyli "co robimy z modułem podrzędnym, o danym adresie MAC"). No niby pięknie.

    Nextion działa jak należy, ale wypluwa z siebie dane "znak po znaku" , czyli mając MAC-Adres np. 52.04.34.AB.BC.46 - Nextion śle przez UART te dane poprawnie...ale znak po znaku ("5" , "2" , "." , "0" , "4" , "." , "3" , "4" , "." , "A" , "B" itd). Traci się zatem wartość liczbowa tak przesyłanych znaków. Nie znajduję polecenia w spisie rozkazów w samym Nextion aby inaczej coś przesłać z pamięci EEPROM (w której przechowuję te MAC-Adresy) jak tylko jako dane RAW od adresu początkowego, cięgiem jedna wartość po drugiej. Niestety. A w NodeMCU muszę z powrotem z tego poskładać poprawny adres MAC modułu. Funkcja atoi odpada , bo nie przetworzy ze stringa nic co nie jest z zakresu liczbowego. Gdy próbuję wrzucić odbierane dane w tablicę to także źle, bo program także jako takie osobne znaki char te dane wrzuca w kolejne adresy w tablicy , i też nie umiem tego poskładać potem w poprawny MAC-Adres. Możliwości pisania kodu w samym edytorze Nextion są dość mocno okrojone, więc wolałbym tego kolegę już w spokoju zostawić, chyba że jest jakiś łatwy sposób na zmianę tego co on wysyła jako ten adres MAC.

    Czy zna ktoś z szanownych kolegów jakieś sposoby aby poskładać z takich danych poprawny MAC-Adres, czyli zarówno liczby jak i litery ?
  • REKLAMA
  • #2 19328763
    excray
    Poziom 41  
    A z czym dokładnie masz problem? Z zamianą znaków ASCII na wartość liczbową? Kropki i wszystko, co nie jest znakiem z zakresu '0-9' lub 'A-F', odrzucasz, a resztę zamieniasz na hex w myśl zasady - jeśli znak <='9' to odejmij '0', a jeśli większy to odejmij '7' i otrzymasz wartość hex.
  • #3 19328882
    ex-or
    Poziom 28  
    excray napisał:
    jeśli większy to odejmij '7'
    Wydaje mi się, że czytelniej by było powiedzieć "odejmij 'A' i dodaj 10" :-) Albo dla pewności "przepuść przez toupper, potem odejmij 'A' i dodaj 10". Przydało by się też dodać, że otrzymaną liczbę należy pomnożyć przez odpowiednią potęgę liczby 2. I tu pytanie...
    Adrian1978 napisał:
    poprawny MAC-Adres

    ...jaki dokładnie ma być format? 48 bitowa liczba czy ciąg sześciu ośmiobitowych liczb? Albo jeszcze inaczej? Na ten przykład w SDK IDF numery MAC podaje się w postaci 6 elementowej tablicy uint8_t. Więc...?
    Tak czy inaczej chyba najprościej zapisać odebrany ciąg jako ASCII-Z i skorzystać ze sscanf, np. jeśli miała by to być tablica 6 elementowa:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #4 19329727
    Adrian1978
    Poziom 11  
    Dziękuję Wam bardzo ! Protokół espNOW w podstawowej wersji wymaga, aby urządzenie nadrzędne podawało MAC do wysyłki danych do konkretnego modułu - w postaci ciągu sześciu ośmiobitowych liczb. Ten można co prawda zmienić w samych modułach na łatwiejszy (np. same cyfry, tylko 2 bajty itp) ale fabrycznie moduły ESP-01 mają ten MAC dość długi, ja np. mam : 0x50, 0x03, 0x92, 0x76, 0xAF, 0x34. Dałem więc pole tekstowe w Nextion, które umożliwia łatwe wprowadzanie takiego adresu i jest ono potem zapisywane we wbudowanym EEPROM, z którego czytam te adresy i wysyłam UARTEM aby od razu polecenie z GUI wysyłać "temu komu trzeba". No ale to co wpisane w Nextion muszę w module nadrzędnym (u mnie nodeMCU) poskładać z powrotem w takie właśnie dane i z tym się gramoliłem. Uprościłem sobie już MAC-adresy do pary bajtów, na dodatek tylko cyfrowych ( w Nextion klawiatura ekranowa do wpisywania cyfr jest znacznie wygodniejsza niż pełna QWERTY). Zaraz sprawdzę zaproponowany przez kolegę ex-or sposób.
  • REKLAMA
  • #5 19332456
    Adrian1978
    Poziom 11  
    Rany Boskie , albo zwariowałem albo już mi się podstawy pier...niczą
    DLACZEGO nie odczytuję poprawnie wartości z tablicy, która zapisana jest poprawnie ?

    Odczytuję dane z Nextion. Wrzucam do tablicy (tablica celowo typu uint8_t). Nextion wysyła: 49 50 51 52 53 113 1 0 0 0 255 255 255
    (1,2,3,4,5 - uproszczony MAC, potem jakieś ich "q", potem stan klawisza i sekwencja końca, "000FFF"). Razem otrzymuję 13 bajtów danych za każdym naciśnięciem klawisza w Nextion. 7 bajt zmienia swoją wartośc z 0x00 na 0x01 w zależności od stanu ekranowego klawisza.
    (odbieram dosłownie : 49 50 51 52 53 113 1 0 0 0 255 255 255)
    kod :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Odbieram dane. Przyłazi 13 bajtów, w tym ten uproszczony MAC, stan klawisza, bajty stopu. Mam to powpisywane pięknie do tablicy podczas odbioru. W kolejnej funkcji chcę sprawdzić np. stan klawisza (stan klawisza zakodowany w siódmej zmiennej wysyłanej z Nextion) - czyli stan powinien być pod adresem: rec[6].

    Próbuję zrobić warunek sprawdzania czy klawisz jest w stanie ON czy OFF i...kiszka !

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


    Nie działa. Tak prosty warunek. Wiecznie zwraca OFF. Zwariowałem ?
  • REKLAMA
  • #6 19332471
    BlueDraco
    Specjalista - Mikrokontrolery
    A co to niby jest ten "stan" i skąd się bierze? Jakie wartości może przyjmować ta zmienna? Wkładasz tu jakieś drobne kawałki programu, z których niestety widać, że nie bardzo ogarniasz programowanie. Przyjrzyj się komunikatom z kompilacji. Doprowadź kod do takiego stanu, żeby nie było ani jednego ostrzeżenia - zrozum ostrzeżenie i usuń je. Pokaż większy kawałek kodu.
  • #7 19332509
    Adrian1978
    Poziom 11  
    Dzięki za chęć wytknięcia błędów - oto mój kod, właściwie w całości:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #8 19333304
    BlueDraco
    Specjalista - Mikrokontrolery
    Co to za dziwne typy byte i boolean? Po co definiujesz w pamięci stałą
    const byte numChars = 32;
    zamiast
    #define NCHARS 32 ?
    (
    Dlaczego Record() kończy się po odczytaniu jednego bajtu?
    Dlaczego dane jest typu int (i po co w ogąle ta zmienna)?
    Co wypisze showNewData kiedy jeszcze nie przyszedł bajt numer 6?
    Ta procedura zeruje zmienną adres, więc nigdy nie wpiszesz nic do rec[] dalej, niż na pozycję 0.

    Wystarczy na początek?
  • #9 19333374
    Adrian1978
    Poziom 11  
    Dzięki - już odpowiadam :

    BlueDraco napisał:
    const byte numChars = 32;
    - żywcem z przykładu autora espNOW , nic nie zmieniałem. Dlaczego miałaby być źle ? Pytam z ciekawości, czy jest to nieprawidłowa forma ? nie będzie działać ?

    BlueDraco napisał:
    Dlaczego Record() kończy się po odczytaniu jednego bajtu?
    - Jednego ? Sprawdzam UART i czy poprzednio to odczytywałem, jeśli są jakieś nowe dane to je odczytuję bajt po bajcie aż do momentu gdy Serial.available zwróci mi 0 (=brak danych - jeśli wierzyć książce) i wpisuję każdy odebrany bajt do zmiennej dane i stamtąd do kolejnych adresów tablicy , inkrementując indeks pod którym ten bajt zostanie zapisany. Leci 13 bajtów, to tyle się przecież powinno zapisać... Też nie kumam dlaczego miała by tu być jakaś kiszka ? czy mógłbyś mi napisać dlaczego ta konstrukcja jest zła ? to jest także żywcem z książki Simona Monka, traktującej o arduino.

    BlueDraco napisał:
    Co wypisze showNewData kiedy jeszcze nie przyszedł bajt numer 6?
    - showNewData przecież się wykona PO zakończeniu odbierania danych z UART, jak już mam tę tablicę zapisaną (zresztą poprawnie wyświetla się to w serial monitor...tzn jak zmodyfikuję funkcję showNewData to wypluwa mi tę tablicę poprawnie zapisaną tym co Nextion wysyła)

    BlueDraco napisał:
    Ta procedura zeruje zmienną adres, więc nigdy nie wpiszesz nic do rec[] dalej, niż na pozycję 0.
    - Zeruje, owszem, już po tym jak odczytam tę tablicę i coś z tymi danymi zrobię, np. sprawdzę jaka jest zawartość komórki o adresie 6 - czy to też jest nieprawidłowo ? Po odczycie tych danych i sprawdzeniu chciałbym nadpisać tę tablicę kolejnymi danymi, bo zawierają inne rozkazy i inny MAC. Jednorazowo muszę z nimi coś zrobić (odebrać, zinterpretować , wysłać do modułu podrzędnego rozkaz i tyle, czekam na dalsze komendy)

    Dodano po 3 [godziny] 45 [minuty]:

    Coś się jednak krzaczy przy odbiorze danych z Nextion i zapisywaniu ich do kolejnych adresów w tablicy. Zgłupiałem bo jeśli tę tablicę wyślę na monitor UART - dane są jakby poprawne (...) , ale dalsza część programu świruje i nie odczytuję z tej tablicy tego czego oczekuję. Jak "podłożę" prawidłowe, spodziewane wartości do tej tablicy - reszta programu działa, zgodnie z oczekiwaniami. Tu jakiś błąd głupi robię, którego nie widzę.

    Zerknijcie proszę jak odbieram dane z Nextion - on wysyła cięgiem np. takie dane : 31 32 33 34 35 71 01 00 00 00 FF FF FF

    a ja to usiłuję tak odebrać i wpisać do tablicy (po ostatnich zmianach, fragment, aby nie przynudzać) :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Może problem polega na tym że wyświetlacz wypluwa ciąg, i to mi się taką pętlą źle wpisuje bo traktuję to jako kilkanaście osobnych liczb ?
  • #10 19334046
    BlueDraco
    Specjalista - Mikrokontrolery
    Twój problem polega na tym, że nie masz kontroli nad tym, co piszesz i wydaje Ci się, że kod powinien działać inaczej, niż mu kazałeś (nie mylić z "chciałeś").

    Ostatnia wersja funkcji loop() po przetłumaczeniu na polski:
    "jeśli odebrano cokolwiek, np. jeden bajt, przeczytaj 13 bajtów", i tak w kółko.

    Na pocieszenie dodam, że pomysł jest zły, bo nie masz gwarancji synchronizacji paczki danych - możesz zacząć odbierać ją w środku, a nie od początku. Wykrywaj jakieś charakterystyczne zdarzenie - wartość bajtu, koniec wiersza lub dłuższą przerwę w transmisji. Po tym zdarzeniu próbuj łapać ramkę, ale jeśli w trakcie wystąpi dłuższa przerwa - zresetuj odbiór i zacznij od nowa. Jeśli to za trudne - wynajmij fachowca.
  • #11 19334055
    ex-or
    Poziom 28  
    I w ostatnia i poprzednia wersja kodu w części odbiorczej jest zła. Musisz założyć, że serial.available będzie zwracać 0 w środku ciągu. Zastanów się co się będzie działo w programie gdy serial.available będzie równe 1 to stanie się jasne skąd biorą się śmieci.
    Kod z postu #7 jest prawie dobry, po małych zmianach powinien mniej więcej działać. Twierdzisz, że 000fff jest wyróżnikiem końca danych, a więc trzeba to wykorzystać. Coś w tym stylu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #12 19335838
    Adrian1978
    Poziom 11  
    Dziękuję serdecznie za wszelkie uwagi - nawet te ciut zbyt kąśliwe. Nigdy nie twierdziłem że jestem asem programowania, człowiek wiecznie się uczy i zawsze ktoś będzie w czymś lepszy. Mimo tego - bardzo dziękuję za informacje.

    Trochę to inaczej rozwiązałem, kilku-etapowo, ale działa dość fajnie (mniejsza o pamięć i prędkość, nodeMCU ma tego pod dostatkiem):

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


    do powpisywania w tablicę znaków z tego stringa :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    i na koniec, by przekonwertować char na int :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Może będziecie wydziwiać i krytykować że to strasznie naokoło robię, ale tylko tak potrafiłem i w miarę realizuje to o co mi chodziło - aby z potoku stringa przesyłanego z nextion, a zawierającego różne dane, odebrać te ciągi, i finalnie wartości liczbowe wpisać odpowiednio w adres MAC który potem wysyłam pakietem do modułów ESP-01. Umieściłem tu tylko fragmenty kodu pokazujące sposób, bo oczywiście dla kilku danych niektóre z tych operacji musiałem wykonać kilkukrotnie, dla każdej wartości liczbowej. Może się ten temat komuś przyda.

    Pozdrawiam serdecznie : Adrian

    p.s. wcale się nie zdziwię jeśli kolega BlueDraco lub ex-or zastrzelą mnie jedną linijką ultra mądrego kodu który te wszystkie przekształcenia wykonuje od razu... :)

Podsumowanie tematu

Użytkownik napotkał problem z interpretacją danych odbieranych z wyświetlacza Nextion, który współpracuje z modułem NodeMCU 8266 i ESP12. Chciałby przetwarzać adresy MAC modułów ESP12, które są przesyłane w formie ciągu znaków przez UART. W odpowiedziach zaproponowano różne metody konwersji danych, w tym użycie funkcji sscanf do dekodowania adresów MAC oraz sugestie dotyczące poprawy kodu, aby zapewnić prawidłowe odczytywanie danych. Użytkownik ostatecznie zdecydował się na podejście z użyciem klasy String do odbierania danych i konwersji ich na tablicę znaków, co pozwoliło mu na efektywne przetwarzanie adresów MAC.
Podsumowanie wygenerowane przez model językowy.
REKLAMA