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

Atmega 328p - UART odbieranie stringów z Matlaba - niepełne dane

Tojmak987123 28 Gru 2016 11:10 1509 18
REKLAMA
  • #1 16154510
    Tojmak987123
    Poziom 6  
    Witam,

    mam problem z transmisją za pomocą modułu UART. To co chcę osiągnąć to z poziomu Matlaba móc sterować wartością PWM podawaną na silnik. Algorytm działania jest następujący -> Z Matlaba wysyłam wartość (typu string) np. "1700". Mikrokontroler odbiera tą wartość, a po odebraniu jest odsyłana z powrotem do Matlaba. Problem jest taki, że poza odebraną wartością 1700 co jakiś czas odbieram np. '17', albo tym podobne. Czy mógł by ktoś pomóc? Pewnie to jakiś prosty błąd, nie potrafię sobie jednak z tym poradzić na chwilę obecną. Poniżej zamieszczam kod.

    Funkcja main

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


    Funkcja log_get_value

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


    Funkcja send_value_dec

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


    Funkcja uart_getc() + przerwanie - zapożyczone z książki pana Kardasia

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


    Kod z Matlaba

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


    Zamieszczam również zdjęcie obrazujące sytuację. Wybrany został fragment gdzie dane dość mocno szwankują.

    Atmega 328p - UART odbieranie stringów z Matlaba - niepełne dane
  • REKLAMA
  • #2 16154547
    tmf
    VIP Zasłużony dla elektroda
    Całe parsowanie jest skopane, w dodatku np. while ( (data = uart_getc()) != 0x0A) - twoje uart_getc() jeśli kolejka jest pusta zwraca 0, w efekcie pętla hula dalej, pomimo braku danych. Nigdzie też nie sprawdzasz błędów.
  • #4 16154613
    Tojmak987123
    Poziom 6  
    Wielkie dzięki za tak szybką odpowiedź. Czy mógł bym spytać co rozumiesz przez skopane sparsowanie? Jeśli chodzi o return 0 w funkcji uart_getc() - to w książce, z której korzystałem autor z tego skorzystał, tłumacząc, że 0 przy łańcuchach tekstowych oznacza koniec tekstu. Czy w takim razie lepiej było by zrobić np. coś takiego?

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


    Co do sprawdzenia błędów. To co dokładniej powinienem sprawdzać?
    Kwarc w uC to 16 Mhz. Przerwań w sumie jest 4. Jedno przerwanie odbiorcze transmisji RS232, jedno na timer 16 bitowy, oraz 2 na timery 8 bitowe. Przy czym jedno z tych przerwań od timera 8 bitowego nie jest wykorzystywane na razie. Przerwania timera 16 bitowego i jeden timer 8 bitowy są wykorzystywane do generowania PWM programowo.
  • REKLAMA
  • #5 16154632
    tmf
    VIP Zasłużony dla elektroda
    @Tojmak987123 Twoja zmiana nic nie zmienia. Musisz kończyć pętlę, jeśli bufor odbiornika jest pusty, czyli trzeba to sprawdzić. Poza tym wypadałoby sprawdzić, czy atoi zakończyło się sukcesem. Swoją droga nie wiem po co zwracasz wynik przez wskaźnik, jakby nie można było po prostu go zwrócić przez return.
  • #6 16154663
    Tojmak987123
    Poziom 6  
    Czy w takim razie to wystarczy?
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Co do funkcji zwracającej wartość przez wskaźnik to tak, przerobie ją na zwracanie przez normalny return.
    Jeśli chodzi o zasugerowane sprawdzanie. To masz na myśli porównanie zmiennej value (po zastosowaniu atoi) z tablicą str[] bez ostatniego bajtu, którym był by znak kończący stringa - LF?
  • Pomocny post
    #7 16154720
    tmf
    VIP Zasłużony dla elektroda
    @Tojmak987123 Pomyśl - co dadzą ci wprowadzone zmiany? Nic. Bo problemem nie jest sama funkcja uart_getc, lecz sposób interpretacji jej wyniku. Czyli twoja pętla, która kompletnie ignoruje zwrócenie końca łańcucha.
  • #8 16154997
    Tojmak987123
    Poziom 6  
    @tmf Chyba jednak nie rozumiem. Jeśli chodzi o ten fragment w funkcji uart_getc(). Sprawdzałem dokładnie analizatorem stanów logicznych co wysyłam z Matlaba. Każda z liczb kończy się w odpowiednim miejscu znakiem \n, czyli ten fragment jest raczej dobrze? Z tego co czytałem to przy przesyłaniu stringów bajt o wartości 0 nie powinien być przesłany. Stąd prawdopodobnie return 0 się pojawiło. Sam jednak piszesz, że funkcja nie jest problemem lecz sposób interpretacji wyniku. Mówisz o pętli ignorującej zwrócenie końca łancucha. Nie wiem czy dobrze Cie rozumiem, ale chodzi o to, że powinienem dodać do zmiennej test, która jest w main, końcówkę 0x0A (LF)? Co ciekawe... sprawdziłem też analizatorem jakie dane wychodzą z uC. Dane są takie jak powinny być. Każda paczka bajtów zakończona jest też znakiem \r\n. Jakim cudem analizator pokazuje dobrze, a całość nie działa... Chyba, że źle korzystam z samego analizatora. Wybacz jeśli nie łapię czegoś oczywistego. Problem już mnie trochę nurtuje i chyba tracę powoli do tego cierpliwość.
  • REKLAMA
  • Pomocny post
    #9 16155086
    Konto nie istnieje
    Konto nie istnieje  
  • #10 16155426
    Tojmak987123
    Poziom 6  
    Wow... Chyba działa, przeprowadzę jeszcze dogłębniejsze testy by się upewnić, ale wstępnie wygląda na to, że problem się rozwiązał. Czyli podsumowując wychodzi na to, że błąd leżał po stronie tego przypadku gdy RxHead == RxTail? Dlaczego to return 0 było złe skoro niby 0 w przypadku stringów nie jest wysyłane?
  • REKLAMA
  • #11 16155487
    Konto nie istnieje
    Konto nie istnieje  
  • #12 16162928
    Tojmak987123
    Poziom 6  
    Okej, ogólnie to działa, wielkie dzięki za tamto. Mam jednak dalszy problem troszkę. Ogólnie chcę osiągnąć coś takiego, że wysyłam najpierw z Matlaba liczbę - jakąś flagę, po której uC wejdzie do odpowiedniej pętli. Po wejściu do tej pętli dopiero w niej ma odbierać wysłaną z Matlaba wartość. Czyli np. najpierw wysyłam liczbę równą 2 z Matlaba do uC. On odpowiednio reaguje wchodząc do danej pętli. Następnie z Matlaba wysyłana jest kolejna liczba, np. 1700. No i ona jest odbierana w uC, nadpisywana jest odpowiednia zmienna, a później - na końcu - odsyłana do Matlaba. Napotykam 2 problemy. Po pierwsze - zmienna która ma być nadpisana w uC (pwm_value) nie jest nadpisywana. Ma ona początkową wartość 900 i po odpaleniu programu z Matlaba pozostaje bez zmian. Po drugie - Matlab odbiera (już w tym ostatnim etapie) liczbę z uC (tą niezmienioną liczbę 900) tylko raz. Podczas próby kolejnego odpalenia programu w Matlabie podczas ostatniego etapu program wpada w pętle (warunek if(BytesAvailable == 0)). Czy ma ktoś pomysł gdzie leży problem? Poniżej wstawiam fragmenty kodu.

    Plik main

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


    Plik z użytymi funkcjami

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


    plik nagłówkowy

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


    Wybaczcie za być może głupie problemy, ale jak to się mówi - nie ma głupich pytań :). Przy okazji życzę wszystkim forumowiczom szczęśliwego nowego roku!
  • Pomocny post
    #13 16162991
    Konto nie istnieje
    Konto nie istnieje  
  • Pomocny post
    #14 16163104
    tmf
    VIP Zasłużony dla elektroda
    @Tojmak987123 IMHO niepotrzebnie komplikujesz. Jaki jest cel tego, aby dublować funkcje odbioru znaków? Masz na przerwaniach wpisywać znaki do bufora i ew. sygnalizować, że mamy coś wartego zainteresowania (czyli jest linia zakończona CRLF). Interpretacja zawartości bufora może być zrealizowana za pomocą funkcji obsługi tokenów ze string.h. A całość zrealizowałbym w oparciu o maszynę stanów. Dzięki temu czytelność kodu nie będzie malała w miarę jak będziesz dodawał kolejne funkcjonalności. W przykładach do książki "AVR. Układy peryferyjne" masz przykłady jak interpretować polecenia wysyłane z PC przez AVR - co prawda polecenia są związane z obsługą kart SD, ale wystarczy tylko zmienić wzorce tokenów i za 5 minut będziesz miał zrealizowane to co obecnie robisz.
  • #15 16163374
    Tojmak987123
    Poziom 6  
    Obu Panom dziękuję niezmiernie za pomocne słowa. Niestety prawdą jest, że poziom kodu zaczyna wykraczać niektórymi elementami poza moje mierne umiejętności programistyczne. Mam niestety sporo braków, które będę musiał nadrobić w najbliższym czasie, jednak projekt muszę szybko skończyć. Poczytam na razie zarówno o maszynie stanów jak i wspomnianych tokenach. Sprawdzę również zaproponowany przykład w książce i mam nadzieję, że pójdzie całość do przodu, a jeśli nie to pozwolę sobie Panów jeszcze troszkę pomęczyć :). Dziękuje jeszcze raz bardzo serdecznie, zabieram się za lekturę.
  • #16 16163459
    Konto nie istnieje
    Konto nie istnieje  
  • #17 16167541
    Tojmak987123
    Poziom 6  
    Mimo wszystko głupio tak marnować czas innych :). W każdym razie. Parę tematów chciałem poruszyć.

    - Po pierwsze odniosę się może do poleconej książki - "AVR. Układy peryferyjne" . Udało mi się dziś ją dostać i niestety nie znajduje w niej zbytniej pomocy. Nie jestem pewny czy szukałem w dobrym miejscu, jednak postanowiłem zagłębić się w dwa tematy - "Polecenia odczytu pamięci" w dziale nr. 22. Interfejs SPI i USART SPI, oraz "Operacje odczytu" z rodziału nr. 25. Jeszcze więcej pamięci, czyli karty SD, SDHC i spółka. Abstrahując od tego, że sam kod niestety jest dla mnie dość mocno nieczytelny, to nie znalazłem tam nic nawiązującego do tokenów. Czytałem jednak o samych tokenach w string.h. Czy dobrze rozumiem, że konkretnie chodziło o funkcję strtok? To jedyne co znalazłem co jednocześnie bezpośrednio nawiązywało by do nich. Nie potrafię jednak zrozumieć w jaki sposób mogło by mi to pomóc. Ogólnie mój program w tle (poza regulacją PID), ma komunikować się z interfejsem graficznym, który stworzyłem w Matlabie. W tym celu odczytywałem dwukrotnie dane w bufforze. Opisując to dokładniej - we wspomnianym menu, mam na chwilę obecną 4 istotne funkcje, które potrzebują komunikacji z uC. By uC wiedział, w którą funkcję wejść korzystałem z pierwszego pobrania znaku. Czyli np. odczytano z buffora znak '2', to uC miał zrozumieć to jako chęć zmiany wartośi PWM. Wtedy miał odczytać nową wartość PWM - np. 900. Nie widzę niestety analogii, jak obsługa tokenów mogła by mi tu pomóc. Czy na pewno w tym przypadku, który mam na pewno można wykonać ten algorytm z funkcją do odczytywania w tylko jednym miejscu? Sam algorytm (o ile dobrze to zrobiłem) jest widoczny na zdjęciu poniżej.

    - Po drugie maszyna stanów - poczytałem o tym, mniej więcej wydaje mi się, że wiem już jak to działa. Na pewno całkiem inaczej w praktyce. Jednak w miarę możliwości postaram się tym pobawić i wpleść to w program. Na razie jednak przez goniący termin wolał bym nie wprowadzać już radykalnych zmian. Jednak przy okazji chętnie się spytam czy tak miało by to wyglądać?

    Atmega 328p - UART odbieranie stringów z Matlaba - niepełne dane

    - Po trzecie - cofnąłem się o krok by jeszcze raz sprawdzić po kolei progresując, gdzie może leżeć problem. Wróciłem do bardziej podstawowego kodu, gdzie odczytywałem to co pojawiło się w bufforze po czym to wysyłałem z powrotem. Okazało się, że dalej nie zawsze odczytuje dobrą liczbę. Czasami odbierając liczbę, spodziewając się np. 1111 okazuje się, że dostaje 11. Bardzo częstym przypadkiem też jest (prawie zawsze), to, że pierwsza odczytana liczba jest liczba starą/początkową (tak jak by nie zdążyła się jeszcze zmienić). Dodam może jeszcze raz jak wygląda program na etapie po cofnięciu się żeby Panowie nie musieli się domyślać niczego.

    Main.c

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


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


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


    Pamiętam oczywiście o propozycji by funkcja log_get_value() nie posiadała wskaźnika. Przerobiłem ją jednak na razie jest tam jakiś błąd, przy następnej sposobności będzie już poprawiona.
  • #18 16167566
    tmf
    VIP Zasłużony dla elektroda
    Masz kod z książki interpretujący polecenia dla karty SD:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Powyższy kod robi dokładnie to co chcesz - czeka na przesłanie wskazanego polecenie, po czym go interpretuje.
  • #19 16169890
    Tojmak987123
    Poziom 6  
    Jestem w trakcie analizowania tego, a czy macie pomysł jaka może być przyczyna tego problemu z "po trzecie"?
REKLAMA