Mogway Napisano Wrzesień 27, 2018 Udostępnij Napisano Wrzesień 27, 2018 Witam forumowiczów ! Jako iż po kilku dniach poszukiwania odpowiedzi na dręczące mnie pytania postanowiłem poszukać pomocy u osób bardziej obeznanych w temacie. Po obejrzeniu kilkudziesięciu kursów , projektów ARDUINO itp. nadal mam problem z logiczny zrozumieniem problemu (może to juz wiek?) Chcę przesłać transmisją szeregową kilka zmiennych pomiędzy dwoma arduino i wyświetlić te zmienne gdzieś tam(to mniej istotne). Problemem jest dla mnie jak powinienem podejść do tematu przesyłania zmiennych - powiedzmy zmiennoprzecinkowych. Próbuje na różne sposoby ale nic mi nie wychodzi . Prawdopodobnie gdzieś robię jakiś błąd logiczny bo jedyne co udaje mi się odbierać przez Serial.read() to jakieś przypadkowe cyfry podając tylko jedna zmienną Serial.print(zmienna) . Cytuj Link do komentarza Share on other sites More sharing options...
ethanak Wrzesień 27, 2018 Udostępnij Wrzesień 27, 2018 Pokaż kody nadajnika i odbiornika. Bez tego można tylko wróżyć, a szklana kula akurat w konserwacji... Tak przy okazji - jeśli zwalasz coś na wiek to napisz ile masz lat, bo inaczej będę traktować dziarskiego emeryta, a inaczej zmęczonego życiem gimnazjalistę 😉 Cytuj Link do komentarza Share on other sites More sharing options...
Mogway Wrzesień 27, 2018 Autor tematu Udostępnij Wrzesień 27, 2018 (edytowany) Próbowałem wielu kodów, sęk w tym że chciałem sie nauczyć robić to dobrze . Aktualnie próbuje opcje która najbardziej mi się spodobała czyli struktura danych. Znalazłem w sieci taki kod ale nadal odbieram smieci. // Nadajnik struct strukturaDanych { int zmiennaA; int zmiennaB; } mojeDane; void setup() { Serial.begin(9600); mojeDane.zmiennaA = 20; mojeDane.zmiennaB = 80; } void loop() { Serial.write((uint8_t *)&mojeDane, sizeof(mojeDane)); delay(1000); } // Odbiornik struct strukturaDanych { int zmiennaA; int zmiennaB; } *mojeDane; uint8_t usartBuffer[sizeof(strukturaDanych)] = {0}; void setup() { Serial.begin(9600); Serial.print(sizeof(strukturaDanych)); } void loop() { if (Serial.readBytes(usartBuffer, sizeof(strukturaDanych))){ mojeDane = (strukturaDanych*)usartBuffer; Serial.print(mojeDane->zmiennaA); } } Oczywiście nie upieram się przy tej metodzie ale wydaje się ona "elegancka" Edytowano Wrzesień 27, 2018 przez Mogway Cytuj Link do komentarza Share on other sites More sharing options...
ethanak Wrzesień 27, 2018 Udostępnij Wrzesień 27, 2018 Sposób jest bardzo dobry... ale w jaki sposób zagwaranrujesz, że odbiornik zsynchronizuje się z nadajnikiem a nie rozpocznie w połowie transmisji? Spróbuj w odbiorniku zresetować odczyt, jeśli w ciągu np. Pół sekundy nie odbierzesz kolejnego bajtu. I jeszcze techniczna uwaga: zadbaj o czytelność umieszczanego kodu, bo fatalnie się to czyta. Edytor na forum pozwala na umieszczanie kodu w spoób czytelny, jeśli nie będziesz.z tego korzystać nikt Ci nie pomoże. 1 Cytuj Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Produkcja i montaż PCB - wybierz sprawdzone PCBWay! • Darmowe płytki dla studentów i projektów non-profit • Tylko 5$ za 10 prototypów PCB w 24 godziny • Usługa projektowania PCB na zlecenie • Montaż PCB od 30$ + bezpłatna dostawa i szablony • Darmowe narzędzie do podglądu plików Gerber Zobacz również » Film z fabryki PCBWay
Mogway Wrzesień 27, 2018 Autor tematu Udostępnij Wrzesień 27, 2018 Chyba się poddaje w temacie- wszędzie piszą że to proste wręcz banalne a jednak nie udało mi się spowodować prawidłowego przesłania i odzwierciedlenia 2 liczb zmiennoprzecinkowych. Czy się da ?- tak ale znalazłem bibliotekę do arduino która zrobi to za mnie. Dzieki za chęć pomocy - chętnie by się dowiedział gdzie zrobiłem błąd Cytuj Link do komentarza Share on other sites More sharing options...
ethanak Wrzesień 27, 2018 Udostępnij Wrzesień 27, 2018 Po prostu nie zagwarantowałeś tego, że odbiornik rozpocznie swoje odbieranie od pierwszego bajtu danych a nie od środka. Jeśli to zagwarantujesz - reszta będzie prosta i banalna. 1 Cytuj Link do komentarza Share on other sites More sharing options...
Treker (Damian Szymański) Wrzesień 27, 2018 Udostępnij Wrzesień 27, 2018 @Mogway, witam na forum 😉 Widzę, że to Twoje pierwsze kroki na Forbocie, oto najważniejsze informacje na start: Chcesz przywitać się z innymi członkami naszej społeczności? Skorzystaj z tematu powitania użytkowników. Opis najciekawszych funkcji, które ułatwiają korzystanie z forum znajdziesz w temacie instrukcja korzystania z forum - co warto wiedzieć? Poszczególne posty możesz oceniać (pozytywnie i negatywnie) za pomocą reakcji - ikona serca w prawym dolnym rogu każdej wiadomości. 43 minuty temu, Mogway napisał: Czy się da ?- tak ale znalazłem bibliotekę do arduino która zrobi to za mnie. Daj znać z ciekawości co to za biblioteka 🙂 Jeśli chodzi o Twój program, to możliwości jest wiele. Najprościej stworzyć ramki, które będą miały znak startu i stopu. Dzięki temu będziesz miał pewność, że odbiornik odebrał cały ciąg znaków i może go poprawnie zinterpretować. Przykładowo zamiast wysyłać dwie liczby w takiej postaci: "123,456" możesz wysyłać je w ramce: "@123,456#". Wtedy w odbieranych danych szukasz danych pasujących do wzorca, czyli zaczynających się od znaku małpy, a kończących się znakiem #. Wtedy będziesz miał pewność, że odebrano wszystkie dane. Jeśli wysyłasz samo "123,456" to podczas odebrania "123,45" nie będziesz wiedział czy to błąd czy faktycznie druga wartość to "45". Inaczej mówiąc wysyłasz paczkę danych i zakładasz, że odbiornik odebrał identyczne dane. Czasami pojawiają się błędy, które mogą się kumulować i cała komunikacja będzie skutkowała właśnie odczytywaniem jakiś "losowych wartości". Oczywiście opisuję to w olbrzymi skrócie, bo możliwości rozwiązania tego problemu jest bardzo dużo. Pamiętaj jednak, że zapewnienie dobrej, bezbłędnej komunikacji wcale nie jest bardzo prostym zadaniem. Cytuj Link do komentarza Share on other sites More sharing options...
Mogway Wrzesień 27, 2018 Autor tematu Udostępnij Wrzesień 27, 2018 @Treker biblioteka to EasyTransfer i w symie dziala tak jak w moim przykładzie, tylko lepiej. Co do moich problemów to problem leży gdzieś pomiędzy zrozumieniem jak działa hardware a jak do tego dorobić software. Z teorii jestem dobry wiem że można zrobić znak końca i początku ale jak to fizycznie zapisać to juz problem. Bez przykładowego programu jak to działa nie dam rady w przyzwoicie krótkim czasie poznać możliwości standardowych bibliotek. Jak napisał ethanak - rozumiem to ze powinienem zastosować jakąś kontrole początku ,końca moich danych ale jak to zrobić fizycznie w moim programie jeszcze nie wiem. Ponieważ próbuje odczytać strukturę danych to zapewne powinienem ja zacząć odczytywać jak jakaś komenda będzie sprawdza jakiś ustalony znak na porcie i wtedy uruchomi odczyt struktury. Jakieś dwadzieścia kilka lat temu coś pisałem w C - troche w C++ i tak mi się zachciało ... Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Wrzesień 27, 2018 Udostępnij Wrzesień 27, 2018 (edytowany) Hardware z którego korzystasz przesyłając informacje przez port szeregowy (tzw. UART) umie wysłać i odebrać bajt i nie ma dla niego znaczenia co to jest. Tak samo potraktuje każdą dowolną kombinację 8 bitów więc jeśli próbujesz wprost wysłać obszar pamięci RAM zawierający binarną reprezentację liczby zmiennoprzecinkowej to musisz się liczyć z faktem, że wysyłasz bajty o każdej możliwej wartości. W tej sytuacji nie masz szans wymyślić takiego bajtu który wstawiony np. na początku będzie unikalnym znakiem/znacznikiem początku transmisji. I to samo na końcu. Korzystając z takiego hardware musisz ograniczyć repertuar przesyłanych bajtów. To właśnie proponuje Treker. Przykładowo liczba zmiennoprzecinkowa w pamięci RAM może wyglądać tak: 0x73, 0x28, 0xC1 0x58 Zmyśliłem te wartości i być może powyższy ciąg nie ma sensu (w kontekście poprawnej liczby float), ale to tylko taki eksperyment myślowy. Nie możesz takiego ciągu poprzedzić/zakończyć jakimś arbitralnie wybranym bajtem, bo taką samą wartość za chwilę może przyjąć któryś z bajtów wnętrza liczby i odbiornik włączony w przypadkowym momencie zgłupieje. Możesz oczywiście wprowadzić nadmiarowość, np. wysyłać jako początek transmisji 4 bajty 0x55, 0x55, 0x55 i 0x55 lub jakąkolwiek inną kombinację 32 bitów i na taką sekwencję czekać w odbiorniku. To znacznie zmniejsza możliwość złej synchronizacji po stronie odbiorczej i takie rozwiązania też się stosuje. Wszystko jest kwestią szacunku ryzyka i oceny kosztów ewentualnego błędu. Niemniej jednak dość powszechną metodą jest - jak już wspomniałem używanie protokołów znakowych.Ludzie już dawno umówili się na pewien zestaw obowiązujących liczb/kodów które reprezentują znaki czyli litery, cyfry itp.Powszechnie używanym standardem jest ASCII - skrót rozszyfruj sam: https://ascii.cl/ Widzisz tutaj litery duże (kody od 0x41 do 0x5A), małe (0x61-0x7A), cyfry (0x30-0x39) itd. Ciekawym pomysłem jest zarezerwowanie pewnych kodów poniżej spacji (<0x20) na pewne informacje specjalne. Poczytaj o tych kodach bo tego właśnie potrzebujesz: https://ascii.cl/control-characters.htm Transmisja znakowa wymaga jednak, by w polu danych pojawiały się tylko znaki tekstu a więc litery, cyfry, separatory (przecinki, spacje) itp. Dlatego zanim zaczniesz coś nadawać, musisz swoje liczby przekonwertować na tekst. Zatem zamiast powyższego 4-bajtowego ciągu binarnego musisz mieć w pamięci ciąg znaków, np: "125.37", który w RAMie będzie wyglądał tak: 0x31, 0x32, 0x35, 0x2E, 0x33, 0x37 Do tego dopisujesz drugą liczbę np. po przecinku (sprawdź jaką dopisałem): 0x31, 0x32, 0x35, 0x2E, 0x33, 0x37, 0x2C, 0x33, 0x2E, 0x31, 0x34 i dopiero coś takiego uzupełniasz znakami specjalnymi: 0x01, 0x31, 0x32, 0x35, 0x2E, 0x33, 0x37, 0x2C, 0x33, 0x2E, 0x31, 0x34, 0x04 Teraz wystarczy, że odbiornik będzie czekał na bajt 0x01 i wiesz, że jest to na pewno początek transmisji a gdy odbierze 0x04 to może zająć się analizą tego co odebrał. Wszelkie manipulacje przygotowujące dane do nadania możesz robić za pomocą buforów i funkcji konwersji, np. standardowej itoa() lub formatowanych (s)print'ów.Transmisje znakowe mają też tę zaletę, że ich poprawność możesz obserwować na zwykłym terminalu (monitorze portu szeregowego) w komputerze. Wadą jest konieczność dokonywania konwersji po obu stronach. Edytowano Wrzesień 27, 2018 przez marek1707 1 Cytuj Link do komentarza Share on other sites More sharing options...
Gość es2 Wrzesień 29, 2018 Udostępnij Wrzesień 29, 2018 (edytowany) Sposobów na przesłanie danych binarnych jest wiele. Do wcześniej opisanych mogę dodać ASCII HEX - opis znajdziesz w opisie protokołu IntelHex. Prosty tekstowy, o którym pisał Treker, możesz uzyskać stosując sprintf i scanf (uwaga na zakres danych). Protokoły tekstowe mają poważna wadę, trzeba przesłać dużo nadmiarowych danych, co najmniej dwa razy więcej niż trzeba. Jeśli chcesz zmniejszyć liczbę przesyłanych danych musisz użyć transmisji binarnej. Pierwszym prostym rozwiązaniem jest skorzystanie z timeoutu o czym już było napisane, inny sposób to znak synchronizacji. Nie to będzie np 0xFF. Co gdy taka wartość pojawi się w danych? Nadajesz go dwa razy. Na podobnej zasadzie mógł działać Z80SIO tyle, że na poziomie bitów a nie bajtów. Nie pamiętam nazwy tego protokołu ale nadal jest używany w transmisjach radiowych. Poza wykrywaniem początku ramki, warto byłoby określić gdzie się kończy. Najczęściej używa się pola długości. Czasem, gdy przesyłane sa komendy, jej rodzaj może określać długość ramki. Poza długością warto dodać CRC. Cała ramka wygląda wtedy tak: SYNC - Znak/znaki synchronizacji LEN - bajt(słowo) długość danych DATA - dane o ilości określonej w polu LEN CRC Wybór CRC jest dużo, od prostych ADD, XOR, przez CRC8,16, 32. Podsumowując: dane przesyłane tekstem (para sprintf scanf), są czytelne dla człowieka ale mogą być problemy z konwersja dużych liczb, trzeba uzupełnić dane o znak początku/końca.Warto dodać CRC, może jak w GPS? IntelHex i podobne (S-rekord) są doskonałe do przesyłania danych binarnych, kodowanie/dekodowanie jest bardzo szybkie (proste dodawanie/odejmowanie i warunek if), niestety dane nie są zbyt czytelne, ale wszystko ładnie widać w terminalu i są gotowe programy (np HexPlorer) do konwersji (podglądania) danych. Dane przesyłane binarnie są krótkie, niestety mało czytelne nie da się ich podejrzeć w terminalu. Do ich podglądania najczęściej trzeba napisać własną aplikację. Edytowano Wrzesień 30, 2018 przez es2 Poprawiłem formatowanie list. Cytuj Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
Dołącz do dyskusji, napisz odpowiedź!
Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!